package iace

import (
	"strings"
	"testing"
)

// TestGTBremse_PinnedHazardToMeasureMappings is a regression net for the IACE
// benchmark fix. Each pinned (GT-Nr, hazard pattern, measure) triple was
// validated by an expert review on 2026-05 against testdata/ground_truth_bremse.json.
// If any pattern stops referencing the listed measures, this test fails — so the
// underlying GT scenario is no longer answered with the Fachmann-grade mitigation.
//
// Adding new entries here pins the Engine's answer for a specific GT scenario.
// Removing entries means the GT scenario is no longer covered with the same
// concrete measure (e.g. because the library was reorganized) — that needs an
// active decision, not a silent drift.
func TestGTBremse_PinnedHazardToMeasureMappings(t *testing.T) {
	cases := []struct {
		gtNr           string
		patternID      string
		requiredMeasures []string
	}{
		// GT 2.1/2.2: Elektrischer Schlag durch direktes Beruehren
		// Expert demand: konkrete Isolation MOhm + IP2X Einhausung
		{"2.1/2.2", "HP1640", []string{"M481", "M482"}},
		// GT 2.4: Schutzleiterfehler (>10 mA Ableitstroeme)
		// Expert demand: mech. Schutz + 10mm²-Cu + Ueberwachung + durchgehende Verbindung
		{"2.4", "HP1641", []string{"M511", "M512", "M514", "M515"}},
		// GT 2.5: Indirektes Beruehren — Schutzleiter durchgaengig + SK II / Kleinspannung
		{"2.5", "HP1685", []string{"M511", "M512", "M515", "M516"}},
		// GT 2.7: RCD an Steckdosenkreisen
		{"2.7", "HP1689", []string{"M518"}},
		// GT 2.12: Potentialausgleich zwischen Anlagenteilen
		{"2.12", "HP1688", []string{"M475", "M477"}},
		// GT 1.3: Pneumatik-Komponenten + Schlauchsicherung
		{"1.3", "HP1630", []string{"M483", "M484", "M485"}},
		// GT 1.5: Pneumatik-Restenergie nach Abschaltung
		{"1.5", "HP1717", []string{"M485", "M534"}},
		// GT 1.7: Teach-Modus mit Schluesselschalter + 250 mm/s + Zustimmtaster
		{"1.7", "HP1605", []string{"M491", "M492", "M493"}},
		// GT 1.8: Sicher begrenzter Bewegungsbereich + Zaun-Lastbemessung
		{"1.8", "HP1604", []string{"M494", "M501"}},
		// GT 1.10/1.18: Reach-over Sicherheitsabstand
		{"1.10/1.18", "HP1602", []string{"M495", "M486"}},
		// GT 1.11: Foerderband-Geometrie (Abstand + Oeffnungsgroesse)
		{"1.11", "HP1621", []string{"M496", "M497", "M498"}},
		// GT 1.22: Greifer-Versagen + Werkstueck weggeschleudert
		{"1.22", "HP1711", []string{"M501", "M502", "M536"}},
		// GT 1.24: Eingeschlossen in Zelle — Innenoeffnung + bewusster Wiederanlauf
		{"1.24", "HP1603", []string{"M489", "M488"}},
		// GT 1.12/1.24 (HP1651 Wiederanlauf-Variante): Wiederanlauf-Schutz-Measures —
		// NOT thermal (M054 was wrongly placed here and surfaced as
		// "Sichere thermische Auslegung" for a restart hazard)
		{"1.12/1.24", "HP1651", []string{"M488", "M487", "M489", "M490"}},
		// GT 1.1 (HP1625 sharp edges): edge-specific only, no rotational/distance fillers
		{"1.1", "HP1625", []string{"M003", "M004", "M027"}},
		// GT 1.26: Foerderband-Geschwindigkeit < 100 mm/s
		{"1.26", "HP1620", []string{"M498", "M499"}},
		// GT 1.27: Mechanischer Anschlag am Bandende
		{"1.27", "HP1622", []string{"M500"}},
		// GT 1.30: Druckluft-Reinigungsduese
		{"1.30", "HP1712", []string{"M504", "M505"}},
		// GT 1.32: WZM-Beladetuer + zweikanaliger Tuerschalter
		{"1.32", "HP1634", []string{}}, // skipped: HP1634 already had M061; verify exists
		// GT 1.34/2.10: KSS-Druckschlauch
		{"1.34/2.10", "HP1675", []string{"M484", "M483"}},
		// GT 1.38/1.39: KSS-Auslauf unten + Druck begrenzt
		{"1.38/1.39", "HP1703", []string{"M505", "M506", "M526"}},
		// GT 2.9: Wasser/Reinigung Schaltschrank
		{"2.9", "HP1716", []string{"M521", "M522", "M539"}},
		// GT 7.1: KSS-Hautkontakt
		{"7.1", "HP1715", []string{"M408", "M533"}},
		// GT 8.1: Manuelle Werkstueck-Handhabung + Hebehilfe >25kg
		{"8.1", "HP1713", []string{"M530", "M532"}},
		// GT 8.2: Bedienelement-Position ergonomisch
		{"8.2", "HP1714", []string{"M531"}},
	}

	patterns := collectAllPatterns()
	measureByID := make(map[string]ProtectiveMeasureEntry)
	for _, m := range GetProtectiveMeasureLibrary() {
		measureByID[m.ID] = m
	}
	patternByID := make(map[string]HazardPattern)
	for _, p := range patterns {
		patternByID[p.ID] = p
	}

	for _, c := range cases {
		t.Run(c.gtNr+"_"+c.patternID, func(t *testing.T) {
			p, ok := patternByID[c.patternID]
			if !ok {
				t.Fatalf("pattern %s missing — GT %s no longer covered", c.patternID, c.gtNr)
			}
			suggested := make(map[string]bool)
			for _, m := range p.SuggestedMeasureIDs {
				suggested[m] = true
			}
			for _, req := range c.requiredMeasures {
				if _, exists := measureByID[req]; !exists {
					t.Errorf("required measure %s referenced by GT %s does not exist in library", req, c.gtNr)
					continue
				}
				if !suggested[req] {
					t.Errorf("pattern %s no longer suggests %s — GT %s expert mitigation lost (current: %v)",
						c.patternID, req, c.gtNr, p.SuggestedMeasureIDs)
				}
			}
		})
	}
}

