package handlers

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

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

	"github.com/google/uuid"
)

type TimeEntryHandler struct {
	svc *services.TimeEntryService
}

func NewTimeEntryHandler(svc *services.TimeEntryService) *TimeEntryHandler {
	return &TimeEntryHandler{svc: svc}
}

// ListForCase handles GET /api/cases/{id}/time-entries
func (h *TimeEntryHandler) ListForCase(w http.ResponseWriter, r *http.Request) {
	tenantID, ok := auth.TenantFromContext(r.Context())
	if !ok {
		writeError(w, http.StatusForbidden, "missing tenant")
		return
	}

	caseID, err := parsePathUUID(r, "id")
	if err != nil {
		writeError(w, http.StatusBadRequest, "invalid case ID")
		return
	}

	entries, err := h.svc.ListForCase(r.Context(), tenantID, caseID)
	if err != nil {
		internalError(w, "failed to list time entries", err)
		return
	}

	writeJSON(w, http.StatusOK, map[string]any{"time_entries": entries})
}

// List handles GET /api/time-entries?case_id=&user_id=&from=&to=
func (h *TimeEntryHandler) List(w http.ResponseWriter, r *http.Request) {
	tenantID, ok := auth.TenantFromContext(r.Context())
	if !ok {
		writeError(w, http.StatusForbidden, "missing tenant")
		return
	}

	limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
	offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
	limit, offset = clampPagination(limit, offset)

	filter := services.TimeEntryFilter{
		From:   r.URL.Query().Get("from"),
		To:     r.URL.Query().Get("to"),
		Limit:  limit,
		Offset: offset,
	}

	if caseStr := r.URL.Query().Get("case_id"); caseStr != "" {
		caseID, err := uuid.Parse(caseStr)
		if err != nil {
			writeError(w, http.StatusBadRequest, "invalid case_id")
			return
		}
		filter.CaseID = &caseID
	}
	if userStr := r.URL.Query().Get("user_id"); userStr != "" {
		userID, err := uuid.Parse(userStr)
		if err != nil {
			writeError(w, http.StatusBadRequest, "invalid user_id")
			return
		}
		filter.UserID = &userID
	}

	entries, total, err := h.svc.List(r.Context(), tenantID, filter)
	if err != nil {
		internalError(w, "failed to list time entries", err)
		return
	}

	writeJSON(w, http.StatusOK, map[string]any{
		"time_entries": entries,
		"total":        total,
	})
}

// Create handles POST /api/cases/{id}/time-entries
func (h *TimeEntryHandler) Create(w http.ResponseWriter, r *http.Request) {
	tenantID, ok := auth.TenantFromContext(r.Context())
	if !ok {
		writeError(w, http.StatusForbidden, "missing tenant")
		return
	}
	userID, _ := auth.UserFromContext(r.Context())

	caseID, err := parsePathUUID(r, "id")
	if err != nil {
		writeError(w, http.StatusBadRequest, "invalid case ID")
		return
	}

	var input services.CreateTimeEntryInput
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		writeError(w, http.StatusBadRequest, "invalid JSON body")
		return
	}
	input.CaseID = caseID

	if input.Description == "" {
		writeError(w, http.StatusBadRequest, "description is required")
		return
	}
	if input.DurationMinutes <= 0 {
		writeError(w, http.StatusBadRequest, "duration_minutes must be positive")
		return
	}
	if input.Date == "" {
		writeError(w, http.StatusBadRequest, "date is required")
		return
	}

	entry, err := h.svc.Create(r.Context(), tenantID, userID, input)
	if err != nil {
		internalError(w, "failed to create time entry", err)
		return
	}

	writeJSON(w, http.StatusCreated, entry)
}

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

	entryID, err := parsePathUUID(r, "id")
	if err != nil {
		writeError(w, http.StatusBadRequest, "invalid time entry ID")
		return
	}

	var input services.UpdateTimeEntryInput
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		writeError(w, http.StatusBadRequest, "invalid JSON body")
		return
	}

	entry, err := h.svc.Update(r.Context(), tenantID, entryID, input)
	if err != nil {
		writeError(w, http.StatusBadRequest, err.Error())
		return
	}

	writeJSON(w, http.StatusOK, entry)
}

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

	entryID, err := parsePathUUID(r, "id")
	if err != nil {
		writeError(w, http.StatusBadRequest, "invalid time entry ID")
		return
	}

	if err := h.svc.Delete(r.Context(), tenantID, entryID); err != nil {
		writeError(w, http.StatusBadRequest, err.Error())
		return
	}

	writeJSON(w, http.StatusOK, map[string]string{"status": "deleted"})
}

// Summary handles GET /api/time-entries/summary?group_by=case|user|month&from=&to=
func (h *TimeEntryHandler) Summary(w http.ResponseWriter, r *http.Request) {
	tenantID, ok := auth.TenantFromContext(r.Context())
	if !ok {
		writeError(w, http.StatusForbidden, "missing tenant")
		return
	}

	groupBy := r.URL.Query().Get("group_by")
	if groupBy == "" {
		groupBy = "case"
	}

	summaries, err := h.svc.Summary(r.Context(), tenantID, groupBy,
		r.URL.Query().Get("from"), r.URL.Query().Get("to"))
	if err != nil {
		internalError(w, "failed to get summary", err)
		return
	}

	writeJSON(w, http.StatusOK, map[string]any{"summary": summaries})
}
