// Package api provides HTTP handlers for the Compliance Engine
package api

import (
	"net/http"
	"time"

	"github.com/breakpilot/compliance-sdk/services/compliance-engine/internal/ucca"
	"github.com/gin-gonic/gin"
)

// Assess performs a full compliance assessment
func Assess(engine *ucca.Engine) gin.HandlerFunc {
	return func(c *gin.Context) {
		var state map[string]interface{}
		if err := c.ShouldBindJSON(&state); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		result := engine.Assess(state)
		result.Timestamp = time.Now().Format(time.RFC3339)

		c.JSON(http.StatusOK, result)
	}
}

// AssessControl assesses a single control
func AssessControl(engine *ucca.Engine) gin.HandlerFunc {
	return func(c *gin.Context) {
		var req struct {
			ControlID string                 `json:"control_id" binding:"required"`
			State     map[string]interface{} `json:"state"`
		}
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		controls := engine.GetControls()
		ctrl, exists := controls[req.ControlID]
		if !exists {
			c.JSON(http.StatusNotFound, gin.H{"error": "Control not found"})
			return
		}

		c.JSON(http.StatusOK, gin.H{
			"control":        ctrl,
			"status":         "ASSESSED",
			"compliance":     true,
			"recommendations": []string{},
		})
	}
}

// AssessRegulation assesses compliance with a specific regulation
func AssessRegulation(engine *ucca.Engine) gin.HandlerFunc {
	return func(c *gin.Context) {
		var req struct {
			RegulationCode string                 `json:"regulation_code" binding:"required"`
			State          map[string]interface{} `json:"state"`
		}
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		regulations := engine.GetRegulations()
		reg, exists := regulations[req.RegulationCode]
		if !exists {
			c.JSON(http.StatusNotFound, gin.H{"error": "Regulation not found"})
			return
		}

		result := engine.Assess(req.State)

		c.JSON(http.StatusOK, gin.H{
			"regulation": reg,
			"score":      result.ByRegulation[req.RegulationCode],
			"findings":   filterFindings(result.Findings, req.RegulationCode),
			"assessed_at": time.Now().Format(time.RFC3339),
		})
	}
}

// CalculateScore calculates the compliance score
func CalculateScore(engine *ucca.Engine) gin.HandlerFunc {
	return func(c *gin.Context) {
		var state map[string]interface{}
		if err := c.ShouldBindJSON(&state); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		result := engine.Assess(state)

		c.JSON(http.StatusOK, gin.H{
			"overall":       result.OverallScore,
			"trend":         result.Trend,
			"by_regulation": result.ByRegulation,
			"by_domain":     result.ByDomain,
			"calculated_at": time.Now().Format(time.RFC3339),
		})
	}
}

// ScoreBreakdown provides a detailed score breakdown
func ScoreBreakdown(engine *ucca.Engine) gin.HandlerFunc {
	return func(c *gin.Context) {
		var state map[string]interface{}
		if err := c.ShouldBindJSON(&state); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		result := engine.Assess(state)

		// Calculate detailed breakdown
		breakdown := gin.H{
			"overall": gin.H{
				"score":       result.OverallScore,
				"max":         100,
				"trend":       result.Trend,
				"description": getScoreDescription(result.OverallScore),
			},
			"by_regulation": []gin.H{},
			"by_domain":     []gin.H{},
			"by_category": gin.H{
				"documentation": 75,
				"technical":     80,
				"organizational": 70,
			},
		}

		for reg, score := range result.ByRegulation {
			breakdown["by_regulation"] = append(
				breakdown["by_regulation"].([]gin.H),
				gin.H{"code": reg, "score": score, "status": getStatus(score)},
			)
		}

		for domain, score := range result.ByDomain {
			breakdown["by_domain"] = append(
				breakdown["by_domain"].([]gin.H),
				gin.H{"domain": domain, "score": score, "status": getStatus(score)},
			)
		}

		c.JSON(http.StatusOK, breakdown)
	}
}

