package infra

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

func buildRBACRoles() []Role {
	return []Role{
		{Name: "admin", Permissions: []Permission{{Resource: "users", Action: "delete"}}},
		{Name: "viewer", Permissions: []Permission{{Resource: "users", Action: "read"}}},
	}
}

func buildAuthedRequest(t *testing.T, role, secret string) *http.Request {
	t.Helper()
	claims := JWTClaims{
		Subject:   "user-1",
		ExpiresAt: time.Now().Add(time.Hour).Unix(),
		Custom:    map[string]any{"role": role},
	}
	tok, err := JWTGenerate(claims, secret)
	if err != nil {
		t.Fatalf("JWTGenerate: %v", err)
	}
	req := httptest.NewRequest(http.MethodGet, "/", nil)
	req.Header.Set("Authorization", "Bearer "+tok)
	return req
}

func TestRBACMiddleware_PermissionGranted(t *testing.T) {
	secret := "s"
	chain := HTTPMiddlewareChain(
		JWTMiddleware(secret),
		RBACMiddleware(buildRBACRoles(), Permission{Resource: "users", Action: "delete"}),
	)
	var called bool
	handler := chain(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		called = true
		w.WriteHeader(200)
	}))

	rec := httptest.NewRecorder()
	handler.ServeHTTP(rec, buildAuthedRequest(t, "admin", secret))
	if rec.Code != 200 || !called {
		t.Errorf("admin deberia pasar: status=%d called=%v", rec.Code, called)
	}
}

func TestRBACMiddleware_PermissionDenied(t *testing.T) {
	secret := "s"
	chain := HTTPMiddlewareChain(
		JWTMiddleware(secret),
		RBACMiddleware(buildRBACRoles(), Permission{Resource: "users", Action: "delete"}),
	)
	handler := chain(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		t.Error("viewer no deberia pasar")
	}))

	rec := httptest.NewRecorder()
	handler.ServeHTTP(rec, buildAuthedRequest(t, "viewer", secret))
	if rec.Code != 403 {
		t.Errorf("status = %d, esperaba 403", rec.Code)
	}
}

func TestRBACMiddleware_UnknownRole(t *testing.T) {
	secret := "s"
	chain := HTTPMiddlewareChain(
		JWTMiddleware(secret),
		RBACMiddleware(buildRBACRoles(), Permission{Resource: "users", Action: "read"}),
	)
	handler := chain(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		t.Error("rol ghost no deberia pasar")
	}))

	rec := httptest.NewRecorder()
	handler.ServeHTTP(rec, buildAuthedRequest(t, "ghost", secret))
	if rec.Code != 403 {
		t.Errorf("status = %d, esperaba 403", rec.Code)
	}
}

func TestRBACMiddleware_NoClaims(t *testing.T) {
	// Sin JWTMiddleware delante → no hay claims en context
	mw := RBACMiddleware(buildRBACRoles(), Permission{Resource: "users", Action: "read"})
	handler := mw(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, esperaba 401", rec.Code)
	}
}
