package handlers

import (
	"net/http"

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

// MaximizerHandlers exposes the Compliance Maximizer API.
type MaximizerHandlers struct {
	svc *maximizer.Service
}

// NewMaximizerHandlers creates handlers backed by a maximizer service.
func NewMaximizerHandlers(svc *maximizer.Service) *MaximizerHandlers {
	return &MaximizerHandlers{svc: svc}
}

// Optimize evaluates a DimensionConfig and returns optimized variants.
func (h *MaximizerHandlers) Optimize(c *gin.Context) {
	var req maximizer.OptimizeInput
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	req.TenantID, _ = getTenantID(c)
	req.UserID = maximizerGetUserID(c)
	result, err := h.svc.Optimize(c.Request.Context(), &req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, result)
}

// OptimizeFromIntake maps a UseCaseIntake to dimensions and optimizes.
func (h *MaximizerHandlers) OptimizeFromIntake(c *gin.Context) {
	var req maximizer.OptimizeFromIntakeInput
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	req.TenantID, _ = getTenantID(c)
	req.UserID = maximizerGetUserID(c)
	result, err := h.svc.OptimizeFromIntake(c.Request.Context(), &req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, result)
}

// OptimizeFromAssessment optimizes an existing UCCA assessment.
func (h *MaximizerHandlers) OptimizeFromAssessment(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid assessment id"})
		return
	}
	tid, _ := getTenantID(c)
	uid := maximizerGetUserID(c)
	result, err := h.svc.OptimizeFromAssessment(c.Request.Context(), id, tid, uid)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, result)
}

// OptimizeFromIntakeWithProfile maps intake + profile to dimensions and optimizes.
func (h *MaximizerHandlers) OptimizeFromIntakeWithProfile(c *gin.Context) {
	var req maximizer.OptimizeFromIntakeWithProfileInput
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	req.TenantID, _ = getTenantID(c)
	req.UserID = maximizerGetUserID(c)
	result, err := h.svc.OptimizeFromIntakeWithProfile(c.Request.Context(), &req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, result)
}

// Evaluate performs a 3-zone evaluation without persisting.
func (h *MaximizerHandlers) Evaluate(c *gin.Context) {
	var config maximizer.DimensionConfig
	if err := c.ShouldBindJSON(&config); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	result := h.svc.Evaluate(&config)
	c.JSON(http.StatusOK, result)
}

// ListOptimizations returns stored optimizations for the tenant.
func (h *MaximizerHandlers) ListOptimizations(c *gin.Context) {
	f := &maximizer.OptimizationFilters{
		Search: c.Query("search"),
		Limit:  maximizerParseInt(c.Query("limit"), 20),
		Offset: maximizerParseInt(c.Query("offset"), 0),
	}
	tid, _ := getTenantID(c)
	results, total, err := h.svc.ListOptimizations(c.Request.Context(), tid, f)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"optimizations": results, "total": total})
}

// GetOptimization returns a single optimization.
func (h *MaximizerHandlers) GetOptimization(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
		return
	}
	result, err := h.svc.GetOptimization(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
		return
	}
	c.JSON(http.StatusOK, result)
}

// DeleteOptimization removes an optimization.
func (h *MaximizerHandlers) DeleteOptimization(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
		return
	}
	if err := h.svc.DeleteOptimization(c.Request.Context(), id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusNoContent, nil)
}

// GetDimensionSchema returns the dimension enum values for the frontend.
func (h *MaximizerHandlers) GetDimensionSchema(c *gin.Context) {
	c.JSON(http.StatusOK, h.svc.GetDimensionSchema())
}

func maximizerGetUserID(c *gin.Context) uuid.UUID {
	if id, exists := c.Get("user_id"); exists {
		if uid, ok := id.(uuid.UUID); ok {
			return uid
		}
	}
	return uuid.Nil
}

// maximizerParseInt is a local helper for query param parsing.
func maximizerParseInt(s string, def int) int {
	if s == "" {
		return def
	}
	n := 0
	for _, c := range s {
		if c < '0' || c > '9' {
			return def
		}
		n = n*10 + int(c-'0')
	}
	return n
}
