package gap

import (
	"strings"
	"time"
)

// RegulationDeadlines maps regulation IDs to their enforcement deadlines.
var RegulationDeadlines = map[RegulationID]time.Time{
	RegCRA:        time.Date(2027, 6, 1, 0, 0, 0, 0, time.UTC),
	RegAIAct:      time.Date(2025, 8, 1, 0, 0, 0, 0, time.UTC),
	RegDataAct:    time.Date(2025, 9, 12, 0, 0, 0, 0, time.UTC),
	RegNIS2:       time.Date(2025, 10, 18, 0, 0, 0, 0, time.UTC),
	RegDSGVO:      time.Date(2018, 5, 25, 0, 0, 0, 0, time.UTC),
	RegMiCA:       time.Date(2024, 12, 30, 0, 0, 0, 0, time.UTC),
	RegPSD2:       time.Date(2018, 1, 13, 0, 0, 0, 0, time.UTC),
	RegMDR:        time.Date(2021, 5, 26, 0, 0, 0, 0, time.UTC),
	RegMachinery:  time.Date(2027, 1, 20, 0, 0, 0, 0, time.UTC),
	RegEAA:        time.Date(2025, 6, 28, 0, 0, 0, 0, time.UTC),
	RegTDDDG:      time.Date(2021, 12, 1, 0, 0, 0, 0, time.UTC),
	RegLkSG:       time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC),
}

// RegulationNames maps IDs to human-readable names.
var RegulationNames = map[RegulationID]string{
	RegCRA:        "Cyber Resilience Act (CRA)",
	RegAIAct:      "KI-Verordnung (AI Act)",
	RegNIS2:       "NIS2-Richtlinie",
	RegDSGVO:      "DSGVO",
	RegDataAct:    "EU Data Act",
	RegMiCA:       "Markets in Crypto-Assets (MiCA)",
	RegPSD2:       "Zahlungsdiensterichtlinie (PSD2)",
	RegAML:        "Geldwäschegesetz (GwG/AML)",
	RegMDR:        "Medizinprodukteverordnung (MDR)",
	RegMachinery:  "Maschinenverordnung (EU) 2023/1230",
	RegEAA:        "European Accessibility Act",
	RegTDDDG:      "TDDDG (Telemedien-Datenschutz)",
	RegLkSG:       "Lieferkettensorgfaltspflichtengesetz",
}

// Classifier determines which regulations apply to a product profile.
type Classifier struct{}

// NewClassifier creates a Classifier.
func NewClassifier() *Classifier { return &Classifier{} }

// ClassifyAll evaluates all regulations against the product profile.
func (c *Classifier) ClassifyAll(p *ProductProfile) []ApplicableRegulation {
	results := []ApplicableRegulation{
		c.classifyCRA(p),
		c.classifyAIAct(p),
		c.classifyNIS2(p),
		c.classifyDSGVO(p),
		c.classifyDataAct(p),
		c.classifyMiCA(p),
		c.classifyPSD2(p),
		c.classifyAML(p),
		c.classifyMDR(p),
		c.classifyMachinery(p),
		c.classifyTDDDG(p),
		c.classifyLkSG(p),
	}

	// Only return applicable ones
	applicable := make([]ApplicableRegulation, 0, len(results))
	for _, r := range results {
		if r.Applicable {
			applicable = append(applicable, r)
		}
	}
	return applicable
}

// ExtractScopeSignals derives scope signals from the product profile.
func (c *Classifier) ExtractScopeSignals(p *ProductProfile) []string {
	signals := []string{}

	if p.ConnectedToInternet {
		signals = append(signals, "networked_product")
	}
	if p.HasSoftwareUpdates {
		signals = append(signals, "has_software_updates")
	}
	if p.UsesAI {
		signals = append(signals, "uses_ai")
	}
	if p.ProcessesPersonalData {
		signals = append(signals, "processes_personal_data")
	}
	if p.IsCriticalInfraSupplier {
		signals = append(signals, "is_kritis_operator")
	}

	for _, tech := range p.Technologies {
		switch strings.ToLower(tech) {
		case "blockchain", "smart_contract":
			signals = append(signals, "uses_blockchain")
		case "encryption":
			signals = append(signals, "uses_encryption")
		case "api":
			signals = append(signals, "has_public_api")
		case "cloud":
			signals = append(signals, "uses_cloud")
		case "ota_updates":
			signals = append(signals, "has_software_updates")
		}
	}

	for _, dp := range p.DataProcessing {
		switch strings.ToLower(dp) {
		case "health_data":
			signals = append(signals, "processes_health_data")
		case "financial_data":
			signals = append(signals, "processes_financial_data")
		case "personal_data":
			signals = append(signals, "processes_personal_data")
		}
	}

	if p.ProductType == ProductTypeExchange {
		signals = append(signals, "operates_payment_service",
			"holds_client_funds", "uses_blockchain")
	}

	return dedupStrings(signals)
}

