package infra

import (
	"strings"
	"testing"
	"time"
)

func TestJWTValidate_ValidatesGeneratedToken(t *testing.T) {
	claims := JWTClaims{
		Subject:   "user-42",
		Issuer:    "tester",
		ExpiresAt: time.Now().Add(time.Hour).Unix(),
		Custom:    map[string]any{"role": "admin"},
	}
	token, err := JWTGenerate(claims, "super-secret")
	if err != nil {
		t.Fatalf("JWTGenerate error: %v", err)
	}
	got, err := JWTValidate(token, "super-secret")
	if err != nil {
		t.Fatalf("JWTValidate error: %v", err)
	}
	if got.Subject != "user-42" {
		t.Errorf("Subject = %q, esperado user-42", got.Subject)
	}
	if got.Issuer != "tester" {
		t.Errorf("Issuer = %q, esperado tester", got.Issuer)
	}
	if got.Custom["role"] != "admin" {
		t.Errorf("Custom[role] = %v, esperado admin", got.Custom["role"])
	}
}

func TestJWTValidate_RejectsInvalidSignature(t *testing.T) {
	token, err := JWTGenerate(JWTClaims{Subject: "x", ExpiresAt: time.Now().Add(time.Hour).Unix()}, "secret-a")
	if err != nil {
		t.Fatalf("JWTGenerate error: %v", err)
	}
	if _, err := JWTValidate(token, "secret-b"); err == nil {
		t.Fatal("esperaba error con secret distinto")
	}
}

func TestJWTValidate_RejectsExpiredToken(t *testing.T) {
	token, err := JWTGenerate(JWTClaims{
		Subject:   "x",
		ExpiresAt: time.Now().Add(-1 * time.Hour).Unix(),
	}, "s")
	if err != nil {
		t.Fatalf("JWTGenerate error: %v", err)
	}
	if _, err := JWTValidate(token, "s"); err == nil {
		t.Fatal("esperaba error con token expirado")
	}
}

func TestJWTValidate_RejectsMalformedToken(t *testing.T) {
	cases := []string{
		"",
		"not-a-token",
		"one.two",
		"one.two.three.four",
	}
	for _, tok := range cases {
		if _, err := JWTValidate(tok, "s"); err == nil {
			t.Errorf("esperaba error con token %q", tok)
		}
	}
}

func TestJWTValidate_RejectsOtherAlgorithms(t *testing.T) {
	// Token con alg=none no es aceptado aunque la firma sea vacia
	// Construimos manualmente: header con alg=none
	// "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0" = {"alg":"none","typ":"JWT"}
	token := "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJ4In0."
	if _, err := JWTValidate(token, "s"); err == nil {
		t.Fatal("esperaba error con alg=none")
	}
	if !strings.Contains(token, ".") {
		t.Fatal("token debe tener puntos")
	}
}
