package handlers

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

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

// GET /api/checklists/templates/mine — list authored templates owned by caller.
func handleListMyChecklistTemplates(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	rows, err := dbSvc.checklistTemplate.ListOwnedBy(r.Context(), uid)
	if err != nil {
		writeServiceError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, rows)
}

// POST /api/checklists/templates — create a new authored template.
func handleCreateChecklistTemplate(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	var input services.CreateTemplateInput
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid JSON"})
		return
	}
	t, err := dbSvc.checklistTemplate.Create(r.Context(), uid, input)
	if err != nil {
		writeChecklistTemplateError(w, err)
		return
	}
	writeJSON(w, http.StatusCreated, t)
}

// PATCH /api/checklists/templates/{slug} — update authored template (owner only).
func handleUpdateChecklistTemplate(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	slug := r.PathValue("slug")
	var input services.UpdateTemplateInput
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid JSON"})
		return
	}
	t, err := dbSvc.checklistTemplate.Update(r.Context(), uid, slug, input)
	if err != nil {
		writeChecklistTemplateError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, t)
}

// PATCH /api/checklists/templates/{slug}/visibility — toggle private↔firm.
func handleSetChecklistTemplateVisibility(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	slug := r.PathValue("slug")
	var body struct {
		Visibility string `json:"visibility"`
	}
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid JSON"})
		return
	}
	t, err := dbSvc.checklistTemplate.SetVisibility(r.Context(), uid, slug, body.Visibility)
	if err != nil {
		writeChecklistTemplateError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, t)
}

// DELETE /api/checklists/templates/{slug} — delete authored template.
func handleDeleteChecklistTemplate(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	slug := r.PathValue("slug")
	if err := dbSvc.checklistTemplate.Delete(r.Context(), uid, slug); err != nil {
		writeChecklistTemplateError(w, err)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}

// writeChecklistTemplateError maps service errors to HTTP status. Falls
// through to writeServiceError for unknown errors so the generic
// ErrNotVisible / ErrInvalidInput / ErrForbidden mappings still apply.
func writeChecklistTemplateError(w http.ResponseWriter, err error) {
	if errors.Is(err, services.ErrInvalidInput) {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": strings.TrimPrefix(err.Error(), "invalid input: ")})
		return
	}
	if errors.Is(err, services.ErrForbidden) {
		writeJSON(w, http.StatusForbidden, map[string]string{"error": err.Error()})
		return
	}
	if errors.Is(err, services.ErrNotVisible) {
		writeJSON(w, http.StatusNotFound, map[string]string{"error": "checklist not found"})
		return
	}
	writeServiceError(w, err)
}