// ── Private classification methods ──────────────────────────────────

func (c *Classifier) classifyCRA(p *ProductProfile) ApplicableRegulation {
	r := c.newResult(RegCRA)

	hasDigitalElements := p.ConnectedToInternet || p.HasSoftwareUpdates ||
		containsAny(p.Technologies, "api", "cloud", "ota_updates", "network")

	if !hasDigitalElements {
		r.Reasoning = "Produkt hat keine digitalen Elemente"
		return r
	}

	r.Applicable = true
	r.Confidence = 0.9

	if containsAny(p.Technologies, "ota_updates") && p.ConnectedToInternet {
		r.RiskLevel = "high"
		r.Reasoning = "Vernetztes Produkt mit Software-Updates → CRA Class I/II"
		r.Requirements = []string{
			"Schwachstellenmanagement (Art. 10)",
			"SBOM erstellen (Anhang I, Teil II)",
			"Security Updates bereitstellen (Art. 13)",
			"Meldepflicht bei Schwachstellen (Art. 11)",
			"Konformitätsbewertung (Art. 24-28)",
		}
	} else {
		r.RiskLevel = "medium"
		r.Reasoning = "Produkt mit digitalen Elementen → CRA Default-Kategorie"
		r.Requirements = []string{
			"Cybersicherheitsanforderungen (Anhang I)",
			"Technische Dokumentation (Anhang V)",
		}
	}
	return r
}

func (c *Classifier) classifyAIAct(p *ProductProfile) ApplicableRegulation {
	r := c.newResult(RegAIAct)
	if !p.UsesAI && !containsAny(p.Technologies, "ai", "machine_learning", "neural_network") {
		r.Reasoning = "Produkt verwendet keine KI"
		return r
	}

	r.Applicable = true
	isSafetyRelevant := p.ProductType == ProductTypeMachinery ||
		p.ProductType == ProductTypeMedicalDevice ||
		containsAny(p.DataProcessing, "health_data")

	if isSafetyRelevant {
		r.RiskLevel = "high"
		r.Confidence = 0.9
		r.Reasoning = "KI in sicherheitsrelevantem Produkt → Hochrisiko-KI"
		r.Requirements = []string{
			"Risikomanagement (Art. 9)",
			"Datenqualität (Art. 10)",
			"Technische Dokumentation (Art. 11)",
			"Aufzeichnungspflichten (Art. 12)",
			"Transparenz (Art. 13)",
			"Menschliche Aufsicht (Art. 14)",
			"Genauigkeit und Robustheit (Art. 15)",
			"FRIA — Grundrechte-Folgenabschätzung",
		}
	} else {
		r.RiskLevel = "medium"
		r.Confidence = 0.8
		r.Reasoning = "KI-System → Transparenzpflichten (Limited Risk)"
		r.Requirements = []string{
			"Transparenzpflicht (Art. 52)",
			"KI-Kennzeichnung",
		}
	}
	return r
}

