package handlers

import (
	"net/http"

	"github.com/gin-gonic/gin"

	"chat-switchboard/memory"
	"chat-switchboard/models"
	"chat-switchboard/store"
)

// MemoryHandler provides REST endpoints for memory management.
type MemoryHandler struct {
	stores    store.Stores
	compactor *memory.Compactor
}

// NewMemoryHandler creates a new memory handler.
func NewMemoryHandler(stores store.Stores) *MemoryHandler {
	return &MemoryHandler{stores: stores}
}

// SetCompactor wires the compactor for the /compact endpoint.
func (h *MemoryHandler) SetCompactor(c *memory.Compactor) {
	h.compactor = c
}

// ListMyMemories returns the current user's memories with optional filters.
// GET /api/v1/memories?status=active&query=...
func (h *MemoryHandler) ListMyMemories(c *gin.Context) {
	userID := c.GetString("user_id")
	if userID == "" {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
		return
	}

	status := c.DefaultQuery("status", "active")
	query := c.Query("query")

	memories, err := h.stores.Memories.List(c.Request.Context(), models.MemoryFilter{
		Scope:   models.MemoryScopeUser,
		OwnerID: userID,
		Status:  status,
		Query:   query,
		Limit:   100,
	})
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	if memories == nil {
		memories = []models.Memory{}
	}
	c.JSON(http.StatusOK, gin.H{"data": memories})
}

// UpdateMemory updates a memory's key/value/confidence.
// PUT /api/v1/memories/:id
func (h *MemoryHandler) UpdateMemory(c *gin.Context) {
	userID := c.GetString("user_id")
	memoryID := c.Param("id")

	existing, err := h.stores.Memories.GetByID(c.Request.Context(), memoryID)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "memory not found"})
		return
	}

	// Ownership check: user can only edit their own user-scope memories
	if existing.Scope == models.MemoryScopeUser && existing.OwnerID != userID {
		c.JSON(http.StatusForbidden, gin.H{"error": "not your memory"})
		return
	}

	var body struct {
		Key        *string  `json:"key"`
		Value      *string  `json:"value"`
		Confidence *float64 `json:"confidence"`
	}
	if err := c.ShouldBindJSON(&body); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid body"})
		return
	}

	if body.Key != nil {
		existing.Key = *body.Key
	}
	if body.Value != nil {
		existing.Value = *body.Value
	}
	if body.Confidence != nil {
		existing.Confidence = *body.Confidence
	}

	if err := h.stores.Memories.Update(c.Request.Context(), existing); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"memory": existing})
}

// DeleteMemory hard-deletes a memory.
// DELETE /api/v1/memories/:id
func (h *MemoryHandler) DeleteMemory(c *gin.Context) {
	userID := c.GetString("user_id")
	memoryID := c.Param("id")

	existing, err := h.stores.Memories.GetByID(c.Request.Context(), memoryID)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "memory not found"})
		return
	}

	if existing.Scope == models.MemoryScopeUser && existing.OwnerID != userID {
		c.JSON(http.StatusForbidden, gin.H{"error": "not your memory"})
		return
	}

	if err := h.stores.Memories.Delete(c.Request.Context(), memoryID); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"deleted": true})
}

// ApproveMemory transitions a pending_review memory to active.
// POST /api/v1/memories/:id/approve
func (h *MemoryHandler) ApproveMemory(c *gin.Context) {
	memoryID := c.Param("id")

	existing, err := h.stores.Memories.GetByID(c.Request.Context(), memoryID)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "memory not found"})
		return
	}

	if existing.Status != models.MemoryStatusPendingReview {
		c.JSON(http.StatusConflict, gin.H{"error": "only pending_review memories can be approved"})
		return
	}

	existing.Status = models.MemoryStatusActive
	if err := h.stores.Memories.Upsert(c.Request.Context(), existing); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"memory": existing})
}

// RejectMemory archives a pending_review memory.
// POST /api/v1/memories/:id/reject
func (h *MemoryHandler) RejectMemory(c *gin.Context) {
	userID := c.GetString("user_id")
	memoryID := c.Param("id")

	existing, err := h.stores.Memories.GetByID(c.Request.Context(), memoryID)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "memory not found"})
		return
	}

	// Ownership check: user can only reject their own user-scope memories
	if existing.Scope == models.MemoryScopeUser && existing.OwnerID != userID {
		c.JSON(http.StatusForbidden, gin.H{"error": "not your memory"})
		return
	}

	if existing.Status != models.MemoryStatusPendingReview {
		c.JSON(http.StatusConflict, gin.H{"error": "only pending_review memories can be rejected"})
		return
	}

	if err := h.stores.Memories.Archive(c.Request.Context(), memoryID); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"rejected": true})
}

// MemoryCount returns active + pending counts for the current user.
// GET /api/v1/memories/count
func (h *MemoryHandler) MemoryCount(c *gin.Context) {
	userID := c.GetString("user_id")
	ctx := c.Request.Context()

	active, err := h.stores.Memories.CountByOwner(ctx, models.MemoryScopeUser, userID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Count pending by listing
	pending, err := h.stores.Memories.List(ctx, models.MemoryFilter{
		Scope:   models.MemoryScopeUser,
		OwnerID: userID,
		Status:  models.MemoryStatusPendingReview,
		Limit:   1000,
	})
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"active":  active,
		"pending": len(pending),
	})
}

// ── Admin Endpoints ──────────────────────────

// ListPendingReview returns all pending_review memories (admin only).
// GET /api/v1/admin/memories/pending
func (h *MemoryHandler) ListPendingReview(c *gin.Context) {
	ctx := c.Request.Context()

	memories, err := h.stores.Memories.ListByStatus(ctx, models.MemoryStatusPendingReview, 200)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	if memories == nil {
		memories = []models.Memory{}
	}
	c.JSON(http.StatusOK, gin.H{"data": memories})
}

// BulkApprove approves multiple memories at once.
// POST /api/v1/admin/memories/bulk-approve
func (h *MemoryHandler) BulkApprove(c *gin.Context) {
	var body struct {
		IDs []string `json:"ids"`
	}
	if err := c.ShouldBindJSON(&body); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid body"})
		return
	}

	ctx := c.Request.Context()
	approved := 0
	for _, id := range body.IDs {
		existing, err := h.stores.Memories.GetByID(ctx, id)
		if err != nil {
			continue
		}
		if existing.Status != models.MemoryStatusPendingReview {
			continue
		}
		existing.Status = models.MemoryStatusActive
		if err := h.stores.Memories.Upsert(ctx, existing); err == nil {
			approved++
		}
	}

	c.JSON(http.StatusOK, gin.H{"approved": approved})
}

// CompactMemories triggers memory compaction for the current user.
// POST /api/v1/memories/compact
func (h *MemoryHandler) CompactMemories(c *gin.Context) {
	if h.compactor == nil {
		c.JSON(http.StatusServiceUnavailable, gin.H{"error": "compaction not available"})
		return
	}

	userID := c.GetString("user_id")
	if userID == "" {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
		return
	}

	teamID := c.GetString("team_id")
	var tID *string
	if teamID != "" {
		tID = &teamID
	}

	result, err := h.compactor.Compact(c.Request.Context(), userID, tID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"before":   result.Before,
		"after":    result.After,
		"merged":   result.Merged,
		"archived": result.Archived,
	})
}
