package infra

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"errors"
	"strings"
	"time"
)

// JWTValidate verifica la firma HMAC-SHA256 de un JWT y decodifica sus claims.
// Rechaza tokens mal formados, con firma invalida o expirados (exp < time.Now()).
// Retorna las claims si todo es valido.
func JWTValidate(token string, secret string) (JWTClaims, error) {
	var zero JWTClaims
	if secret == "" {
		return zero, errors.New("jwt_validate: secret vacio")
	}

	parts := strings.Split(token, ".")
	if len(parts) != 3 {
		return zero, errors.New("jwt_validate: token malformado (se esperaban 3 segmentos)")
	}

	enc := base64.RawURLEncoding
	signingInput := parts[0] + "." + parts[1]

	// Verificar firma
	mac := hmac.New(sha256.New, []byte(secret))
	mac.Write([]byte(signingInput))
	expectedSig := mac.Sum(nil)

	gotSig, err := enc.DecodeString(parts[2])
	if err != nil {
		return zero, errors.New("jwt_validate: firma mal codificada")
	}
	if !hmac.Equal(expectedSig, gotSig) {
		return zero, errors.New("jwt_validate: firma invalida")
	}

	// Decodificar header y confirmar alg
	headerBytes, err := enc.DecodeString(parts[0])
	if err != nil {
		return zero, errors.New("jwt_validate: header mal codificado")
	}
	var header map[string]string
	if err := json.Unmarshal(headerBytes, &header); err != nil {
		return zero, errors.New("jwt_validate: header no es JSON valido")
	}
	if alg, _ := header["alg"]; alg != "HS256" {
		return zero, errors.New("jwt_validate: algoritmo no soportado (solo HS256)")
	}

	// Decodificar claims
	payloadBytes, err := enc.DecodeString(parts[1])
	if err != nil {
		return zero, errors.New("jwt_validate: payload mal codificado")
	}
	var claims JWTClaims
	if err := json.Unmarshal(payloadBytes, &claims); err != nil {
		return zero, errors.New("jwt_validate: payload no es JSON valido")
	}

	// Validar expiracion si esta presente
	if claims.ExpiresAt > 0 && time.Now().Unix() >= claims.ExpiresAt {
		return zero, errors.New("jwt_validate: token expirado")
	}

	return claims, nil
}
