package ucca

// ============================================================================
// NIS2 Module
// ============================================================================
//
// This module implements the NIS2 directive (EU 2022/2555) and the German
// implementation (BSIG-E - BSI-Gesetz Entwurf).
//
// NIS2 applies to:
// - Essential Entities (besonders wichtige Einrichtungen): Large enterprises in Annex I sectors
// - Important Entities (wichtige Einrichtungen): Medium enterprises in Annex I/II sectors
//
// Split into:
//   - nis2_module.go      — struct, sector maps, classification, derive methods, decision tree
//   - nis2_yaml.go        — YAML loading and conversion helpers
//   - nis2_obligations.go — hardcoded fallback obligations/controls/deadlines
//
// ============================================================================

// NIS2Module implements the RegulationModule interface for NIS2
type NIS2Module struct {
	obligations       []Obligation
	controls          []ObligationControl
	incidentDeadlines []IncidentDeadline
	decisionTree      *DecisionTree
	loaded            bool
}

var (
	// NIS2AnnexISectors contains Sectors of High Criticality
	NIS2AnnexISectors = map[string]bool{
		"energy":                 true,
		"transport":              true,
		"banking_financial":      true,
		"financial_market":       true,
		"health":                 true,
		"drinking_water":         true,
		"wastewater":             true,
		"digital_infrastructure": true,
		"ict_service_mgmt":       true,
		"public_administration":  true,
		"space":                  true,
	}

	// NIS2AnnexIISectors contains Other Critical Sectors
	NIS2AnnexIISectors = map[string]bool{
		"postal":            true,
		"waste":             true,
		"chemicals":         true,
		"food":              true,
		"manufacturing":     true,
		"digital_providers": true,
		"research":          true,
	}

	// NIS2SpecialServices are always in scope regardless of size
	NIS2SpecialServices = map[string]bool{
		"dns":              true,
		"tld":              true,
		"cloud":            true,
		"datacenter":       true,
		"cdn":              true,
		"trust_service":    true,
		"public_network":   true,
		"electronic_comms": true,
		"msp":              true,
		"mssp":             true,
	}
)

// NewNIS2Module creates a new NIS2 module, loading obligations from YAML
func NewNIS2Module() (*NIS2Module, error) {
	m := &NIS2Module{
		obligations:       []Obligation{},
		controls:          []ObligationControl{},
		incidentDeadlines: []IncidentDeadline{},
	}

	if err := m.loadFromYAML(); err != nil {
		m.loadHardcodedObligations()
	}

	m.buildDecisionTree()
	m.loaded = true

	return m, nil
}

// ID returns the module identifier
func (m *NIS2Module) ID() string { return "nis2" }

// Name returns the human-readable name
func (m *NIS2Module) Name() string { return "NIS2-Richtlinie / BSIG-E" }

// Description returns a brief description
func (m *NIS2Module) Description() string {
	return "EU-Richtlinie über Maßnahmen für ein hohes gemeinsames Cybersicherheitsniveau (NIS2) und deutsche Umsetzung (BSIG-E)"
}

// IsApplicable checks if NIS2 applies to the organization
func (m *NIS2Module) IsApplicable(facts *UnifiedFacts) bool {
	return m.Classify(facts) != NIS2NotAffected
}

// GetClassification returns the NIS2 classification as string
func (m *NIS2Module) GetClassification(facts *UnifiedFacts) string {
	return string(m.Classify(facts))
}

// Classify determines the NIS2 classification for an organization
func (m *NIS2Module) Classify(facts *UnifiedFacts) NIS2Classification {
	if m.hasSpecialService(facts) {
		return NIS2EssentialEntity
	}

	inAnnexI := NIS2AnnexISectors[facts.Sector.PrimarySector]
	inAnnexII := NIS2AnnexIISectors[facts.Sector.PrimarySector]

	if !inAnnexI && !inAnnexII {
		return NIS2NotAffected
	}

	meetsSize := facts.Organization.MeetsNIS2SizeThreshold()
	isLarge := facts.Organization.MeetsNIS2LargeThreshold()

	if !meetsSize {
		if facts.Sector.IsKRITIS && facts.Sector.KRITISThresholdMet {
			return NIS2EssentialEntity
		}
		return NIS2NotAffected
	}

	if inAnnexI {
		if isLarge {
			return NIS2EssentialEntity
		}
		return NIS2ImportantEntity
	}

	if inAnnexII {
		return NIS2ImportantEntity
	}

	return NIS2NotAffected
}

func (m *NIS2Module) hasSpecialService(facts *UnifiedFacts) bool {
	for _, service := range facts.Sector.SpecialServices {
		if NIS2SpecialServices[service] {
			return true
		}
	}
	return false
}

// DeriveObligations derives all applicable NIS2 obligations
func (m *NIS2Module) DeriveObligations(facts *UnifiedFacts) []Obligation {
	classification := m.Classify(facts)
	if classification == NIS2NotAffected {
		return []Obligation{}
	}

	var result []Obligation
	for _, obl := range m.obligations {
		if m.obligationApplies(obl, classification, facts) {
			customized := obl
			customized.RegulationID = m.ID()
			result = append(result, customized)
		}
	}

	return result
}

