package service

import (
	"errors"
	"time"

	"hyapp-admin-server/internal/security"

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

type AuthService struct {
	secret []byte
	ttl    time.Duration
}

type Claims struct {
	UserID      uint     `json:"uid"`
	Username    string   `json:"username"`
	Permissions []string `json:"permissions"`
	jwt.RegisteredClaims
}

func NewAuthService(secret string, accessTTL time.Duration) *AuthService {
	return &AuthService{secret: []byte(secret), ttl: accessTTL}
}

func HashPassword(password string) (string, error) {
	return security.HashPassword(password)
}

func CheckPassword(hash string, password string) bool {
	return security.CheckPassword(hash, password)
}

func (s *AuthService) GenerateAccessToken(userID uint, username string, permissions []string) (string, time.Time, error) {
	now := time.Now().UTC()
	expiresAt := now.Add(s.ttl)
	claims := Claims{
		UserID:      userID,
		Username:    username,
		Permissions: permissions,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(expiresAt),
			IssuedAt:  jwt.NewNumericDate(now),
			Subject:   username,
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	signed, err := token.SignedString(s.secret)
	if err != nil {
		return "", time.Time{}, err
	}

	return signed, expiresAt, nil
}

func (s *AuthService) ParseAccessToken(tokenString string) (*Claims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (any, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, errors.New("unexpected jwt signing method")
		}
		return s.secret, nil
	})
	if err != nil {
		return nil, err
	}

	claims, ok := token.Claims.(*Claims)
	if !ok || !token.Valid {
		return nil, errors.New("invalid jwt")
	}

	return claims, nil
}

func NewRefreshToken() (string, string, error) {
	return security.NewRefreshToken()
}

func HashToken(token string) string {
	return security.HashToken(token)
}
