package handlers

import (
	"encoding/json"
	"fmt"
	"net/http"

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

// ============================================================================
// Component Management
// ============================================================================

// CreateComponent handles POST /projects/:id/components
// Adds a new component to a project.
func (h *IACEHandler) CreateComponent(c *gin.Context) {
	projectID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"})
		return
	}

	var req iace.CreateComponentRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// Override project ID from URL path
	req.ProjectID = projectID

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

	// Audit trail
	userID := rbac.GetUserID(c)
	newVals, _ := json.Marshal(component)
	h.store.AddAuditEntry(
		c.Request.Context(), projectID, "component", component.ID,
		iace.AuditActionCreate, userID.String(), nil, newVals,
	)

	c.JSON(http.StatusCreated, gin.H{"component": component})
}

// ListComponents handles GET /projects/:id/components
// Lists all components for a project.
func (h *IACEHandler) ListComponents(c *gin.Context) {
	projectID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"})
		return
	}

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

	if components == nil {
		components = []iace.Component{}
	}

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

// UpdateComponent handles PUT /projects/:id/components/:cid
// Updates a component with the provided fields.
func (h *IACEHandler) UpdateComponent(c *gin.Context) {
	_, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"})
		return
	}

	componentID, err := uuid.Parse(c.Param("cid"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid component ID"})
		return
	}

	var updates map[string]interface{}
	if err := c.ShouldBindJSON(&updates); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	component, err := h.store.UpdateComponent(c.Request.Context(), componentID, updates)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if component == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "component not found"})
		return
	}

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

// DeleteComponent handles DELETE /projects/:id/components/:cid
// Deletes a component from a project.
func (h *IACEHandler) DeleteComponent(c *gin.Context) {
	_, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"})
		return
	}

	componentID, err := uuid.Parse(c.Param("cid"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid component ID"})
		return
	}

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

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

// CheckCompleteness handles POST /projects/:id/completeness-check
// Loads all project data, evaluates all 25 CE completeness gates, updates the
// project's completeness score, and returns the result.
func (h *IACEHandler) CheckCompleteness(c *gin.Context) {
	projectID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"})
		return
	}

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

	// Load all related entities
	components, _ := h.store.ListComponents(c.Request.Context(), projectID)
	classifications, _ := h.store.GetClassifications(c.Request.Context(), projectID)
	hazards, _ := h.store.ListHazards(c.Request.Context(), projectID)

	// Collect all assessments and mitigations across all hazards
	var allAssessments []iace.RiskAssessment
	var allMitigations []iace.Mitigation
	for _, hazard := range hazards {
		assessments, _ := h.store.ListAssessments(c.Request.Context(), hazard.ID)
		allAssessments = append(allAssessments, assessments...)

		mitigations, _ := h.store.ListMitigations(c.Request.Context(), hazard.ID)
		allMitigations = append(allMitigations, mitigations...)
	}

	evidence, _ := h.store.ListEvidence(c.Request.Context(), projectID)
	techFileSections, _ := h.store.ListTechFileSections(c.Request.Context(), projectID)

	// Determine if the project has AI components
	hasAI := false
	for _, comp := range components {
		if comp.ComponentType == iace.ComponentTypeAIModel {
			hasAI = true
			break
		}
	}

	// Check audit trail for pattern matching
	patternMatchingPerformed, _ := h.store.HasAuditEntryForType(c.Request.Context(), projectID, "pattern_matching")

	// Build completeness context
	completenessCtx := &iace.CompletenessContext{
		Project:                  project,
		Components:               components,
		Classifications:          classifications,
		Hazards:                  hazards,
		Assessments:              allAssessments,
		Mitigations:              allMitigations,
		Evidence:                 evidence,
		TechFileSections:         techFileSections,
		HasAI:                    hasAI,
		PatternMatchingPerformed: patternMatchingPerformed,
	}

	// Run the checker
	result := h.checker.Check(completenessCtx)

	// Build risk summary for the project update
	riskSummary := map[string]int{
		"total_hazards": len(hazards),
	}
	for _, a := range allAssessments {
		riskSummary[string(a.RiskLevel)]++
	}

	// Update project completeness score and risk summary
	if err := h.store.UpdateProjectCompleteness(
		c.Request.Context(), projectID, result.Score, riskSummary,
	); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

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

// ============================================================================
// Classification
// ============================================================================

// Classify handles POST /projects/:id/classify
// Runs all regulatory classifiers (AI Act, Machinery Regulation, CRA, NIS2),
// upserts each result into the store, and returns classifications.
func (h *IACEHandler) Classify(c *gin.Context) {
	projectID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"})
		return
	}

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

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

	// Run all classifiers
	results := h.classifier.ClassifyAll(project, components)

	// Upsert each classification result into the store
	var classifications []iace.RegulatoryClassification
	for _, r := range results {
		reqsJSON, _ := json.Marshal(r.Requirements)

		classification, err := h.store.UpsertClassification(
			c.Request.Context(),
			projectID,
			r.Regulation,
			r.ClassificationResult,
			r.RiskLevel,
			r.Confidence,
			r.Reasoning,
			nil, // ragSources - not available from rule-based classifier
			reqsJSON,
		)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
		if classification != nil {
			classifications = append(classifications, *classification)
		}
	}

	// Advance project status to classification
	h.store.UpdateProjectStatus(c.Request.Context(), projectID, iace.ProjectStatusClassification)

	// Audit trail
	userID := rbac.GetUserID(c)
	newVals, _ := json.Marshal(classifications)
	h.store.AddAuditEntry(
		c.Request.Context(), projectID, "classification", projectID,
		iace.AuditActionCreate, userID.String(), nil, newVals,
	)

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

// GetClassifications handles GET /projects/:id/classifications
// Returns all regulatory classifications for a project.
func (h *IACEHandler) GetClassifications(c *gin.Context) {
	projectID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"})
		return
	}

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

	if classifications == nil {
		classifications = []iace.RegulatoryClassification{}
	}

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

// ClassifySingle handles POST /projects/:id/classify/:regulation
// Runs a single regulatory classifier for the specified regulation type.
func (h *IACEHandler) ClassifySingle(c *gin.Context) {
	projectID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"})
		return
	}

	regulation := iace.RegulationType(c.Param("regulation"))

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

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

	// Run the appropriate classifier
	var result iace.ClassificationResult
	switch regulation {
	case iace.RegulationAIAct:
		result = h.classifier.ClassifyAIAct(project, components)
	case iace.RegulationMachineryRegulation:
		result = h.classifier.ClassifyMachineryRegulation(project, components)
	case iace.RegulationCRA:
		result = h.classifier.ClassifyCRA(project, components)
	case iace.RegulationNIS2:
		result = h.classifier.ClassifyNIS2(project, components)
	default:
		c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("unknown regulation type: %s", regulation)})
		return
	}

	// Upsert the classification result
	reqsJSON, _ := json.Marshal(result.Requirements)

	classification, err := h.store.UpsertClassification(
		c.Request.Context(),
		projectID,
		result.Regulation,
		result.ClassificationResult,
		result.RiskLevel,
		result.Confidence,
		result.Reasoning,
		nil,
		reqsJSON,
	)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

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