package handlers

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

	"github.com/google/uuid"

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

// GET /api/user-card-layouts — list the user's named card layouts (default first).
func handleListCardLayouts(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	if dbSvc.cardLayout == nil {
		writeJSON(w, http.StatusServiceUnavailable, map[string]string{"error": "card-layout service not configured"})
		return
	}
	rows, err := dbSvc.cardLayout.List(r.Context(), uid)
	if err != nil {
		writeServiceError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, rows)
}

type createCardLayoutBody struct {
	Name      string             `json:"name"`
	Layout    services.LayoutSpec `json:"layout"`
	IsDefault bool               `json:"is_default"`
}

// POST /api/user-card-layouts — create a new named layout.
func handleCreateCardLayout(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	if dbSvc.cardLayout == nil {
		writeJSON(w, http.StatusServiceUnavailable, map[string]string{"error": "card-layout service not configured"})
		return
	}
	var body createCardLayoutBody
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid JSON body"})
		return
	}
	row, err := dbSvc.cardLayout.Create(r.Context(), uid, services.CreateCardLayoutInput{
		Name:      body.Name,
		Layout:    body.Layout,
		IsDefault: body.IsDefault,
	})
	if err != nil {
		if errors.Is(err, services.ErrUserCardLayoutNameTaken) {
			writeJSON(w, http.StatusConflict, map[string]string{"error": "name already exists"})
			return
		}
		writeServiceError(w, err)
		return
	}
	writeJSON(w, http.StatusCreated, row)
}

type updateCardLayoutBody struct {
	Name      *string              `json:"name,omitempty"`
	Layout    *services.LayoutSpec `json:"layout,omitempty"`
	IsDefault *bool                `json:"is_default,omitempty"`
}

// PATCH /api/user-card-layouts/{id} — partial update.
func handleUpdateCardLayout(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	if dbSvc.cardLayout == nil {
		writeJSON(w, http.StatusServiceUnavailable, map[string]string{"error": "card-layout service not configured"})
		return
	}
	id, err := uuid.Parse(r.PathValue("id"))
	if err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid id"})
		return
	}
	var body updateCardLayoutBody
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid JSON body"})
		return
	}
	row, err := dbSvc.cardLayout.Update(r.Context(), uid, id, services.UpdateCardLayoutInput{
		Name:      body.Name,
		Layout:    body.Layout,
		IsDefault: body.IsDefault,
	})
	if err != nil {
		if errors.Is(err, services.ErrUserCardLayoutNotFound) {
			writeJSON(w, http.StatusNotFound, map[string]string{"error": "not found"})
			return
		}
		if errors.Is(err, services.ErrUserCardLayoutNameTaken) {
			writeJSON(w, http.StatusConflict, map[string]string{"error": "name already exists"})
			return
		}
		writeServiceError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, row)
}

// DELETE /api/user-card-layouts/{id} — remove a named layout. The active
// default cannot be deleted (return 409); the UI gates this.
func handleDeleteCardLayout(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	if dbSvc.cardLayout == nil {
		writeJSON(w, http.StatusServiceUnavailable, map[string]string{"error": "card-layout service not configured"})
		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.cardLayout.Delete(r.Context(), uid, id); err != nil {
		if errors.Is(err, services.ErrUserCardLayoutNotFound) {
			writeJSON(w, http.StatusNotFound, map[string]string{"error": "not found"})
			return
		}
		if errors.Is(err, services.ErrUserCardLayoutDefaultGate) {
			writeJSON(w, http.StatusConflict, map[string]string{"error": "cannot delete default layout — switch defaults first"})
			return
		}
		writeServiceError(w, err)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}

// POST /api/user-card-layouts/{id}/set-default — sugar over PATCH .{is_default:true}.
func handleSetDefaultCardLayout(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	if dbSvc.cardLayout == nil {
		writeJSON(w, http.StatusServiceUnavailable, map[string]string{"error": "card-layout service not configured"})
		return
	}
	id, err := uuid.Parse(r.PathValue("id"))
	if err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid id"})
		return
	}
	row, err := dbSvc.cardLayout.SetDefault(r.Context(), uid, id)
	if err != nil {
		if errors.Is(err, services.ErrUserCardLayoutNotFound) {
			writeJSON(w, http.StatusNotFound, map[string]string{"error": "not found"})
			return
		}
		writeServiceError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, row)
}
