package model

import (
	"time"

	"github.com/pingcap/errors"
	"gorm.io/gorm"

	"github.com/pingcap-inc/clinic/pkg/db"
	"github.com/pingcap-inc/clinic/pkg/pagination"
)

// AddInternalAPICredential creates a new internal API credential for an internal user.
func AddInternalAPICredential(userID uint, name, hashedKey string, expiresAt *time.Time) (*db.InternalAPICredential, error) {
	c := db.InternalAPICredential{
		Model: gorm.Model{
			CreatedAt: time.Now(),
			UpdatedAt: time.Now(),
		},
		UserID:    userID,
		Name:      name,
		HashedKey: hashedKey,
		Status:    "active",
		ExpiresAt: expiresAt,
	}
	err := db.Transaction(func(tx *gorm.DB) error {
		return tx.Create(&c).Error
	})

	return &c, err
}

// GetInternalAPICredential retrieves an internal API credential by ID.
func GetInternalAPICredential(id uint) (*db.InternalAPICredential, error) {
	var (
		credential db.InternalAPICredential
		err        error
	)
	err = db.Transaction(func(tx *gorm.DB) error {
		return tx.First(&credential, id).Error
	})

	return &credential, err
}

// ListInternalAPICredentials lists all internal API credentials for a user.
func ListInternalAPICredentials(userID uint, page, perPage int) ([]db.InternalAPICredential, int64, error) {
	var (
		credentials []db.InternalAPICredential
		total       int64
		err         error
	)

	err = db.Transaction(func(tx *gorm.DB) error {
		q := tx.Model(&db.InternalAPICredential{}).Where("user_id = ?", userID)

		if perPage > 0 {
			if err = q.Count(&total).Error; err != nil {
				return errors.Annotate(err, "count internal api credentials error")
			}

			startIndex := pagination.GetStartIndex(page, perPage)
			q = q.Limit(perPage).Offset(startIndex)
		}

		if err := q.Find(&credentials).Error; err != nil {
			return errors.Annotate(err, "fetch internal api credentials failed")
		}

		if perPage <= 0 {
			total = int64(len(credentials))
		}

		return nil
	})
	if err != nil {
		return nil, 0, err
	}

	return credentials, total, nil
}

// ListActiveInternalAPICredentials lists all active internal API credentials for a user
// (used during authentication).
func ListActiveInternalAPICredentials(userID uint) ([]db.InternalAPICredential, error) {
	var (
		credentials []db.InternalAPICredential
		err         error
	)

	err = db.Transaction(func(tx *gorm.DB) error {
		return tx.Where("user_id = ? AND status = ?", userID, "active").Find(&credentials).Error
	})

	return credentials, err
}

// DeleteInternalAPICredential deletes an internal API credential by ID.
func DeleteInternalAPICredential(id uint) error {
	return db.Transaction(func(tx *gorm.DB) error {
		return tx.Delete(&db.InternalAPICredential{}, id).Error
	})
}

// UpdateInternalCredentialLastUsed updates the last used timestamp for a credential.
func UpdateInternalCredentialLastUsed(id uint) error {
	now := time.Now()
	return db.Transaction(func(tx *gorm.DB) error {
		return tx.Model(&db.InternalAPICredential{}).Where("id = ?", id).Update("last_used_at", &now).Error
	})
}
