package web

import (
	"encoding/json"
	"io"
	"log/slog"
	"net/http"

	"pete/internal/storage"
)

// maxPrefsBytes caps the stored blob. Preferences are small (disabled feeds,
// a postal code, a couple toggles); this is generous headroom, not a target.
const maxPrefsBytes = 64 * 1024

// handlePrefs serves GET (load) and PUT (save) of the signed-in user's
// preferences blob. The blob is opaque JSON owned by the frontend. Both verbs
// require a session; anonymous callers get 401 and fall back to localStorage.
func (s *Server) handlePrefs(w http.ResponseWriter, r *http.Request) {
	if s.auth == nil {
		http.Error(w, "auth disabled", http.StatusNotFound)
		return
	}
	u := s.auth.userFromRequest(r)
	if u == nil {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		http.Error(w, `{"error":"not signed in"}`, http.StatusUnauthorized)
		return
	}

	switch r.Method {
	case http.MethodGet:
		blob, err := storage.GetUserPrefs(u.Sub)
		if err != nil {
			slog.Error("prefs: load failed", "sub", u.Sub, "err", err)
			http.Error(w, "internal error", http.StatusInternalServerError)
			return
		}
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.Header().Set("Cache-Control", "no-store")
		if blob == "" {
			_, _ = w.Write([]byte(`{"prefs":null}`))
			return
		}
		// blob is already valid JSON; embed it verbatim.
		_, _ = w.Write([]byte(`{"prefs":`))
		_, _ = io.WriteString(w, blob)
		_, _ = w.Write([]byte(`}`))

	case http.MethodPut:
		body, err := io.ReadAll(io.LimitReader(r.Body, maxPrefsBytes+1))
		if err != nil {
			http.Error(w, "read error", http.StatusBadRequest)
			return
		}
		if len(body) > maxPrefsBytes {
			http.Error(w, "preferences too large", http.StatusRequestEntityTooLarge)
			return
		}
		if !json.Valid(body) {
			http.Error(w, "invalid JSON", http.StatusBadRequest)
			return
		}
		if err := storage.PutUserPrefs(u.Sub, string(body), u.Name, u.Email); err != nil {
			slog.Error("prefs: save failed", "sub", u.Sub, "err", err)
			http.Error(w, "internal error", http.StatusInternalServerError)
			return
		}
		w.WriteHeader(http.StatusNoContent)

	default:
		http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
	}
}
