package handlers

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

	"github.com/google/uuid"

	"mgit.msbls.de/m/KanzlAI-mGMT/internal/auth"
	"mgit.msbls.de/m/KanzlAI-mGMT/internal/services"
)

type NoteHandler struct {
	svc *services.NoteService
}

func NewNoteHandler(svc *services.NoteService) *NoteHandler {
	return &NoteHandler{svc: svc}
}

// List handles GET /api/notes?{parent_type}_id={id}
func (h *NoteHandler) List(w http.ResponseWriter, r *http.Request) {
	tenantID, ok := auth.TenantFromContext(r.Context())
	if !ok {
		writeError(w, http.StatusUnauthorized, "missing tenant")
		return
	}

	parentType, parentID, err := parseNoteParent(r)
	if err != nil {
		writeError(w, http.StatusBadRequest, err.Error())
		return
	}

	notes, err := h.svc.ListByParent(r.Context(), tenantID, parentType, parentID)
	if err != nil {
		writeError(w, http.StatusInternalServerError, "failed to list notes")
		return
	}

	writeJSON(w, http.StatusOK, notes)
}

// Create handles POST /api/notes
func (h *NoteHandler) Create(w http.ResponseWriter, r *http.Request) {
	tenantID, ok := auth.TenantFromContext(r.Context())
	if !ok {
		writeError(w, http.StatusUnauthorized, "missing tenant")
		return
	}
	userID, _ := auth.UserFromContext(r.Context())

	var input services.CreateNoteInput
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		writeError(w, http.StatusBadRequest, "invalid request body")
		return
	}
	if input.Content == "" {
		writeError(w, http.StatusBadRequest, "content is required")
		return
	}
	if msg := validateStringLength("content", input.Content, maxDescriptionLen); msg != "" {
		writeError(w, http.StatusBadRequest, msg)
		return
	}

	var createdBy *uuid.UUID
	if userID != uuid.Nil {
		createdBy = &userID
	}

	note, err := h.svc.Create(r.Context(), tenantID, createdBy, input)
	if err != nil {
		writeError(w, http.StatusInternalServerError, "failed to create note")
		return
	}

	writeJSON(w, http.StatusCreated, note)
}

// Update handles PUT /api/notes/{id}
func (h *NoteHandler) Update(w http.ResponseWriter, r *http.Request) {
	tenantID, ok := auth.TenantFromContext(r.Context())
	if !ok {
		writeError(w, http.StatusUnauthorized, "missing tenant")
		return
	}

	noteID, err := uuid.Parse(r.PathValue("id"))
	if err != nil {
		writeError(w, http.StatusBadRequest, "invalid note ID")
		return
	}

	var req struct {
		Content string `json:"content"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		writeError(w, http.StatusBadRequest, "invalid request body")
		return
	}
	if req.Content == "" {
		writeError(w, http.StatusBadRequest, "content is required")
		return
	}
	if msg := validateStringLength("content", req.Content, maxDescriptionLen); msg != "" {
		writeError(w, http.StatusBadRequest, msg)
		return
	}

	note, err := h.svc.Update(r.Context(), tenantID, noteID, req.Content)
	if err != nil {
		writeError(w, http.StatusInternalServerError, "failed to update note")
		return
	}
	if note == nil {
		writeError(w, http.StatusNotFound, "note not found")
		return
	}

	writeJSON(w, http.StatusOK, note)
}

// Delete handles DELETE /api/notes/{id}
func (h *NoteHandler) Delete(w http.ResponseWriter, r *http.Request) {
	tenantID, ok := auth.TenantFromContext(r.Context())
	if !ok {
		writeError(w, http.StatusUnauthorized, "missing tenant")
		return
	}

	noteID, err := uuid.Parse(r.PathValue("id"))
	if err != nil {
		writeError(w, http.StatusBadRequest, "invalid note ID")
		return
	}

	if err := h.svc.Delete(r.Context(), tenantID, noteID); err != nil {
		writeError(w, http.StatusNotFound, "note not found")
		return
	}

	w.WriteHeader(http.StatusNoContent)
}

// parseNoteParent extracts the parent type and ID from query parameters.
func parseNoteParent(r *http.Request) (string, uuid.UUID, error) {
	params := map[string]string{
		"case_id":       "case",
		"deadline_id":   "deadline",
		"appointment_id": "appointment",
		"case_event_id": "case_event",
	}

	for param, parentType := range params {
		if v := r.URL.Query().Get(param); v != "" {
			id, err := uuid.Parse(v)
			if err != nil {
				return "", uuid.Nil, fmt.Errorf("invalid %s", param)
			}
			return parentType, id, nil
		}
	}

	return "", uuid.Nil, fmt.Errorf("one of case_id, deadline_id, appointment_id, or case_event_id is required")
}
