package auth

import (
	"errors"
	"time"

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

type Claims struct {
	Account    string `json:"account"`
	TokenEpoch int64  `json:"epoch"` // 与 users.token_epoch 一致；管理员封禁等操作会递增，旧 JWT 全部作废
	jwt.RegisteredClaims
}

func GenerateToken(secret []byte, issuer string, account string, tokenEpoch int64, ttl time.Duration) (string, time.Time, error) {
	if account == "" {
		return "", time.Time{}, errors.New("account is required")
	}
	expiresAt := time.Now().Add(ttl)
	claims := Claims{
		Account:    account,
		TokenEpoch: tokenEpoch,
		RegisteredClaims: jwt.RegisteredClaims{
			Issuer:    issuer,
			Subject:   account,
			ExpiresAt: jwt.NewNumericDate(expiresAt),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	signed, err := token.SignedString(secret)
	return signed, expiresAt, err
}

func ParseToken(secret []byte, issuer string, tokenString string) (*Claims, error) {
	if tokenString == "" {
		return nil, errors.New("token is required")
	}
	token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (any, error) {
		return secret, nil
	}, jwt.WithIssuer(issuer))
	if err != nil {
		return nil, err
	}
	claims, ok := token.Claims.(*Claims)
	if !ok || !token.Valid {
		return nil, errors.New("invalid token")
	}
	return claims, nil
}
