package auth

import (
	"context"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq"
)

// injectUser returns a copy of r with the given user stored under userCtxKey.
// This mirrors what RequireUser does at runtime.
func injectUser(r *http.Request, u dbq.User) *http.Request {
	ctx := context.WithValue(r.Context(), userCtxKey, u)
	return r.WithContext(ctx)
}

func TestRequireAdmin_AdminPasses(t *testing.T) {
	called := false
	stub := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		called = true
		w.WriteHeader(http.StatusOK)
	})

	h := RequireAdmin()(stub)

	req := injectUser(
		httptest.NewRequest(http.MethodGet, "/api/admin/test", nil),
		dbq.User{IsAdmin: true},
	)
	w := httptest.NewRecorder()
	h.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("status = %d, want 200", w.Code)
	}
	if !called {
		t.Error("stub handler was not called for admin user")
	}
}

func TestRequireAdmin_NonAdminReturns403(t *testing.T) {
	stub := http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {
		t.Fatal("stub handler must not be called for non-admin user")
	})

	h := RequireAdmin()(stub)

	req := injectUser(
		httptest.NewRequest(http.MethodGet, "/api/admin/test", nil),
		dbq.User{IsAdmin: false},
	)
	w := httptest.NewRecorder()
	h.ServeHTTP(w, req)

	if w.Code != http.StatusForbidden {
		t.Errorf("status = %d, want 403", w.Code)
	}
	body := w.Body.String()
	if !strings.Contains(body, "not_authorized") {
		t.Errorf("body %q does not contain %q", body, "not_authorized")
	}
	ct := w.Header().Get("Content-Type")
	if !strings.HasPrefix(ct, "application/json") {
		t.Errorf("Content-Type = %q, want application/json", ct)
	}
}

func TestRequireAdmin_NoUserContextReturns500(t *testing.T) {
	stub := http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {
		t.Fatal("stub handler must not be called when no user is in context")
	})

	h := RequireAdmin()(stub)

	// Do NOT inject a user — simulate RequireUser being bypassed.
	req := httptest.NewRequest(http.MethodGet, "/api/admin/test", nil)
	w := httptest.NewRecorder()
	h.ServeHTTP(w, req)

	if w.Code != http.StatusInternalServerError {
		t.Errorf("status = %d, want 500", w.Code)
	}
	body := w.Body.String()
	if !strings.Contains(body, "internal_error") {
		t.Errorf("body %q does not contain %q", body, "internal_error")
	}
	ct := w.Header().Get("Content-Type")
	if !strings.HasPrefix(ct, "application/json") {
		t.Errorf("Content-Type = %q, want application/json", ct)
	}
}
