package handlers

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

	"github.com/google/uuid"

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

// GET /api/partner-units — list every PartnerUnit (readable by all
// authenticated users).
//
// `?include=members` returns each unit enriched with its lead's display
// name + email and the full members list. Used by the /team directory page
// so the frontend can render the "group by partner unit" view with one fetch.
func handleListPartnerUnits(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	if _, ok := requireUser(w, r); !ok {
		return
	}
	if r.URL.Query().Get("include") == "members" {
		rows, err := dbSvc.partnerUnit.ListWithMembers(r.Context())
		if err != nil {
			writeServiceError(w, err)
			return
		}
		writeJSON(w, http.StatusOK, rows)
		return
	}
	rows, err := dbSvc.partnerUnit.List(r.Context())
	if err != nil {
		writeServiceError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, rows)
}

// POST /api/partner-units — admin-only create.
func handleCreatePartnerUnit(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	var input services.CreatePartnerUnitInput
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid JSON"})
		return
	}
	d, err := dbSvc.partnerUnit.Create(r.Context(), uid, input)
	if err != nil {
		writeServiceError(w, err)
		return
	}
	writeJSON(w, http.StatusCreated, d)
}

// GET /api/partner-units/{id}
func handleGetPartnerUnit(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	if _, ok := requireUser(w, r); !ok {
		return
	}
	id, err := uuid.Parse(r.PathValue("id"))
	if err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid id"})
		return
	}
	d, err := dbSvc.partnerUnit.GetByID(r.Context(), id)
	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			writeJSON(w, http.StatusNotFound, map[string]string{"error": "not found"})
			return
		}
		writeServiceError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, d)
}

// PATCH /api/partner-units/{id} — admin-only.
func handleUpdatePartnerUnit(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
	}
	var input services.UpdatePartnerUnitInput
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid JSON"})
		return
	}
	d, err := dbSvc.partnerUnit.Update(r.Context(), uid, id, input)
	if err != nil {
		writeServiceError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, d)
}

// DELETE /api/partner-units/{id} — admin-only.
func handleDeletePartnerUnit(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.partnerUnit.Delete(r.Context(), uid, id); err != nil {
		writeServiceError(w, err)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}

// GET /api/partner-units/{id}/members
func handleListPartnerUnitMembers(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	if _, ok := requireUser(w, r); !ok {
		return
	}
	id, err := uuid.Parse(r.PathValue("id"))
	if err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid id"})
		return
	}
	rows, err := dbSvc.partnerUnit.ListMembers(r.Context(), id)
	if err != nil {
		writeServiceError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, rows)
}

// POST /api/partner-units/{id}/members — admin-only. Body: {"user_id": "<uuid>"}
func handleAddPartnerUnitMember(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	partnerUnitID, err := uuid.Parse(r.PathValue("id"))
	if err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid id"})
		return
	}
	var body struct {
		UserID uuid.UUID `json:"user_id"`
	}
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid JSON"})
		return
	}
	if err := dbSvc.partnerUnit.AddMember(r.Context(), uid, partnerUnitID, body.UserID); err != nil {
		writeServiceError(w, err)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}

// DELETE /api/partner-units/{id}/members/{user_id} — admin-only.
func handleRemovePartnerUnitMember(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	partnerUnitID, err := uuid.Parse(r.PathValue("id"))
	if err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid partner_unit id"})
		return
	}
	userID, err := uuid.Parse(r.PathValue("user_id"))
	if err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid user id"})
		return
	}
	if err := dbSvc.partnerUnit.RemoveMember(r.Context(), uid, partnerUnitID, userID); err != nil {
		writeServiceError(w, err)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}