func (c *Classifier) classifyNIS2(p *ProductProfile) ApplicableRegulation {
	r := c.newResult(RegNIS2)

	isDirectlyAffected := p.IsCriticalInfraSupplier ||
		p.ProductType == ProductTypeExchange ||
		containsAny(p.DataProcessing, "financial_data")

	isSupplyChain := p.ConnectedToInternet && (p.ProductType == ProductTypeSaaS ||
		p.ProductType == ProductTypeIoT)

	if !isDirectlyAffected && !isSupplyChain {
		r.Reasoning = "Kein KRITIS-Betreiber oder -Zulieferer"
		return r
	}

	r.Applicable = true
	if isDirectlyAffected {
		r.RiskLevel = "high"
		r.Confidence = 0.85
		r.Reasoning = "Direkt betroffen als KRITIS-Betreiber/Finanzdienstleister"
	} else {
		r.RiskLevel = "medium"
		r.Confidence = 0.7
		r.Reasoning = "Indirekt betroffen als Zulieferer vernetzter Dienste"
	}
	r.Requirements = []string{
		"Cybersicherheits-Risikomanagement (Art. 21)",
		"Meldepflichten (Art. 23)",
		"Supply-Chain-Sicherheit",
		"Incident Response",
	}
	return r
}

func (c *Classifier) classifyDSGVO(p *ProductProfile) ApplicableRegulation {
	r := c.newResult(RegDSGVO)
	if !p.ProcessesPersonalData && !containsAny(p.DataProcessing, "personal_data", "health_data") {
		r.Reasoning = "Keine Verarbeitung personenbezogener Daten"
		return r
	}
	r.Applicable = true
	r.RiskLevel = "high"
	r.Confidence = 0.95
	r.Reasoning = "Verarbeitung personenbezogener Daten → DSGVO anwendbar"
	r.Requirements = []string{
		"Rechtsgrundlage (Art. 6)",
		"Informationspflichten (Art. 13/14)",
		"Betroffenenrechte (Art. 15-22)",
		"Verarbeitungsverzeichnis (Art. 30)",
		"TOM (Art. 32)",
	}
	if containsAny(p.DataProcessing, "health_data") {
		r.Requirements = append(r.Requirements, "DSFA (Art. 35)", "Besondere Kategorien (Art. 9)")
	}
	return r
}

func (c *Classifier) classifyDataAct(p *ProductProfile) ApplicableRegulation {
	r := c.newResult(RegDataAct)
	isConnectedProduct := p.ConnectedToInternet && (p.ProductType == ProductTypeIoT ||
		p.ProductType == ProductTypeHardware || p.ProductType == ProductTypeMachinery)
	if !isConnectedProduct {
		r.Reasoning = "Kein vernetztes Produkt mit Datengenerierung"
		return r
	}
	r.Applicable = true
	r.RiskLevel = "medium"
	r.Confidence = 0.8
	r.Reasoning = "Vernetztes Produkt generiert Nutzungsdaten → Data Act anwendbar"
	r.Requirements = []string{
		"Nutzerdatenzugang (Art. 3-5)",
		"Datenweitergabe an Dritte (Art. 5)",
		"Beschränkung der Datennutzung (Art. 6)",
	}
	return r
}

func (c *Classifier) classifyMiCA(p *ProductProfile) ApplicableRegulation {
	r := c.newResult(RegMiCA)
	if p.ProductType != ProductTypeExchange &&
		!containsAny(p.Technologies, "blockchain", "smart_contract", "crypto") {
		r.Reasoning = "Kein Kryptowerte-Bezug"
		return r
	}
	r.Applicable = true
	r.RiskLevel = "high"
	r.Confidence = 0.9
	r.Reasoning = "Kryptowerte-Dienstleistung → MiCA anwendbar"
	r.Requirements = []string{
		"CASP-Zulassung (Art. 59-63)",
		"Eigenmittelanforderungen (Art. 67)",
		"Organisatorische Anforderungen (Art. 68)",
		"Custody-Trennung (Art. 70)",
		"Marktmissbrauchsvorschriften (Art. 86-92)",
	}
	return r
}

func (c *Classifier) classifyPSD2(p *ProductProfile) ApplicableRegulation {
	r := c.newResult(RegPSD2)
	if p.ProductType != ProductTypeExchange &&
		!containsAny(p.Technologies, "payment", "fiat_gateway") &&
		!containsAny(p.DataProcessing, "financial_data") {
		r.Reasoning = "Kein Zahlungsdienstbezug"
		return r
	}
	r.Applicable = true
	r.RiskLevel = "high"
	r.Confidence = 0.85
	r.Reasoning = "Zahlungsdienste oder Fiat-Gateway → PSD2 anwendbar"
	r.Requirements = []string{
		"Starke Kundenauthentifizierung (Art. 97)",
		"Sicherheit der Kommunikation (Art. 98)",
		"Open Banking API (Art. 36)",
	}
	return r
}

