package handlers

import (
	"fmt"
	"net/http"
	"strings"

	"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"
)

// ============================================================================
// CE Technical File
// ============================================================================

// GenerateTechFile handles POST /projects/:id/tech-file/generate
// Generates technical file sections for a project.
// TODO: Integrate LLM for intelligent content generation based on project data.
func (h *IACEHandler) GenerateTechFile(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
	}

	// Define sections per EU Machinery Regulation 2023/1230 Annex IV structure.
	// Core Annex IV sections come first, then supplementary CE-Akte sections.
	sectionDefinitions := []struct {
		SectionType string
		Title       string
	}{
		// Annex IV mandatory sections
		{"general_description", "Anhang IV.1 — Allgemeine Beschreibung der Maschine"},
		{"design_specifications", "Anhang IV.2 — Gesamtplan und Schaltplaene"},
		{"component_list", "Anhang IV.3 — Detailplaene und Komponentenliste"},
		{"risk_assessment_report", "Anhang IV.4 — Risikobeurteilung"},
		{"standards_applied", "Anhang IV.5 — Angewandte harmonisierte Normen"},
		{"test_reports", "Anhang IV.6 — Pruefberichte und Ergebnisse"},
		{"instructions_for_use", "Anhang IV.7 — Betriebsanleitung"},
		{"declaration_of_conformity", "Anhang IV.8 — EU-Konformitaetserklaerung"},
		{"assembly_declaration", "Anhang IV.9 — Einbauerklaerung (falls zutreffend)"},
		// Supplementary CE-Akte sections
		{"hazard_log_combined", "Gefaehrdungsprotokoll (Hazard Log)"},
		{"essential_requirements", "Grundlegende Anforderungen (EHSR)"},
		{"mitigation_report", "Massnahmenbericht (3-Stufen-Verfahren)"},
		{"verification_report", "Verifikationsbericht"},
		{"evidence_index", "Nachweisverzeichnis"},
		{"classification_report", "Regulatorischer Klassifizierungsbericht"},
		{"monitoring_plan", "Post-Market-Monitoring-Plan"},
	}

	// Check if project has AI components for additional sections
	components, _ := h.store.ListComponents(c.Request.Context(), projectID)
	hasAI := false
	for _, comp := range components {
		if comp.ComponentType == iace.ComponentTypeAIModel {
			hasAI = true
			break
		}
	}

	if hasAI {
		sectionDefinitions = append(sectionDefinitions,
			struct {
				SectionType string
				Title       string
			}{"ai_intended_purpose", "AI System Intended Purpose"},
			struct {
				SectionType string
				Title       string
			}{"ai_model_description", "AI Model Description and Training Data"},
			struct {
				SectionType string
				Title       string
			}{"ai_risk_management", "AI Risk Management System"},
			struct {
				SectionType string
				Title       string
			}{"ai_human_oversight", "AI Human Oversight Measures"},
		)
	}

	// Generate each section with LLM-based content
	var sections []iace.TechFileSection
	existingSections, _ := h.store.ListTechFileSections(c.Request.Context(), projectID)
	existingMap := make(map[string]bool)
	for _, s := range existingSections {
		existingMap[s.SectionType] = true
	}

	for _, def := range sectionDefinitions {
		// Skip sections that already exist
		if existingMap[def.SectionType] {
			continue
		}

		// Generate content via LLM (falls back to structured placeholder if LLM unavailable)
		content, _ := h.techFileGen.GenerateSection(c.Request.Context(), projectID, def.SectionType)
		if content == "" {
			content = fmt.Sprintf("[Sektion: %s — Inhalt wird generiert]", def.Title)
		}

		section, err := h.store.CreateTechFileSection(
			c.Request.Context(), projectID, def.SectionType, def.Title, content,
		)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
		sections = append(sections, *section)
	}

	// Update project status
	h.store.UpdateProjectStatus(c.Request.Context(), projectID, iace.ProjectStatusTechFile)

	// Audit trail
	userID := rbac.GetUserID(c)
	h.store.AddAuditEntry(
		c.Request.Context(), projectID, "tech_file", projectID,
		iace.AuditActionCreate, userID.String(), nil, nil,
	)

	c.JSON(http.StatusCreated, gin.H{
		"sections_created": len(sections),
		"sections":         sections,
	})
}