// GetObligations returns all regulatory obligations
func GetObligations(engine *ucca.Engine) gin.HandlerFunc {
	return func(c *gin.Context) {
		regulations := engine.GetRegulations()
		obligations := []gin.H{}

		for code, reg := range regulations {
			for _, article := range reg.Articles {
				obligations = append(obligations, gin.H{
					"id":              code + "-" + article,
					"regulation_code": code,
					"regulation_name": reg.Name,
					"article":         article,
					"status":          "PENDING",
				})
			}
		}

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

// GetObligationsByRegulation returns obligations for a specific regulation
func GetObligationsByRegulation(engine *ucca.Engine) gin.HandlerFunc {
	return func(c *gin.Context) {
		regCode := c.Param("regulation")

		regulations := engine.GetRegulations()
		reg, exists := regulations[regCode]
		if !exists {
			c.JSON(http.StatusNotFound, gin.H{"error": "Regulation not found"})
			return
		}

		obligations := []gin.H{}
		for _, article := range reg.Articles {
			obligations = append(obligations, gin.H{
				"id":              regCode + "-" + article,
				"regulation_code": regCode,
				"article":         article,
				"status":          "PENDING",
			})
		}

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

// GetControlsCatalog returns the controls catalog
func GetControlsCatalog(engine *ucca.Engine) gin.HandlerFunc {
	return func(c *gin.Context) {
		controls := engine.GetControls()
		result := []gin.H{}

		for _, ctrl := range controls {
			result = append(result, gin.H{
				"id":          ctrl.ID,
				"name":        ctrl.Name,
				"description": ctrl.Description,
				"domain":      ctrl.Domain,
				"category":    ctrl.Category,
				"objective":   ctrl.Objective,
			})
		}

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

// GetControlsByDomain returns controls for a specific domain
func GetControlsByDomain(engine *ucca.Engine) gin.HandlerFunc {
	return func(c *gin.Context) {
		domain := c.Param("domain")
		controls := engine.GetControlsByDomain(domain)

		result := []gin.H{}
		for _, ctrl := range controls {
			result = append(result, gin.H{
				"id":          ctrl.ID,
				"name":        ctrl.Name,
				"description": ctrl.Description,
				"category":    ctrl.Category,
				"objective":   ctrl.Objective,
				"guidance":    ctrl.Guidance,
				"evidence":    ctrl.Evidence,
			})
		}

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

// ListPolicies lists all loaded policies
func ListPolicies(engine *ucca.Engine) gin.HandlerFunc {
	return func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"total_rules":       engine.RuleCount(),
			"total_regulations": len(engine.GetRegulations()),
			"total_controls":    len(engine.GetControls()),
			"regulations":       getRegulationCodes(engine),
		})
	}
}

// GetPolicy returns details of a specific policy
func GetPolicy(engine *ucca.Engine) gin.HandlerFunc {
	return func(c *gin.Context) {
		policyID := c.Param("id")

		regulations := engine.GetRegulations()
		if reg, exists := regulations[policyID]; exists {
			c.JSON(http.StatusOK, reg)
			return
		}

		c.JSON(http.StatusNotFound, gin.H{"error": "Policy not found"})
	}
}

// Helper functions

func filterFindings(findings []ucca.Finding, regulation string) []ucca.Finding {
	result := []ucca.Finding{}
	for _, f := range findings {
		if f.Regulation == regulation {
			result = append(result, f)
		}
	}
	return result
}

func getScoreDescription(score int) string {
	switch {
	case score >= 90:
		return "Excellent - Full compliance achieved"
	case score >= 75:
		return "Good - Minor improvements needed"
	case score >= 50:
		return "Fair - Significant work required"
	default:
		return "Poor - Major compliance gaps exist"
	}
}

func getStatus(score int) string {
	switch {
	case score >= 80:
		return "COMPLIANT"
	case score >= 60:
		return "PARTIAL"
	default:
		return "NON_COMPLIANT"
	}
}

func getRegulationCodes(engine *ucca.Engine) []string {
	regulations := engine.GetRegulations()
	codes := make([]string, 0, len(regulations))
	for code := range regulations {
		codes = append(codes, code)
	}
	return codes
}