func (c *Classifier) classifyAML(p *ProductProfile) ApplicableRegulation {
	r := c.newResult(RegAML)
	if p.ProductType != ProductTypeExchange &&
		!containsAny(p.DataProcessing, "financial_data") {
		r.Reasoning = "Kein Verpflichteter nach GwG"
		return r
	}
	r.Applicable = true
	r.RiskLevel = "high"
	r.Confidence = 0.9
	r.Reasoning = "Finanzdienstleistung → AML/GwG anwendbar"
	r.Requirements = []string{
		"KYC-Verfahren (§10 GwG)",
		"Transaktionsmonitoring",
		"Verdachtsmeldung (§43 GwG)",
		"PEP-Prüfung",
	}
	return r
}

func (c *Classifier) classifyMDR(p *ProductProfile) ApplicableRegulation {
	r := c.newResult(RegMDR)
	if p.ProductType != ProductTypeMedicalDevice {
		r.Reasoning = "Kein Medizinprodukt"
		return r
	}
	r.Applicable = true
	r.RiskLevel = "high"
	r.Confidence = 0.9
	r.Reasoning = "Medizinprodukt → MDR anwendbar"
	r.Requirements = []string{
		"Konformitätsbewertung",
		"Klinische Bewertung (Art. 61)",
		"Post-Market Surveillance (Art. 83-86)",
		"UDI (Art. 27)",
	}
	return r
}

func (c *Classifier) classifyMachinery(p *ProductProfile) ApplicableRegulation {
	r := c.newResult(RegMachinery)
	if p.ProductType != ProductTypeMachinery && p.ProductType != ProductTypeHardware {
		r.Reasoning = "Kein Maschinenprodukt"
		return r
	}
	r.Applicable = true
	r.RiskLevel = "high"
	r.Confidence = 0.85
	r.Reasoning = "Maschinenprodukt → Maschinenverordnung anwendbar"
	r.Requirements = []string{
		"CE-Konformitätsbewertung",
		"Risikobeurteilung (Anhang III)",
		"Betriebsanleitung",
		"Technische Dokumentation",
	}
	return r
}

func (c *Classifier) classifyTDDDG(p *ProductProfile) ApplicableRegulation {
	r := c.newResult(RegTDDDG)
	hasTelemedien := p.ProductType == ProductTypeSaaS ||
		(p.ConnectedToInternet && containsAny(p.Technologies, "api", "cloud"))
	if !hasTelemedien {
		r.Reasoning = "Kein Telemediendienst"
		return r
	}
	r.Applicable = true
	r.RiskLevel = "medium"
	r.Confidence = 0.8
	r.Reasoning = "Online-Dienst → TDDDG anwendbar"
	r.Requirements = []string{
		"Cookie-Einwilligung (§25 TDDDG)",
		"Impressumspflicht",
	}
	return r
}

func (c *Classifier) classifyLkSG(p *ProductProfile) ApplicableRegulation {
	r := c.newResult(RegLkSG)
	// LkSG applies to companies with >1000 employees — we can't determine this
	// from product profile alone. Flag as "unclear" for larger companies.
	r.Reasoning = "LkSG-Anwendbarkeit hängt von Unternehmensgröße ab (>1000 MA)"
	return r
}

// ── Helpers ─────────────────────────────────────────────────────────

func (c *Classifier) newResult(id RegulationID) ApplicableRegulation {
	r := ApplicableRegulation{
		ID:         id,
		Name:       RegulationNames[id],
		Applicable: false,
		Confidence: 0,
	}
	if dl, ok := RegulationDeadlines[id]; ok {
		r.Deadline = &dl
	}
	return r
}

func containsAny(slice []string, values ...string) bool {
	for _, s := range slice {
		for _, v := range values {
			if strings.EqualFold(s, v) {
				return true
			}
		}
	}
	return false
}

func dedupStrings(in []string) []string {
	seen := make(map[string]bool, len(in))
	out := make([]string, 0, len(in))
	for _, s := range in {
		if !seen[s] {
			seen[s] = true
			out = append(out, s)
		}
	}
	return out
}
