package middleware

import (
	"testing"
	"time"

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

const testSecret = "test-jwt-secret-key"

func makeToken(t *testing.T, userID, email string, expiresAt time.Time) string {
	t.Helper()
	claims := Claims{
		UserID: userID,
		Email:  email,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(expiresAt),
			IssuedAt:  jwt.NewNumericDate(time.Now().Add(-1 * time.Hour)),
			ID:        "test-jti",
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	s, err := token.SignedString([]byte(testSecret))
	if err != nil {
		t.Fatal(err)
	}
	return s
}

func TestParseAndValidateJWT_Valid(t *testing.T) {
	tok := makeToken(t, "u1", "a@b.com", time.Now().Add(15*time.Minute))
	claims, ok := parseAndValidateJWT(tok, testSecret)
	if !ok {
		t.Fatal("expected valid token to parse")
	}
	if claims.UserID != "u1" {
		t.Errorf("UserID = %q, want u1", claims.UserID)
	}
}

func TestParseAndValidateJWT_Expired(t *testing.T) {
	tok := makeToken(t, "u1", "a@b.com", time.Now().Add(-5*time.Minute))
	_, ok := parseAndValidateJWT(tok, testSecret)
	if ok {
		t.Fatal("expected expired token to be rejected by strict parser")
	}
}

func TestParseAndValidateJWT_WrongSecret(t *testing.T) {
	tok := makeToken(t, "u1", "a@b.com", time.Now().Add(15*time.Minute))
	_, ok := parseAndValidateJWT(tok, "wrong-secret")
	if ok {
		t.Fatal("expected wrong-secret token to be rejected")
	}
}

func TestParseJWTIgnoringExpiry_Expired(t *testing.T) {
	tok := makeToken(t, "u1", "a@b.com", time.Now().Add(-5*time.Minute))
	claims, ok := parseJWTIgnoringExpiry(tok, testSecret)
	if !ok {
		t.Fatal("expected expired token to be accepted by lenient parser")
	}
	if claims.UserID != "u1" {
		t.Errorf("UserID = %q, want u1", claims.UserID)
	}
}

func TestParseJWTIgnoringExpiry_WrongSecret(t *testing.T) {
	tok := makeToken(t, "u1", "a@b.com", time.Now().Add(-5*time.Minute))
	_, ok := parseJWTIgnoringExpiry(tok, "wrong-secret")
	if ok {
		t.Fatal("expected tampered token to be rejected even with lenient parser")
	}
}

func TestParseJWTIgnoringExpiry_GarbageToken(t *testing.T) {
	_, ok := parseJWTIgnoringExpiry("not.a.jwt", testSecret)
	if ok {
		t.Fatal("expected garbage token to be rejected")
	}
}
