package jwt

import (
	"errors"
	"time"

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

var (
	ErrTokenValid            = errors.New("未知错误")
	ErrTokenExpired          = errors.New("token已过期")
	ErrTokenNotValidYet      = errors.New("token尚未激活")
	ErrTokenMalformed        = errors.New("这不是一个token")
	ErrTokenSignatureInvalid = errors.New("无效签名")
	ErrTokenInvalid          = errors.New("无法处理此token")
)

// BaseClaims 基础Claims
type BaseClaims struct {
	ID      string `json:"userId"`
	Account string `json:"account"`
}

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

// JWT JWT工具
type JWT struct {
	SigningKey []byte
}

// NewJWT 创建JWT实例
func NewJWT(signingKey string) *JWT {
	return &JWT{
		SigningKey: []byte(signingKey),
	}
}

// CreateClaims 创建Claims
func (j *JWT) CreateClaims(baseClaims BaseClaims, bufferTime, expiresTime time.Duration, issuer string) CustomClaims {
	return CustomClaims{
		BaseClaims: baseClaims,
		BufferTime: int64(bufferTime / time.Second),
		RegisteredClaims: jwtv5.RegisteredClaims{
			Audience:  jwtv5.ClaimStrings{"sundynix"},
			NotBefore: jwtv5.NewNumericDate(time.Now().Add(-1000)),
			ExpiresAt: jwtv5.NewNumericDate(time.Now().Add(expiresTime)),
			Issuer:    issuer,
		},
	}
}

// CreateToken 创建token
func (j *JWT) CreateToken(claims CustomClaims) (string, error) {
	token := jwtv5.NewWithClaims(jwtv5.SigningMethodHS256, claims)
	return token.SignedString(j.SigningKey)
}

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

// GetTokenFromHeader 从Authorization头中提取token
func GetTokenFromHeader(authHeader string) string {
	if len(authHeader) > 7 && authHeader[:7] == "Bearer " {
		return authHeader[7:]
	}
	return authHeader
}
