package iace

import (
	"archive/zip"
	"bytes"
	"encoding/xml"
	"fmt"
)

// buildAssessmentMap builds a map from hazardID string to the latest RiskAssessment.
func buildAssessmentMap(assessments []RiskAssessment) map[string]*RiskAssessment {
	m := make(map[string]*RiskAssessment)
	for i := range assessments {
		a := &assessments[i]
		key := a.HazardID.String()
		if existing, ok := m[key]; !ok || a.Version > existing.Version {
			m[key] = a
		}
	}
	return m
}

// riskLevelColor returns RGB values for PDF fill color based on risk level.
func riskLevelColor(level RiskLevel) (r, g, b int) {
	switch level {
	case RiskLevelNotAcceptable:
		return 180, 0, 0
	case RiskLevelVeryHigh:
		return 220, 40, 40
	case RiskLevelCritical:
		return 255, 80, 80
	case RiskLevelHigh:
		return 255, 165, 80
	case RiskLevelMedium:
		return 255, 230, 100
	case RiskLevelLow:
		return 180, 230, 140
	case RiskLevelNegligible:
		return 140, 210, 140
	default:
		return 240, 240, 240
	}
}

// riskLevelLabel returns a German display label for a risk level.
func riskLevelLabel(level RiskLevel) string {
	switch level {
	case RiskLevelNotAcceptable:
		return "Nicht akzeptabel"
	case RiskLevelVeryHigh:
		return "Sehr hoch"
	case RiskLevelCritical:
		return "Kritisch"
	case RiskLevelHigh:
		return "Hoch"
	case RiskLevelMedium:
		return "Mittel"
	case RiskLevelLow:
		return "Niedrig"
	case RiskLevelNegligible:
		return "Vernachlaessigbar"
	default:
		return string(level)
	}
}

// reductionTypeLabel returns a German label for a reduction type.
func reductionTypeLabel(rt ReductionType) string {
	switch rt {
	case ReductionTypeDesign:
		return "Konstruktiv"
	case ReductionTypeProtective:
		return "Schutzmassnahme"
	case ReductionTypeInformation:
		return "Information"
	default:
		return string(rt)
	}
}

// mitigationStatusLabel returns a German label for a mitigation status.
func mitigationStatusLabel(status MitigationStatus) string {
	switch status {
	case MitigationStatusPlanned:
		return "Geplant"
	case MitigationStatusImplemented:
		return "Umgesetzt"
	case MitigationStatusVerified:
		return "Verifiziert"
	case MitigationStatusRejected:
		return "Abgelehnt"
	default:
		return string(status)
	}
}

// regulationLabel returns a German label for a regulation type.
func regulationLabel(reg RegulationType) string {
	switch reg {
	case RegulationNIS2:
		return "NIS-2 Richtlinie"
	case RegulationAIAct:
		return "EU AI Act"
	case RegulationCRA:
		return "Cyber Resilience Act"
	case RegulationMachineryRegulation:
		return "EU Maschinenverordnung 2023/1230"
	default:
		return string(reg)
	}
}

// escapeXML escapes special XML characters in text content.
func escapeXML(s string) string {
	var buf bytes.Buffer
	if err := xml.EscapeText(&buf, []byte(s)); err != nil {
		return s
	}
	return buf.String()
}

// countByRiskLevel counts assessments per risk level.
func countByRiskLevel(assessments []RiskAssessment) map[RiskLevel]int {
	counts := make(map[RiskLevel]int)
	for _, a := range assessments {
		counts[a.RiskLevel]++
	}
	return counts
}

// pdfTruncate truncates a string for PDF cell display.
func pdfTruncate(s string, maxLen int) string {
	runes := []rune(s)
	if len(runes) <= maxLen {
		return s
	}
	if maxLen <= 3 {
		return string(runes[:maxLen])
	}
	return string(runes[:maxLen-3]) + "..."
}

// cellRef builds an Excel cell reference like "A1", "B12".
func cellRef(col string, row int) string {
	return fmt.Sprintf("%s%d", col, row)
}

// rgbHex converts RGB values to a hex color string (without #).
func rgbHex(r, g, b int) string {
	return fmt.Sprintf("%02X%02X%02X", r, g, b)
}

// addZipEntry writes a text file into a zip archive.
func addZipEntry(zw *zip.Writer, name, content string) error {
	w, err := zw.Create(name)
	if err != nil {
		return err
	}
	_, err = w.Write([]byte(content))
	return err
}

// docxHeading builds a DOCX paragraph with a heading style.
func docxHeading(text string, level int) string {
	sizes := map[int]int{1: 64, 2: 52, 3: 44}
	sz, ok := sizes[level]
	if !ok {
		sz = 44
	}
	escaped := escapeXML(text)
	return fmt.Sprintf(`    <w:p>
      <w:pPr>
        <w:pStyle w:val="Heading%d"/>
        <w:spacing w:after="200"/>
      </w:pPr>
      <w:r>
        <w:rPr><w:b/><w:sz w:val="%d"/><w:szCs w:val="%d"/></w:rPr>
        <w:t xml:space="preserve">%s</w:t>
      </w:r>
    </w:p>
`, level, sz, sz, escaped)
}

// docxParagraph builds a DOCX paragraph, optionally italic.
func docxParagraph(text string, italic bool) string {
	escaped := escapeXML(text)
	rpr := ""
	if italic {
		rpr = "<w:rPr><w:i/></w:rPr>"
	}
	return fmt.Sprintf(`    <w:p>
      <w:r>
        %s
        <w:t xml:space="preserve">%s</w:t>
      </w:r>
    </w:p>
`, rpr, escaped)
}
