package handlers

import (
	"net/http"
	"strconv"

	"github.com/breakpilot/ai-compliance-sdk/internal/portfolio"
	"github.com/breakpilot/ai-compliance-sdk/internal/rbac"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

// ============================================================================
// Statistics & Reports
// ============================================================================

// GetPortfolioStats returns statistics for a portfolio
// GET /sdk/v1/portfolios/:id/stats
func (h *PortfolioHandlers) GetPortfolioStats(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid portfolio ID"})
		return
	}

	stats, err := h.store.GetPortfolioStats(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, stats)
}

// GetPortfolioActivity returns recent activity for a portfolio
// GET /sdk/v1/portfolios/:id/activity
func (h *PortfolioHandlers) GetPortfolioActivity(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid portfolio ID"})
		return
	}

	limit := 20
	if l := c.Query("limit"); l != "" {
		if parsed, err := strconv.Atoi(l); err == nil && parsed > 0 {
			limit = parsed
		}
	}

	activities, err := h.store.GetRecentActivity(c.Request.Context(), id, limit)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"activities": activities,
		"total":      len(activities),
	})
}

// ComparePortfolios compares multiple portfolios
// POST /sdk/v1/portfolios/compare
func (h *PortfolioHandlers) ComparePortfolios(c *gin.Context) {
	var req portfolio.ComparePortfoliosRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if len(req.PortfolioIDs) < 2 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "at least 2 portfolios required for comparison"})
		return
	}
	if len(req.PortfolioIDs) > 5 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "maximum 5 portfolios can be compared"})
		return
	}

	var portfolios []portfolio.Portfolio
	comparison := portfolio.PortfolioComparison{
		RiskScores:       make(map[string]float64),
		ComplianceScores: make(map[string]float64),
		ItemCounts:       make(map[string]int),
		UniqueItems:      make(map[string][]uuid.UUID),
	}

	allItems := make(map[uuid.UUID][]string)

	for _, id := range req.PortfolioIDs {
		p, err := h.store.GetPortfolio(c.Request.Context(), id)
		if err != nil || p == nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "portfolio not found: " + id.String()})
			return
		}
		portfolios = append(portfolios, *p)

		idStr := id.String()
		comparison.RiskScores[idStr] = p.AvgRiskScore
		comparison.ComplianceScores[idStr] = p.ComplianceScore
		comparison.ItemCounts[idStr] = p.TotalAssessments + p.TotalRoadmaps + p.TotalWorkshops

		items, _ := h.store.ListItems(c.Request.Context(), id, nil)
		for _, item := range items {
			allItems[item.ItemID] = append(allItems[item.ItemID], idStr)
		}
	}

	for itemID, portfolioIDs := range allItems {
		if len(portfolioIDs) > 1 {
			comparison.CommonItems = append(comparison.CommonItems, itemID)
		} else {
			pid := portfolioIDs[0]
			comparison.UniqueItems[pid] = append(comparison.UniqueItems[pid], itemID)
		}
	}

	c.JSON(http.StatusOK, portfolio.ComparePortfoliosResponse{
		Portfolios: portfolios,
		Comparison: comparison,
	})
}

// RecalculateMetrics manually recalculates portfolio metrics
// POST /sdk/v1/portfolios/:id/recalculate
func (h *PortfolioHandlers) RecalculateMetrics(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid portfolio ID"})
		return
	}

	if err := h.store.RecalculateMetrics(c.Request.Context(), id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	p, _ := h.store.GetPortfolio(c.Request.Context(), id)

	c.JSON(http.StatusOK, gin.H{
		"message":   "metrics recalculated",
		"portfolio": p,
	})
}

// ============================================================================
// Approval Workflow
// ============================================================================

// ApprovePortfolio approves a portfolio
// POST /sdk/v1/portfolios/:id/approve
func (h *PortfolioHandlers) ApprovePortfolio(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid portfolio ID"})
		return
	}

	p, err := h.store.GetPortfolio(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if p == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "portfolio not found"})
		return
	}

	if p.Status != portfolio.PortfolioStatusReview {
		c.JSON(http.StatusBadRequest, gin.H{"error": "portfolio must be in REVIEW status to approve"})
		return
	}

	userID := rbac.GetUserID(c)
	now := c.Request.Context().Value("now")
	if now == nil {
		t := p.UpdatedAt
		p.ApprovedAt = &t
	}
	p.ApprovedBy = &userID
	p.Status = portfolio.PortfolioStatusApproved

	if err := h.store.UpdatePortfolio(c.Request.Context(), p); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

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

// SubmitForReview submits a portfolio for review
// POST /sdk/v1/portfolios/:id/submit-review
func (h *PortfolioHandlers) SubmitForReview(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid portfolio ID"})
		return
	}

	p, err := h.store.GetPortfolio(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if p == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "portfolio not found"})
		return
	}

	if p.Status != portfolio.PortfolioStatusDraft && p.Status != portfolio.PortfolioStatusActive {
		c.JSON(http.StatusBadRequest, gin.H{"error": "portfolio must be in DRAFT or ACTIVE status to submit for review"})
		return
	}

	p.Status = portfolio.PortfolioStatusReview

	if err := h.store.UpdatePortfolio(c.Request.Context(), p); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"message":   "portfolio submitted for review",
		"portfolio": p,
	})
}
