package jwt

import (
	"errors"
	"time"

	"github.com/golang-jwt/jwt/v5"
)

var (
	ErrTokenExpired     = errors.New("token已过期")
	ErrTokenNotValidYet = errors.New("token尚未激活")
	ErrTokenMalformed   = errors.New("token格式错误")
	ErrTokenInvalid     = errors.New("无效的token")
)

// CustomClaims 自定义Claims
type CustomClaims struct {
	BaseClaims
	BufferTime int64 `json:"bufferTime"`
	jwt.RegisteredClaims
}

// BaseClaims 基础Claims
type BaseClaims struct {
	UUID        string `json:"uuid"`
	ID          uint   `json:"userId"`
	Username    string `json:"username"`
	NickName    string `json:"nickName"`
	AuthorityID uint   `json:"authorityId"`
}

// JWT JWT工具
type JWT struct {
	SigningKey []byte
	Issuer     string
	ExpiresAt  time.Duration
	BufferTime time.Duration
}

// NewJWT 创建JWT实例
func NewJWT(signingKey, issuer string, expiresAt, bufferTime time.Duration) *JWT {
	return &JWT{
		SigningKey: []byte(signingKey),
		Issuer:     issuer,
		ExpiresAt:  expiresAt,
		BufferTime: bufferTime,
	}
}

// CreateToken 创建token
func (j *JWT) CreateToken(baseClaims BaseClaims) (string, error) {
	claims := CustomClaims{
		BaseClaims: baseClaims,
		BufferTime: int64(j.BufferTime / time.Second),
		RegisteredClaims: jwt.RegisteredClaims{
			Issuer:    j.Issuer,
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(j.ExpiresAt)),
			NotBefore: jwt.NewNumericDate(time.Now().Add(-1000)),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(j.SigningKey)
}

// CreateClaims 创建Claims
func (j *JWT) CreateClaims(baseClaims BaseClaims) CustomClaims {
	return CustomClaims{
		BaseClaims: baseClaims,
		BufferTime: int64(j.BufferTime / time.Second),
		RegisteredClaims: jwt.RegisteredClaims{
			Issuer:    j.Issuer,
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(j.ExpiresAt)),
			NotBefore: jwt.NewNumericDate(time.Now().Add(-1000)),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
		},
	}
}

// ParseToken 解析token
func (j *JWT) ParseToken(tokenString string) (*CustomClaims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		return j.SigningKey, nil
	})
	if err != nil {
		switch {
		case errors.Is(err, jwt.ErrTokenExpired):
			return nil, ErrTokenExpired
		case errors.Is(err, jwt.ErrTokenMalformed):
			return nil, ErrTokenMalformed
		case errors.Is(err, jwt.ErrTokenNotValidYet):
			return nil, ErrTokenNotValidYet
		default:
			return nil, ErrTokenInvalid
		}
	}
	if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
		return claims, nil
	}
	return nil, ErrTokenInvalid
}

// NeedRefresh 判断是否需要刷新token
func (j *JWT) NeedRefresh(claims *CustomClaims) bool {
	return claims.ExpiresAt.Unix()-time.Now().Unix() < claims.BufferTime
}

// CreateTokenByOldToken 根据旧token创建新token
func (j *JWT) CreateTokenByOldToken(oldToken string, oldClaims CustomClaims) (string, *CustomClaims, error) {
	// 更新过期时间
	oldClaims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(j.ExpiresAt))
	oldClaims.IssuedAt = jwt.NewNumericDate(time.Now())
	oldClaims.NotBefore = jwt.NewNumericDate(time.Now().Add(-1000))

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, oldClaims)
	newToken, err := token.SignedString(j.SigningKey)
	if err != nil {
		return "", nil, err
	}
	return newToken, &oldClaims, nil
}

// NewJWTFromConfig 从配置创建JWT实例（内部使用）
func NewJWTFromConfig(signingKey, issuer, expiresTime, bufferTime string) *JWT {
	expires, _ := time.ParseDuration(expiresTime)
	if expires == 0 {
		expires = 7 * 24 * time.Hour // 默认7天
	}
	buffer, _ := time.ParseDuration(bufferTime)
	if buffer == 0 {
		buffer = 24 * time.Hour // 默认1天
	}
	return NewJWT(signingKey, issuer, expires, buffer)
}
