package infra

import (
	"net/http"
	"net/http/httptest"
	"testing"
	"time"
)

func makeTokenFor(t *testing.T, subject, secret string) string {
	t.Helper()
	tok, err := JWTGenerate(JWTClaims{
		Subject:   subject,
		ExpiresAt: time.Now().Add(time.Hour).Unix(),
	}, secret)
	if err != nil {
		t.Fatalf("JWTGenerate: %v", err)
	}
	return tok
}

func TestJWTMiddleware_ValidToken(t *testing.T) {
	secret := "test-sec"
	token := makeTokenFor(t, "alice", secret)

	var gotSubject string
	handler := JWTMiddleware(secret)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		claims, ok := JWTClaimsFromContext(r.Context())
		if !ok {
			t.Error("JWTClaimsFromContext no encontro claims")
		}
		gotSubject = claims.Subject
		w.WriteHeader(200)
	}))

	req := httptest.NewRequest(http.MethodGet, "/", nil)
	req.Header.Set("Authorization", "Bearer "+token)
	rec := httptest.NewRecorder()

	handler.ServeHTTP(rec, req)
	if rec.Code != 200 {
		t.Errorf("status = %d", rec.Code)
	}
	if gotSubject != "alice" {
		t.Errorf("subject = %q", gotSubject)
	}
}

func TestJWTMiddleware_MissingAuthHeader(t *testing.T) {
	handler := JWTMiddleware("s")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		t.Error("no deberia ejecutarse")
	}))
	req := httptest.NewRequest(http.MethodGet, "/", nil)
	rec := httptest.NewRecorder()
	handler.ServeHTTP(rec, req)
	if rec.Code != 401 {
		t.Errorf("status = %d", rec.Code)
	}
}

func TestJWTMiddleware_WrongFormat(t *testing.T) {
	handler := JWTMiddleware("s")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		t.Error("no deberia ejecutarse")
	}))
	req := httptest.NewRequest(http.MethodGet, "/", nil)
	req.Header.Set("Authorization", "Basic abcdef")
	rec := httptest.NewRecorder()
	handler.ServeHTTP(rec, req)
	if rec.Code != 401 {
		t.Errorf("status = %d", rec.Code)
	}
}

func TestJWTMiddleware_InvalidToken(t *testing.T) {
	handler := JWTMiddleware("secret-a")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		t.Error("no deberia ejecutarse")
	}))
	tok := makeTokenFor(t, "x", "secret-b") // firmado con otro secret
	req := httptest.NewRequest(http.MethodGet, "/", nil)
	req.Header.Set("Authorization", "Bearer "+tok)
	rec := httptest.NewRecorder()
	handler.ServeHTTP(rec, req)
	if rec.Code != 401 {
		t.Errorf("status = %d", rec.Code)
	}
}

func TestJWTClaimsFromContext_NotPresent(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "/", nil)
	_, ok := JWTClaimsFromContext(req.Context())
	if ok {
		t.Fatal("no deberia haber claims en un context nuevo")
	}
}
