package utils

import (
	"fmt"
	"time"

	"legalgo-BE-go/config"
	authdomain "legalgo-BE-go/internal/domain/auth"
	jwtclaimenum "legalgo-BE-go/internal/enums/jwt"
	timeutils "legalgo-BE-go/internal/utilities/time_utils"

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

type ClaimOption func(options jwt.MapClaims)

// func GenerateToken(options ...ClaimOption) (string, error) {
// 	now := timeutils.Now()

// 	claims := jwt.MapClaims{
// 		string(jwtclaimenum.ISSUED_AT): now.Unix(),
// 	}

// 	for _, o := range options {
// 		o(claims)
// 	}

// 	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

// 	return token.SignedString(jwtSecret)
// }

func GenerateToken(data authdomain.AuthToken) (string, error) {
	now := timeutils.Now()
	claims := jwt.MapClaims{
		string(jwtclaimenum.EMAIL):      data.Email,
		string(jwtclaimenum.ROLE):       data.Role,
		string(jwtclaimenum.SESSION_ID): data.SessionID,
		string(jwtclaimenum.ID):         data.ID,
		string(jwtclaimenum.EXPIRED_AT): now.Add(time.Minute * time.Duration(config.REDIS_TIMEOUT)).Unix(),
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	return token.SignedString([]byte(config.SALT_SECURITY))
}

func ParseToken(s string) (*jwt.Token, error) {
	return jwt.Parse(s, func(t *jwt.Token) (any, error) {
		if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
		}

		return []byte(config.SALT_SECURITY), nil
	})
}

func DestructToken(s string) (authdomain.AuthToken, error) {
	var data authdomain.AuthToken

	token, err := ParseToken(s)
	if err != nil {
		return data, err
	}

	claims, ok := token.Claims.(jwt.MapClaims)

	if !ok {
		return data, fmt.Errorf("failed to parse token")
	}

	if !token.Valid {
		return data, fmt.Errorf("invalid token")
	}

	email, ok := claims[string(jwtclaimenum.EMAIL)].(string)
	if !ok {
		return data, fmt.Errorf("invalid email")
	}

	sessionId, ok := claims[string(jwtclaimenum.SESSION_ID)].(string)
	if !ok {
		return data, fmt.Errorf("invalid session_id")
	}

	role, ok := claims[string(jwtclaimenum.ROLE)].(string)
	if !ok {
		return data, fmt.Errorf("invalid role")
	}

	id, ok := claims[string(jwtclaimenum.ID)].(string)
	if !ok {
		return data, fmt.Errorf("invalid id")
	}

	data = authdomain.AuthToken{
		Email:     email,
		SessionID: sessionId,
		Role:      role,
		ID:        id,
	}

	return data, nil
}