// GenerateSingleSection handles POST /projects/:id/tech-file/:section/generate
// Generates or regenerates a single tech file section using LLM.
func (h *IACEHandler) GenerateSingleSection(c *gin.Context) {
	projectID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"})
		return
	}

	sectionType := c.Param("section")
	if sectionType == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "section type required"})
		return
	}

	// Generate content via LLM
	content, err := h.techFileGen.GenerateSection(c.Request.Context(), projectID, sectionType)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("generation failed: %v", err)})
		return
	}

	// Find existing section and update, or create new
	sections, _ := h.store.ListTechFileSections(c.Request.Context(), projectID)
	var sectionID uuid.UUID
	found := false
	for _, s := range sections {
		if s.SectionType == sectionType {
			sectionID = s.ID
			found = true
			break
		}
	}

	if found {
		if err := h.store.UpdateTechFileSection(c.Request.Context(), sectionID, content); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
	} else {
		title := sectionType // fallback
		sectionTitles := map[string]string{
			"general_description":       "General Description of the Machinery",
			"risk_assessment_report":    "Risk Assessment Report",
			"hazard_log_combined":       "Combined Hazard Log",
			"essential_requirements":    "Essential Health and Safety Requirements",
			"design_specifications":     "Design Specifications and Drawings",
			"test_reports":              "Test Reports and Verification Results",
			"standards_applied":         "Applied Harmonised Standards",
			"declaration_of_conformity": "EU Declaration of Conformity",
			"component_list":            "Component List",
			"classification_report":     "Regulatory Classification Report",
			"mitigation_report":         "Mitigation Measures Report",
			"verification_report":       "Verification Report",
			"evidence_index":            "Evidence Index",
			"instructions_for_use":      "Instructions for Use",
			"monitoring_plan":           "Post-Market Monitoring Plan",
			"assembly_declaration":      "Anhang IV.9 — Einbauerklaerung (falls zutreffend)",
			"ai_intended_purpose":       "AI System Intended Purpose",
			"ai_model_description":      "AI Model Description and Training Data",
			"ai_risk_management":        "AI Risk Management System",
			"ai_human_oversight":        "AI Human Oversight Measures",
		}
		if t, ok := sectionTitles[sectionType]; ok {
			title = t
		}

		_, err := h.store.CreateTechFileSection(c.Request.Context(), projectID, sectionType, title, content)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
	}

	// Audit trail
	userID := rbac.GetUserID(c)
	h.store.AddAuditEntry(
		c.Request.Context(), projectID, "tech_file_section", projectID,
		iace.AuditActionCreate, userID.String(), nil, nil,
	)

	c.JSON(http.StatusOK, gin.H{
		"message":      "section generated",
		"section_type": sectionType,
		"content":      content,
	})
}

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

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

	if sections == nil {
		sections = []iace.TechFileSection{}
	}

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