// TestGTBremse_ExpertMeasuresAllResolvable pins the static-text expectation
// that every Fachmann measure newly added during the 2026-05 GT coverage work
// (M481-M482, M483-M539) carries the concrete EN/IEC/ISO/DGUV norm reference
// that the expert cited in the GT file. A measure without a concrete norm
// reference is a regression — generic "Sichere X" entries were exactly the
// problem this work was meant to fix.
func TestGTBremse_ExpertMeasuresAllResolvable(t *testing.T) {
	expertIDs := []string{
		"M481", "M482", "M483", "M484", "M485", "M486", "M487", "M488", "M489", "M490",
		"M491", "M492", "M493", "M494", "M495", "M496", "M497", "M498", "M499", "M500",
		"M501", "M502", "M503", "M504", "M505", "M506", "M507", "M508", "M509", "M510",
		"M511", "M512", "M513", "M514", "M515", "M516", "M517", "M518", "M519", "M520",
		"M521", "M522", "M523", "M524", "M525", "M526", "M527", "M528", "M529", "M530",
		"M531", "M532", "M533", "M534", "M535", "M536", "M537", "M538", "M539",
	}
	measureByID := make(map[string]ProtectiveMeasureEntry)
	for _, m := range GetProtectiveMeasureLibrary() {
		measureByID[m.ID] = m
	}
	knownPrefixes := []string{"EN ", "IEC ", "ISO ", "DIN ", "TRBS", "TRGS", "ASR ", "DGUV", "OSHA", "VDE", "EN ISO", "DIN EN"}
	for _, id := range expertIDs {
		m, ok := measureByID[id]
		if !ok {
			t.Errorf("expert measure %s missing from library", id)
			continue
		}
		if len(m.NormReferences) == 0 {
			t.Errorf("measure %s (%q) has no NormReferences — concrete norm anchor missing", id, m.Name)
			continue
		}
		found := false
		for _, nr := range m.NormReferences {
			for _, p := range knownPrefixes {
				if strings.HasPrefix(nr, p) {
					found = true
					break
				}
			}
			if found {
				break
			}
		}
		if !found {
			t.Errorf("measure %s (%q) NormReferences %v contain no recognized norm prefix",
				id, m.Name, m.NormReferences)
		}
	}
}
