package httpx

import (
	"net/http"
	"strings"
	"testing"
)

func TestLoginPageRenders(t *testing.T) {
	s := newTestServer(t)
	rec := get(t, s.Handler(), "/login")
	if rec.Code != http.StatusOK {
		t.Fatalf("status = %d", rec.Code)
	}
	body := rec.Body.String()
	for _, want := range []string{"login-form", `id="email"`, `id="password"`, "/static/js/login.js"} {
		if !strings.Contains(body, want) {
			t.Errorf("login page missing %q", want)
		}
	}
	// OIDC is not configured → no SSO button
	if strings.Contains(body, "Continue with SSO") {
		t.Error("SSO button shown although OIDC is disabled")
	}
	if csp := rec.Header().Get("Content-Security-Policy"); !strings.Contains(csp, "script-src 'self'") {
		t.Errorf("CSP missing or weak: %q", csp)
	}
	if rec.Header().Get("X-Frame-Options") != "DENY" {
		t.Error("X-Frame-Options missing")
	}
}

func TestRegisterPageRenders(t *testing.T) {
	s := newTestServer(t)
	rec := get(t, s.Handler(), "/register")
	if rec.Code != http.StatusOK {
		t.Fatalf("status = %d", rec.Code)
	}
	if !strings.Contains(rec.Body.String(), "register-form") {
		t.Error("register form missing")
	}
}

func TestAnonymousPageRedirectsToLogin(t *testing.T) {
	s := newTestServer(t)
	for _, path := range []string{"/", "/profile", "/board", "/admin", "/messages"} {
		rec := get(t, s.Handler(), path)
		if rec.Code != http.StatusFound {
			t.Errorf("%s: status = %d, want 302", path, rec.Code)
			continue
		}
		loc := rec.Header().Get("Location")
		if !strings.HasPrefix(loc, "/login?next=") {
			t.Errorf("%s: redirect to %q", path, loc)
		}
	}
}

func TestStaticAssetsServed(t *testing.T) {
	s := newTestServer(t)
	tests := map[string]string{
		"/static/css/app.css": "--bg:#ffffff", // Y2K white-paper light theme
		"/static/js/theme.js": "data-default-theme",
		"/static/js/api.js":   "X-CSRF-Token",
		"/static/js/login.js": "auth/login",
		"/static/js/nav.js":   "nav-theme",
	}
	for path, want := range tests {
		rec := get(t, s.Handler(), path)
		if rec.Code != http.StatusOK {
			t.Errorf("%s: status = %d", path, rec.Code)
			continue
		}
		if !strings.Contains(rec.Body.String(), want) {
			t.Errorf("%s: missing %q", path, want)
		}
	}
}

func TestThemeTokensPresent(t *testing.T) {
	s := newTestServer(t)
	rec := get(t, s.Handler(), "/static/css/app.css")
	css := rec.Body.String()
	// spot-check both palettes (Y2K rework, user-requested deviation from
	// the §10 beige — see DECISIONS.md) and the square-edge radius
	for _, tok := range []string{
		"--bg:#ffffff", "--accent:#7a4a14", // light: white paper, brown ink
		"--bg:#171209", "--accent:#d9a548", // dark
		"--radius:2px",
	} {
		if !strings.Contains(css, tok) {
			t.Errorf("css missing design token %q", tok)
		}
	}
}

func TestInitialsFunc(t *testing.T) {
	tests := []struct{ in, want string }{
		{"Jane Doe", "JD"},
		{"single", "S"},
		{"", "?"},
		{"  spaced  out  ", "SO"},
	}
	f := templateFuncs["initials"].(func(string) string)
	for _, tt := range tests {
		if got := f(tt.in); got != tt.want {
			t.Errorf("initials(%q) = %q, want %q", tt.in, got, tt.want)
		}
	}
}
