package handlers

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

	"github.com/google/uuid"

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

// GET /api/checklists/templates/{slug}/shares — list grants (owner/admin).
func handleListChecklistShares(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	slug := r.PathValue("slug")
	rows, err := dbSvc.checklistShare.ListGrants(r.Context(), uid, slug)
	if err != nil {
		writeChecklistShareError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, rows)
}

// POST /api/checklists/templates/{slug}/shares — grant a share.
func handleGrantChecklistShare(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.ShareGrantInput
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid JSON"})
		return
	}
	share, err := dbSvc.checklistShare.Grant(r.Context(), uid, slug, input)
	if err != nil {
		writeChecklistShareError(w, err)
		return
	}
	writeJSON(w, http.StatusCreated, share)
}

// DELETE /api/checklists/shares/{id} — revoke a share by id.
func handleRevokeChecklistShare(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
	}
	if err := dbSvc.checklistShare.Revoke(r.Context(), uid, id); err != nil {
		writeChecklistShareError(w, err)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}

// POST /api/admin/checklists/{slug}/promote — global_admin only.
func handlePromoteChecklist(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.checklistPromotion.Promote(r.Context(), uid, slug); err != nil {
		writeChecklistShareError(w, err)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}

// POST /api/admin/checklists/{slug}/demote — global_admin only.
func handleDemoteChecklist(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 {
		Target string `json:"target"`
	}
	// Body is optional — Demote defaults to 'firm' when empty.
	_ = json.NewDecoder(r.Body).Decode(&body)
	if err := dbSvc.checklistPromotion.Demote(r.Context(), uid, slug, body.Target); err != nil {
		writeChecklistShareError(w, err)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}

// writeChecklistShareError maps the share/promotion service errors.
// Same as the templates handler: ErrInvalidInput → 400, ErrForbidden →
// 403, ErrNotVisible → 404, fall through to writeServiceError.
func writeChecklistShareError(w http.ResponseWriter, err error) {
	if errors.Is(err, services.ErrInvalidInput) {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
		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)
}
