package handlers

import (
	"encoding/json"
	"net/http"

	"github.com/google/uuid"
)

// GET /api/projects/{id}/scenario-flags returns the project's current
// flag map and the catalog. See ScenarioFlagsService.Get for semantics.
func handleGetScenarioFlags(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	id, err := uuid.Parse(r.PathValue("id"))
	if err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid id"})
		return
	}
	view, err := dbSvc.scenarioFlags.Get(r.Context(), uid, id)
	if err != nil {
		writeServiceError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, view)
}

// PATCH /api/projects/{id}/scenario-flags merges a partial delta into
// the project's scenario_flags. Body shape:
//
//	{ "with_ccr": true, "with_amend": null, "rule:<uuid>": false }
//
// `null` deletes a key from the map so the priority-driven default
// returns; bool values are persisted verbatim.
func handlePatchScenarioFlags(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	id, err := uuid.Parse(r.PathValue("id"))
	if err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid id"})
		return
	}

	// Decode as map[string]*bool so JSON null cleanly resolves to nil
	// (= delete the key) while bool literals stay distinguishable from
	// the zero value.
	var raw map[string]json.RawMessage
	if err := json.NewDecoder(r.Body).Decode(&raw); err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid JSON body"})
		return
	}
	delta := make(map[string]*bool, len(raw))
	for k, v := range raw {
		if len(v) == 0 || string(v) == "null" {
			delta[k] = nil
			continue
		}
		var b bool
		if err := json.Unmarshal(v, &b); err != nil {
			writeJSON(w, http.StatusBadRequest, map[string]string{
				"error": "scenario-flag values must be bool or null (got non-bool for key " + k + ")",
			})
			return
		}
		bv := b
		delta[k] = &bv
	}

	view, err := dbSvc.scenarioFlags.Patch(r.Context(), uid, id, delta)
	if err != nil {
		writeServiceError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, view)
}
