package processor_jwt

import (
	"errors"
	"time"

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

type processor struct {
	secret []byte
}

func NewProcessor(secret string) IProcessorJWT {
	return &processor{
		secret: []byte(secret),
	}
}

func (p *processor) GenerateAccessToken(userId int, userEmail string, userRoles []string) (string, error) {
	now := time.Now()

	claims := &JWTClaims{
		UserID:    userId,
		UserEmail: userEmail,
		Roles:     userRoles,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(now.Add(3 * time.Hour)),
			IssuedAt:  jwt.NewNumericDate(now),
			NotBefore: jwt.NewNumericDate(now),
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(p.secret)
}

func (p *processor) GenerateRefreshToken(userId int) (string, error) {
	now := time.Now()

	claims := &JWTClaims{
		UserID: userId,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(now.Add(7 * 24 * time.Hour)),
			IssuedAt:  jwt.NewNumericDate(now),
			NotBefore: jwt.NewNumericDate(now),
			ID:        uuid.New().String(),
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(p.secret)
}

func (p *processor) GetClaims(token string) (*JWTClaims, error) {
	tokenWithClaims, err := jwt.ParseWithClaims(
		token,
		&JWTClaims{},
		func(token *jwt.Token) (any, error) {
			if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, errors.New("unexpected signing method")
			}
			return p.secret, nil
		},
	)
	if err != nil || !tokenWithClaims.Valid {
		return nil, errors.New("invalid or expired token")
	}

	claims, ok := tokenWithClaims.Claims.(*JWTClaims)
	if !ok {
		return nil, errors.New("invalid claims")
	}

	return claims, nil
}