// UpdateTechFileSection handles PUT /projects/:id/tech-file/:section
// Updates the content of a technical file section (identified by section_type).
func (h *IACEHandler) UpdateTechFileSection(c *gin.Context) {
	projectID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"})
		return
	}

	sectionType := c.Param("section")
	if sectionType == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "section type required"})
		return
	}

	var req struct {
		Content string `json:"content" binding:"required"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// Find the section by project ID and section type
	sections, err := h.store.ListTechFileSections(c.Request.Context(), projectID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	var sectionID uuid.UUID
	found := false
	for _, s := range sections {
		if s.SectionType == sectionType {
			sectionID = s.ID
			found = true
			break
		}
	}

	if !found {
		c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("tech file section '%s' not found", sectionType)})
		return
	}

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

	// Audit trail
	userID := rbac.GetUserID(c)
	h.store.AddAuditEntry(
		c.Request.Context(), projectID, "tech_file_section", sectionID,
		iace.AuditActionUpdate, userID.String(), nil, nil,
	)

	c.JSON(http.StatusOK, gin.H{"message": "tech file section updated"})
}

// ApproveTechFileSection handles POST /projects/:id/tech-file/:section/approve
// Marks a technical file section as approved.
func (h *IACEHandler) ApproveTechFileSection(c *gin.Context) {
	projectID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"})
		return
	}

	sectionType := c.Param("section")
	if sectionType == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "section type required"})
		return
	}

	// Find the section by project ID and section type
	sections, err := h.store.ListTechFileSections(c.Request.Context(), projectID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	var sectionID uuid.UUID
	found := false
	for _, s := range sections {
		if s.SectionType == sectionType {
			sectionID = s.ID
			found = true
			break
		}
	}

	if !found {
		c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("tech file section '%s' not found", sectionType)})
		return
	}

	userID := rbac.GetUserID(c)

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

	// Audit trail
	h.store.AddAuditEntry(
		c.Request.Context(), projectID, "tech_file_section", sectionID,
		iace.AuditActionApprove, userID.String(), nil, nil,
	)

	c.JSON(http.StatusOK, gin.H{"message": "tech file section approved"})
}

// ExportTechFile handles GET /projects/:id/tech-file/export?format=pdf|xlsx|docx|md|json
// Exports all tech file sections in the requested format. When the archive
// succeeds, archiveTechFile (in iace_handler_techfile_archive.go) attaches
// X-DSMS-* response headers carrying the resulting CID so the frontend can
// render an inline CID-badge in the export-success path.
func (h *IACEHandler) ExportTechFile(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
	}

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

	// Load hazards, assessments, mitigations, classifications for export
	hazards, _ := h.store.ListHazards(c.Request.Context(), projectID)
	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...)
	}
	classifications, _ := h.store.GetClassifications(c.Request.Context(), projectID)

	format := c.DefaultQuery("format", "json")
	safeName := strings.ReplaceAll(project.MachineName, " ", "_")

	switch format {
	case "pdf":
		data, err := h.exporter.ExportPDF(project, sections, hazards, allAssessments, allMitigations, classifications)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("PDF export failed: %v", err)})
			return
		}
		h.archiveTechFile(c, data, fmt.Sprintf("CE-Akte-%s.pdf", safeName), projectID)
		c.Header("Content-Disposition", fmt.Sprintf(`attachment; filename="CE-Akte-%s.pdf"`, safeName))
		c.Data(http.StatusOK, "application/pdf", data)

	case "xlsx":
		data, err := h.exporter.ExportExcel(project, sections, hazards, allAssessments, allMitigations)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Excel export failed: %v", err)})
			return
		}
		h.archiveTechFile(c, data, fmt.Sprintf("CE-Akte-%s.xlsx", safeName), projectID)
		c.Header("Content-Disposition", fmt.Sprintf(`attachment; filename="CE-Akte-%s.xlsx"`, safeName))
		c.Data(http.StatusOK, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", data)

	case "docx":
		data, err := h.exporter.ExportDOCX(project, sections)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("DOCX export failed: %v", err)})
			return
		}
		h.archiveTechFile(c, data, fmt.Sprintf("CE-Akte-%s.docx", safeName), projectID)
		c.Header("Content-Disposition", fmt.Sprintf(`attachment; filename="CE-Akte-%s.docx"`, safeName))
		c.Data(http.StatusOK, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", data)

	case "md":
		data, err := h.exporter.ExportMarkdown(project, sections)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Markdown export failed: %v", err)})
			return
		}
		h.archiveTechFile(c, data, fmt.Sprintf("CE-Akte-%s.md", safeName), projectID)
		c.Header("Content-Disposition", fmt.Sprintf(`attachment; filename="CE-Akte-%s.md"`, safeName))
		c.Data(http.StatusOK, "text/markdown", data)

	default:
		// JSON export (original behavior)
		allApproved := true
		for _, s := range sections {
			if s.Status != iace.TechFileSectionStatusApproved {
				allApproved = false
				break
			}
		}
		riskSummary, _ := h.store.GetRiskSummary(c.Request.Context(), projectID)

		c.JSON(http.StatusOK, gin.H{
			"project":         project,
			"sections":        sections,
			"classifications": classifications,
			"risk_summary":    riskSummary,
			"all_approved":    allApproved,
			"export_format":   "json",
		})
	}
}
