package iace

import (
	"fmt"

	"github.com/xuri/excelize/v2"
)

// ExportExcel generates an XLSX workbook with project data across multiple sheets
func (e *DocumentExporter) ExportExcel(
	project *Project,
	sections []TechFileSection,
	hazards []Hazard,
	assessments []RiskAssessment,
	mitigations []Mitigation,
) ([]byte, error) {
	if project == nil {
		return nil, fmt.Errorf("project must not be nil")
	}

	f := excelize.NewFile()
	defer f.Close()

	overviewSheet := "Uebersicht"
	f.SetSheetName("Sheet1", overviewSheet)
	e.xlsxOverview(f, overviewSheet, project)

	hazardSheet := "Gefaehrdungsprotokoll"
	f.NewSheet(hazardSheet)
	e.xlsxHazardLog(f, hazardSheet, hazards, assessments)

	mitigationSheet := "Massnahmen"
	f.NewSheet(mitigationSheet)
	e.xlsxMitigations(f, mitigationSheet, mitigations)

	matrixSheet := "Risikomatrix"
	f.NewSheet(matrixSheet)
	e.xlsxRiskMatrix(f, matrixSheet, assessments)

	sectionSheet := "Sektionen"
	f.NewSheet(sectionSheet)
	e.xlsxSections(f, sectionSheet, sections)

	buf, err := f.WriteToBuffer()
	if err != nil {
		return nil, fmt.Errorf("failed to write Excel: %w", err)
	}
	return buf.Bytes(), nil
}

func (e *DocumentExporter) xlsxOverview(f *excelize.File, sheet string, project *Project) {
	headerStyle, _ := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{Bold: true, Size: 11},
		Fill: excelize.Fill{Type: "pattern", Pattern: 1, Color: []string{"D9E1F2"}},
	})

	f.SetColWidth(sheet, "A", "A", 30)
	f.SetColWidth(sheet, "B", "B", 50)

	rows := [][]string{
		{"Eigenschaft", "Wert"},
		{"Maschinenname", project.MachineName},
		{"Maschinentyp", project.MachineType},
		{"Hersteller", project.Manufacturer},
		{"Beschreibung", project.Description},
		{"CE-Kennzeichnungsziel", project.CEMarkingTarget},
		{"Projektstatus", string(project.Status)},
		{"Vollstaendigkeits-Score", fmt.Sprintf("%.1f%%", project.CompletenessScore*100)},
		{"Erstellt am", project.CreatedAt.Format("02.01.2006 15:04")},
		{"Aktualisiert am", project.UpdatedAt.Format("02.01.2006 15:04")},
	}

	for i, row := range rows {
		rowNum := i + 1
		f.SetCellValue(sheet, cellRef("A", rowNum), row[0])
		f.SetCellValue(sheet, cellRef("B", rowNum), row[1])
		if i == 0 {
			f.SetCellStyle(sheet, cellRef("A", rowNum), cellRef("B", rowNum), headerStyle)
		}
	}
}

func (e *DocumentExporter) xlsxHazardLog(f *excelize.File, sheet string, hazards []Hazard, assessments []RiskAssessment) {
	headerStyle, _ := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{Bold: true, Size: 10, Color: "FFFFFF"},
		Fill: excelize.Fill{Type: "pattern", Pattern: 1, Color: []string{"4472C4"}},
		Alignment: &excelize.Alignment{Horizontal: "center"},
	})

	headers := []string{"Nr", "Name", "Kategorie", "Beschreibung", "S", "E", "P", "A",
		"Inherent Risk", "C_eff", "Residual Risk", "Risk Level", "Akzeptabel"}

	colWidths := map[string]float64{
		"A": 6, "B": 25, "C": 20, "D": 35, "E": 8, "F": 8, "G": 8, "H": 8,
		"I": 14, "J": 10, "K": 14, "L": 18, "M": 12,
	}
	for col, w := range colWidths {
		f.SetColWidth(sheet, col, col, w)
	}

	cols := []string{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M"}
	for i, h := range headers {
		f.SetCellValue(sheet, cellRef(cols[i], 1), h)
	}
	f.SetCellStyle(sheet, "A1", cellRef(cols[len(cols)-1], 1), headerStyle)

	assessMap := buildAssessmentMap(assessments)

	for i, hazard := range hazards {
		row := i + 2
		a := assessMap[hazard.ID.String()]

		f.SetCellValue(sheet, cellRef("A", row), i+1)
		f.SetCellValue(sheet, cellRef("B", row), hazard.Name)
		f.SetCellValue(sheet, cellRef("C", row), hazard.Category)
		f.SetCellValue(sheet, cellRef("D", row), hazard.Description)

		if a != nil {
			f.SetCellValue(sheet, cellRef("E", row), a.Severity)
			f.SetCellValue(sheet, cellRef("F", row), a.Exposure)
			f.SetCellValue(sheet, cellRef("G", row), a.Probability)
			f.SetCellValue(sheet, cellRef("H", row), a.Avoidance)
			f.SetCellValue(sheet, cellRef("I", row), fmt.Sprintf("%.1f", a.InherentRisk))
			f.SetCellValue(sheet, cellRef("J", row), fmt.Sprintf("%.2f", a.CEff))
			f.SetCellValue(sheet, cellRef("K", row), fmt.Sprintf("%.1f", a.ResidualRisk))
			f.SetCellValue(sheet, cellRef("L", row), riskLevelLabel(a.RiskLevel))

			acceptStr := "Nein"
			if a.IsAcceptable {
				acceptStr = "Ja"
			}
			f.SetCellValue(sheet, cellRef("M", row), acceptStr)

			r, g, b := riskLevelColor(a.RiskLevel)
			style, _ := f.NewStyle(&excelize.Style{
				Fill: excelize.Fill{
					Type:    "pattern",
					Pattern: 1,
					Color:   []string{rgbHex(r, g, b)},
				},
				Alignment: &excelize.Alignment{Horizontal: "center"},
			})
			f.SetCellStyle(sheet, cellRef("L", row), cellRef("L", row), style)
		}
	}
}

