package handlers

import (
	"net/http"

	"mgit.msbls.de/m/paliad/internal/auth"
	"mgit.msbls.de/m/paliad/internal/services"
)

// GET /api/dashboard — returns the DashboardData JSON for the logged-in user.
// Returns 503 if DATABASE_URL is unset.
func handleDashboardAPI(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	data, err := dbSvc.dashboard.Get(r.Context(), uid)
	if err != nil {
		writeServiceError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, data)
}

// GET /dashboard — protected shell page. The client boots, reads three
// initial payloads inlined by the server (data, layout, catalog), and
// renders without a second round-trip (audit §2.3: no skeleton→fetch
// waterfall). Each inline is best-effort: if any read fails the
// corresponding blob is left null and the client falls back to fetch.
func handleDashboardPage(w http.ResponseWriter, r *http.Request) {
	uid, hasUser := auth.UserIDFromContext(r.Context())
	var payload, layout []byte
	if hasUser && dbSvc != nil {
		if data, err := dbSvc.dashboard.Get(r.Context(), uid); err == nil {
			payload = mustJSON(data)
		}
		if dbSvc.dashboardLayout != nil {
			if spec, err := dbSvc.dashboardLayout.GetOrSeed(r.Context(), uid); err == nil {
				layout = mustJSON(spec)
			}
		}
	}
	// Catalog is code-resident — always inline it so the widget picker
	// and dispatch logic can boot without an extra fetch even on
	// knowledge-platform-only deployments without DATABASE_URL.
	catalog := mustJSON(services.WidgetCatalog())
	serveDashboardShell(w, r, payload, layout, catalog)
}

// handleRootPage is the public `/` route. Unauthenticated visitors get the
// marketing landing; authenticated users get a 302 to /dashboard so `/` feels
// like a no-op they can bookmark.
func handleRootPage(w http.ResponseWriter, r *http.Request) {
	if hasValidSession(r) {
		http.Redirect(w, r, "/dashboard", http.StatusFound)
		return
	}
	http.ServeFile(w, r, "dist/index.html")
}

// hasValidSession returns true when the session cookie carries a signed,
// unexpired Supabase JWT. Verification is the same one Middleware uses —
// forged or tampered cookies never reach the authenticated branch.
func hasValidSession(r *http.Request) bool {
	cookie, err := r.Cookie(auth.SessionCookieName)
	if err != nil || cookie.Value == "" {
		return false
	}
	_, err = authClient.VerifyToken(cookie.Value)
	return err == nil
}
