package handlers

// HTTP handlers for partner-unit derivation (t-paliad-139 Phase 2).
//
// Endpoints:
//   GET    /api/projects/{id}/partner-units                      → list attached units
//   POST   /api/projects/{id}/partner-units                      → attach (or update opts)
//   DELETE /api/projects/{id}/partner-units/{unit_id}            → detach
//   GET    /api/projects/{id}/team/derived                       → list derived members
//   GET    /api/projects/{id}/team/from-descendants              → list descendant-staffed
//   PATCH  /api/partner-units/{id}/members/{user_id}/role        → set unit_role on a member

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

	"github.com/google/uuid"

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

// GET /api/projects/{id}/partner-units
func handleListAttachedUnits(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	projectID, err := uuid.Parse(r.PathValue("id"))
	if err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid id"})
		return
	}
	rows, err := dbSvc.derivation.ListAttachedUnits(r.Context(), uid, projectID)
	if err != nil {
		writeServiceError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, rows)
}

// POST /api/projects/{id}/partner-units
//
// Body: { partner_unit_id, derive_unit_roles[]?, derive_grants_authority? }.
// Idempotent on (project_id, partner_unit_id) — repeat calls update opts.
func handleAttachPartnerUnit(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	projectID, err := uuid.Parse(r.PathValue("id"))
	if err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid id"})
		return
	}
	var body struct {
		PartnerUnitID         string   `json:"partner_unit_id"`
		DeriveUnitRoles       []string `json:"derive_unit_roles"`
		DeriveGrantsAuthority bool     `json:"derive_grants_authority"`
	}
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid JSON"})
		return
	}
	unitID, err := uuid.Parse(body.PartnerUnitID)
	if err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid partner_unit_id"})
		return
	}
	if err := dbSvc.derivation.AttachUnitToProject(r.Context(), uid, projectID, unitID, services.AttachUnitOptions{
		DeriveUnitRoles:       body.DeriveUnitRoles,
		DeriveGrantsAuthority: body.DeriveGrantsAuthority,
	}); err != nil {
		writeServiceError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, map[string]string{"status": "ok"})
}

// DELETE /api/projects/{id}/partner-units/{unit_id}
func handleDetachPartnerUnit(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	projectID, err := uuid.Parse(r.PathValue("id"))
	if err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid id"})
		return
	}
	unitID, err := uuid.Parse(r.PathValue("unit_id"))
	if err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid unit_id"})
		return
	}
	if err := dbSvc.derivation.DetachUnitFromProject(r.Context(), uid, projectID, unitID); err != nil {
		writeServiceError(w, err)
		return
	}
	writeJSON(w, http.StatusNoContent, nil)
}

// GET /api/projects/{id}/team/derived
func handleListDerivedTeam(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	projectID, err := uuid.Parse(r.PathValue("id"))
	if err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid id"})
		return
	}
	rows, err := dbSvc.derivation.ListDerivedMembers(r.Context(), uid, projectID)
	if err != nil {
		writeServiceError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, rows)
}

// GET /api/projects/{id}/team/from-descendants
func handleListDescendantStaffedTeam(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	projectID, err := uuid.Parse(r.PathValue("id"))
	if err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid id"})
		return
	}
	rows, err := dbSvc.derivation.ListDescendantStaffed(r.Context(), uid, projectID)
	if err != nil {
		writeServiceError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, rows)
}

// PATCH /api/partner-units/{id}/members/{user_id}/role
//
// Body: { unit_role: 'lead'|'attorney'|'senior_pa'|'pa'|'paralegal' }.
// Admin-only (gated by PartnerUnitService.SetMemberRole's requireAdmin).
func handleSetUnitMemberRole(w http.ResponseWriter, r *http.Request) {
	if !requireDB(w) {
		return
	}
	uid, ok := requireUser(w, r)
	if !ok {
		return
	}
	unitID, err := uuid.Parse(r.PathValue("id"))
	if err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid 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
	}
	var body struct {
		UnitRole string `json:"unit_role"`
	}
	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.SetMemberRole(r.Context(), uid, unitID, userID, body.UnitRole); err != nil {
		writeServiceError(w, err)
		return
	}
	writeJSON(w, http.StatusOK, map[string]string{"status": "ok"})
}