func (m *NIS2Module) obligationApplies(obl Obligation, classification NIS2Classification, _ *UnifiedFacts) bool {
	switch obl.AppliesWhen {
	case "classification == 'besonders_wichtige_einrichtung'":
		return classification == NIS2EssentialEntity
	case "classification == 'wichtige_einrichtung'":
		return classification == NIS2ImportantEntity
	case "classification in ['wichtige_einrichtung', 'besonders_wichtige_einrichtung']":
		return classification == NIS2EssentialEntity || classification == NIS2ImportantEntity
	case "classification != 'nicht_betroffen'":
		return classification != NIS2NotAffected
	case "":
		return classification != NIS2NotAffected
	default:
		return classification != NIS2NotAffected
	}
}

// DeriveControls derives all applicable NIS2 controls
func (m *NIS2Module) DeriveControls(facts *UnifiedFacts) []ObligationControl {
	classification := m.Classify(facts)
	if classification == NIS2NotAffected {
		return []ObligationControl{}
	}

	var result []ObligationControl
	for _, ctrl := range m.controls {
		ctrl.RegulationID = m.ID()
		result = append(result, ctrl)
	}

	return result
}

// GetDecisionTree returns the NIS2 applicability decision tree
func (m *NIS2Module) GetDecisionTree() *DecisionTree { return m.decisionTree }

// GetIncidentDeadlines returns NIS2 incident reporting deadlines
func (m *NIS2Module) GetIncidentDeadlines(facts *UnifiedFacts) []IncidentDeadline {
	if m.Classify(facts) == NIS2NotAffected {
		return []IncidentDeadline{}
	}
	return m.incidentDeadlines
}

func (m *NIS2Module) buildDecisionTree() {
	m.decisionTree = &DecisionTree{
		ID:   "nis2_applicability",
		Name: "NIS2 Anwendbarkeits-Entscheidungsbaum",
		RootNode: &DecisionNode{
			ID:       "root",
			Question: "Erbringt Ihr Unternehmen spezielle digitale Dienste (DNS, TLD, Cloud, Rechenzentrum, CDN, MSP, MSSP, Vertrauensdienste)?",
			YesNode: &DecisionNode{
				ID:          "special_services",
				Result:      string(NIS2EssentialEntity),
				Explanation: "Anbieter spezieller digitaler Dienste sind unabhängig von der Größe als besonders wichtige Einrichtungen einzustufen.",
			},
			NoNode: &DecisionNode{
				ID:       "sector_check",
				Question: "Ist Ihr Unternehmen in einem der NIS2-Sektoren tätig (Energie, Verkehr, Gesundheit, Digitale Infrastruktur, Öffentliche Verwaltung, Finanzwesen, etc.)?",
				YesNode: &DecisionNode{
					ID:       "size_check",
					Question: "Hat Ihr Unternehmen mindestens 50 Mitarbeiter ODER mindestens 10 Mio. EUR Jahresumsatz UND Bilanzsumme?",
					YesNode: &DecisionNode{
						ID:       "annex_check",
						Question: "Ist Ihr Sektor in Anhang I der NIS2 (hohe Kritikalität: Energie, Verkehr, Gesundheit, Trinkwasser, Digitale Infrastruktur, Bankwesen, Öffentliche Verwaltung, Weltraum)?",
						YesNode: &DecisionNode{
							ID:       "large_check_annex1",
							Question: "Hat Ihr Unternehmen mindestens 250 Mitarbeiter ODER mindestens 50 Mio. EUR Jahresumsatz?",
							YesNode: &DecisionNode{
								ID:          "essential_annex1",
								Result:      string(NIS2EssentialEntity),
								Explanation: "Großes Unternehmen in Anhang I Sektor = Besonders wichtige Einrichtung",
							},
							NoNode: &DecisionNode{
								ID:          "important_annex1",
								Result:      string(NIS2ImportantEntity),
								Explanation: "Mittleres Unternehmen in Anhang I Sektor = Wichtige Einrichtung",
							},
						},
						NoNode: &DecisionNode{
							ID:          "important_annex2",
							Result:      string(NIS2ImportantEntity),
							Explanation: "Unternehmen in Anhang II Sektor = Wichtige Einrichtung",
						},
					},
					NoNode: &DecisionNode{
						ID:       "kritis_check",
						Question: "Ist Ihr Unternehmen als KRITIS-Betreiber eingestuft?",
						YesNode: &DecisionNode{
							ID:          "kritis_essential",
							Result:      string(NIS2EssentialEntity),
							Explanation: "KRITIS-Betreiber sind unabhängig von der Größe als besonders wichtige Einrichtungen einzustufen.",
						},
						NoNode: &DecisionNode{
							ID:          "too_small",
							Result:      string(NIS2NotAffected),
							Explanation: "Unternehmen unterhalb der Größenschwelle ohne KRITIS-Status sind nicht von NIS2 betroffen.",
						},
					},
				},
				NoNode: &DecisionNode{
					ID:          "not_in_sector",
					Result:      string(NIS2NotAffected),
					Explanation: "Unternehmen außerhalb der NIS2-Sektoren sind nicht betroffen.",
				},
			},
		},
	}
}