func (e *DocumentExporter) xlsxMitigations(f *excelize.File, sheet string, mitigations []Mitigation) {
	headerStyle, _ := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{Bold: true, Size: 10, Color: "FFFFFF"},
		Fill: excelize.Fill{Type: "pattern", Pattern: 1, Color: []string{"4472C4"}},
		Alignment: &excelize.Alignment{Horizontal: "center"},
	})

	headers := []string{"Nr", "Name", "Typ", "Beschreibung", "Status", "Verifikationsmethode", "Ergebnis"}
	cols := []string{"A", "B", "C", "D", "E", "F", "G"}

	f.SetColWidth(sheet, "A", "A", 6)
	f.SetColWidth(sheet, "B", "B", 25)
	f.SetColWidth(sheet, "C", "C", 15)
	f.SetColWidth(sheet, "D", "D", 35)
	f.SetColWidth(sheet, "E", "E", 15)
	f.SetColWidth(sheet, "F", "F", 22)
	f.SetColWidth(sheet, "G", "G", 25)

	for i, h := range headers {
		f.SetCellValue(sheet, cellRef(cols[i], 1), h)
	}
	f.SetCellStyle(sheet, "A1", cellRef(cols[len(cols)-1], 1), headerStyle)

	for i, m := range mitigations {
		row := i + 2
		f.SetCellValue(sheet, cellRef("A", row), i+1)
		f.SetCellValue(sheet, cellRef("B", row), m.Name)
		f.SetCellValue(sheet, cellRef("C", row), reductionTypeLabel(m.ReductionType))
		f.SetCellValue(sheet, cellRef("D", row), m.Description)
		f.SetCellValue(sheet, cellRef("E", row), mitigationStatusLabel(m.Status))
		f.SetCellValue(sheet, cellRef("F", row), string(m.VerificationMethod))
		f.SetCellValue(sheet, cellRef("G", row), m.VerificationResult)
	}
}

func (e *DocumentExporter) xlsxRiskMatrix(f *excelize.File, sheet string, assessments []RiskAssessment) {
	headerStyle, _ := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{Bold: true, Size: 10, Color: "FFFFFF"},
		Fill: excelize.Fill{Type: "pattern", Pattern: 1, Color: []string{"4472C4"}},
		Alignment: &excelize.Alignment{Horizontal: "center"},
	})

	f.SetColWidth(sheet, "A", "A", 25)
	f.SetColWidth(sheet, "B", "B", 12)

	f.SetCellValue(sheet, "A1", "Risikostufe")
	f.SetCellValue(sheet, "B1", "Anzahl")
	f.SetCellStyle(sheet, "A1", "B1", headerStyle)

	counts := countByRiskLevel(assessments)

	levels := []RiskLevel{
		RiskLevelNotAcceptable,
		RiskLevelVeryHigh,
		RiskLevelCritical,
		RiskLevelHigh,
		RiskLevelMedium,
		RiskLevelLow,
		RiskLevelNegligible,
	}

	row := 2
	for _, level := range levels {
		count := counts[level]
		f.SetCellValue(sheet, cellRef("A", row), riskLevelLabel(level))
		f.SetCellValue(sheet, cellRef("B", row), count)

		r, g, b := riskLevelColor(level)
		style, _ := f.NewStyle(&excelize.Style{
			Fill: excelize.Fill{
				Type:    "pattern",
				Pattern: 1,
				Color:   []string{rgbHex(r, g, b)},
			},
		})
		f.SetCellStyle(sheet, cellRef("A", row), cellRef("B", row), style)
		row++
	}

	totalStyle, _ := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{Bold: true},
		Fill: excelize.Fill{Type: "pattern", Pattern: 1, Color: []string{"D9E1F2"}},
	})
	f.SetCellValue(sheet, cellRef("A", row), "Gesamt")
	f.SetCellValue(sheet, cellRef("B", row), len(assessments))
	f.SetCellStyle(sheet, cellRef("A", row), cellRef("B", row), totalStyle)
}

func (e *DocumentExporter) xlsxSections(f *excelize.File, sheet string, sections []TechFileSection) {
	headerStyle, _ := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{Bold: true, Size: 10, Color: "FFFFFF"},
		Fill: excelize.Fill{Type: "pattern", Pattern: 1, Color: []string{"4472C4"}},
		Alignment: &excelize.Alignment{Horizontal: "center"},
	})

	f.SetColWidth(sheet, "A", "A", 25)
	f.SetColWidth(sheet, "B", "B", 40)
	f.SetColWidth(sheet, "C", "C", 15)

	headers := []string{"Sektion", "Titel", "Status"}
	cols := []string{"A", "B", "C"}

	for i, h := range headers {
		f.SetCellValue(sheet, cellRef(cols[i], 1), h)
	}
	f.SetCellStyle(sheet, "A1", cellRef(cols[len(cols)-1], 1), headerStyle)

	for i, s := range sections {
		row := i + 2
		f.SetCellValue(sheet, cellRef("A", row), s.SectionType)
		f.SetCellValue(sheet, cellRef("B", row), s.Title)
		f.SetCellValue(sheet, cellRef("C", row), string(s.Status))
	}
}
