// Package handler contains HTTP handlers for the Control Center API.
// Each handler is a method on a Handler struct that receives its
// dependencies through dependency injection — now wired to PostgreSQL-backed
// repository implementations instead of in-memory stores.
package handler

import (
	"encoding/json"
	"log/slog"
	"net/http"
	"time"

	"code.cubecraftcreations.com/CubeCraft-Creations/Control-Center/go-backend/internal/models"
	"code.cubecraftcreations.com/CubeCraft-Creations/Control-Center/go-backend/internal/repository"
	"github.com/go-chi/chi/v5"
	"github.com/go-playground/validator/v10"
)

// Handler groups all route handlers and their dependencies.
type Handler struct {
	Agents   repository.AgentRepo
	Sessions repository.SessionRepo
	Tasks    repository.TaskRepo
	Projects repository.ProjectRepo
	validate *validator.Validate
}

// NewHandler returns a fully wired Handler with repository backends.
func NewHandler(
	ar repository.AgentRepo,
	sr repository.SessionRepo,
	tr repository.TaskRepo,
	pr repository.ProjectRepo,
) *Handler {
	v := validator.New()
	v.RegisterValidation("agentStatus", validateAgentStatus)
	return &Handler{
		Agents:   ar,
		Sessions: sr,
		Tasks:    tr,
		Projects: pr,
		validate: v,
	}
}

// ─── Agent Handlers ────────────────────────────────────────────────────────────

// ListAgents handles GET /api/agents.
func (h *Handler) ListAgents(w http.ResponseWriter, r *http.Request) {
	statusFilter := models.AgentStatus(r.URL.Query().Get("status"))
	allAgents, err := h.Agents.List(r.Context(), statusFilter)
	if err != nil {
		slog.Error("list agents failed", "error", err)
		writeJSON(w, http.StatusInternalServerError, models.ErrorResponse{Error: "failed to list agents"})
		return
	}

	page, pageSize := parsePagination(r)
	start, end := paginateSlice(len(allAgents), page, pageSize)

	totalCount, _ := h.Agents.Count(r.Context())
	writeJSON(w, http.StatusOK, models.PaginatedResponse{
		Data:       allAgents[start:end],
		TotalCount: totalCount,
		Page:       page,
		PageSize:   pageSize,
		HasMore:    end < len(allAgents),
	})
}

// GetAgent handles GET /api/agents/{id}.
func (h *Handler) GetAgent(w http.ResponseWriter, r *http.Request) {
	id := chi.URLParam(r, "id")
	agent, err := h.Agents.Get(r.Context(), id)
	if err != nil {
		writeJSON(w, http.StatusNotFound, models.ErrorResponse{Error: "agent not found"})
		return
	}
	writeJSON(w, http.StatusOK, agent)
}

// CreateAgent handles POST /api/agents.
func (h *Handler) CreateAgent(w http.ResponseWriter, r *http.Request) {
	var req models.CreateAgentRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		writeJSON(w, http.StatusBadRequest, models.ErrorResponse{Error: "invalid request body"})
		return
	}

	if err := h.validate.Struct(req); err != nil {
		writeJSON(w, http.StatusUnprocessableEntity, models.ErrorResponse{
			Error:   "validation failed",
			Details: validationErrors(err),
		})
		return
	}

	agent := models.AgentCardData{
		ID:           req.ID,
		DisplayName:  req.DisplayName,
		Role:         req.Role,
		Status:       req.Status,
		CurrentTask:  req.CurrentTask,
		SessionKey:   req.SessionKey,
		Channel:      req.Channel,
		LastActivity: time.Now().UTC().Format(time.RFC3339),
	}

	if err := h.Agents.Create(r.Context(), agent); err != nil {
		writeJSON(w, http.StatusConflict, models.ErrorResponse{Error: "agent with this ID already exists"})
		return
	}
	writeJSON(w, http.StatusCreated, agent)
}

// UpdateAgent handles PUT /api/agents/{id}.
func (h *Handler) UpdateAgent(w http.ResponseWriter, r *http.Request) {
	id := chi.URLParam(r, "id")

	var req models.UpdateAgentRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		writeJSON(w, http.StatusBadRequest, models.ErrorResponse{Error: "invalid request body"})
		return
	}

	if err := h.validate.Struct(req); err != nil {
		writeJSON(w, http.StatusUnprocessableEntity, models.ErrorResponse{
			Error:   "validation failed",
			Details: validationErrors(err),
		})
		return
	}

	agent, err := h.Agents.Update(r.Context(), id, req)
	if err != nil {
		writeJSON(w, http.StatusNotFound, models.ErrorResponse{Error: "agent not found"})
		return
	}
	writeJSON(w, http.StatusOK, agent)
}

// DeleteAgent handles DELETE /api/agents/{id}.
func (h *Handler) DeleteAgent(w http.ResponseWriter, r *http.Request) {
	id := chi.URLParam(r, "id")
	if err := h.Agents.Delete(r.Context(), id); err != nil {
		writeJSON(w, http.StatusNotFound, models.ErrorResponse{Error: "agent not found"})
		return
	}
	w.WriteHeader(http.StatusNoContent)
}

// AgentHistory handles GET /api/agents/{id}/history.
func (h *Handler) AgentHistory(w http.ResponseWriter, r *http.Request) {
	id := chi.URLParam(r, "id")
	if _, err := h.Agents.Get(r.Context(), id); err != nil {
		writeJSON(w, http.StatusNotFound, models.ErrorResponse{Error: "agent not found"})
		return
	}

	// History is not currently persisted in PostgreSQL — return stub.
	writeJSON(w, http.StatusOK, []models.AgentStatusHistoryEntry{})
}
