package services

import (
	"NetworkAuth/database"
	"NetworkAuth/models"
	"errors"
	"time"

	"github.com/google/uuid"
	"gorm.io/gorm"
)

// RefreshTokenService 提供 refreshToken 的持久化、轮换、撤销等业务能力
type RefreshTokenService struct{}

var refreshTokenService = &RefreshTokenService{}

// GetRefreshTokenService 单例获取
func GetRefreshTokenService() *RefreshTokenService {
	return refreshTokenService
}

// NewJTI 生成新的 jti
func (s *RefreshTokenService) NewJTI() string {
	return uuid.New().String()
}

// NewFamilyID 生成新的 family_id（每次登录都新建）
func (s *RefreshTokenService) NewFamilyID() string {
	return uuid.New().String()
}

// Create 持久化一条 refreshToken 记录
//   - 登录场景：传入新的 familyID + absolute（now + 绝对过期天数）
//   - 刷新场景：复用旧 familyID 与旧 absolute，保证滑动续期不能突破上限
func (s *RefreshTokenService) Create(jti, familyID, userUUID, userType string,
	expiresAt, absoluteExpiresAt time.Time, ua, ip string) error {
	db, err := database.GetDB()
	if err != nil {
		return err
	}
	rec := models.RefreshToken{
		JTI:               jti,
		FamilyID:          familyID,
		UserUUID:          userUUID,
		UserType:          userType,
		IssuedAt:          time.Now(),
		ExpiresAt:         expiresAt,
		AbsoluteExpiresAt: absoluteExpiresAt,
		UserAgent:         ua,
		IP:                ip,
	}
	return db.Create(&rec).Error
}

// FindByJTI 根据 jti 查询
func (s *RefreshTokenService) FindByJTI(jti string) (*models.RefreshToken, error) {
	db, err := database.GetDB()
	if err != nil {
		return nil, err
	}
	var rec models.RefreshToken
	if err := db.Where("jti = ?", jti).First(&rec).Error; err != nil {
		return nil, err
	}
	return &rec, nil
}

// RevokeFamily 撤销整个 family 下所有未撤销的 refreshToken（用于重用检测/登出）
func (s *RefreshTokenService) RevokeFamily(familyID string) error {
	db, err := database.GetDB()
	if err != nil {
		return err
	}
	return db.Model(&models.RefreshToken{}).
		Where("family_id = ? AND revoked = ?", familyID, false).
		Update("revoked", true).Error
}

// RevokeByJTI 撤销单条 refreshToken（一般在轮换时使用 Rotate）
func (s *RefreshTokenService) RevokeByJTI(jti string) error {
	db, err := database.GetDB()
	if err != nil {
		return err
	}
	return db.Model(&models.RefreshToken{}).
		Where("jti = ?", jti).
		Update("revoked", true).Error
}

// Rotate 标记旧 jti 为已撤销，并记录被替换为新 jti
func (s *RefreshTokenService) Rotate(oldJTI, newJTI string) error {
	db, err := database.GetDB()
	if err != nil {
		return err
	}
	return db.Model(&models.RefreshToken{}).
		Where("jti = ?", oldJTI).
		Updates(map[string]interface{}{
			"revoked":     true,
			"replaced_by": newJTI,
		}).Error
}

// CleanupExpired 清理过期且过期时间早于 retentionDays 天前的记录
func (s *RefreshTokenService) CleanupExpired(retentionDays int) error {
	db, err := database.GetDB()
	if err != nil {
		return err
	}
	cutoff := time.Now().AddDate(0, 0, -retentionDays)
	return db.Where("expires_at < ?", cutoff).Delete(&models.RefreshToken{}).Error
}

// ErrRefreshNotFound refreshToken 不存在
var ErrRefreshNotFound = errors.New("refresh token not found")

// IsNotFound 判断是否为记录未找到错误
func IsNotFound(err error) bool {
	return errors.Is(err, gorm.ErrRecordNotFound)
}
