package iace

// TagResolver resolves component/energy IDs to tags and finds matching
// hazards, measures, and evidence by tag intersection.
type TagResolver struct {
	componentIndex map[string]ComponentLibraryEntry
	energyIndex    map[string]EnergySourceEntry
}

// NewTagResolver creates a TagResolver pre-indexed from the built-in libraries.
func NewTagResolver() *TagResolver {
	tr := &TagResolver{
		componentIndex: make(map[string]ComponentLibraryEntry),
		energyIndex:    make(map[string]EnergySourceEntry),
	}
	for _, c := range GetComponentLibrary() {
		tr.componentIndex[c.ID] = c
	}
	for _, e := range GetEnergySources() {
		tr.energyIndex[e.ID] = e
	}
	return tr
}

// ResolveComponentTags resolves component library IDs to their combined tag set.
func (tr *TagResolver) ResolveComponentTags(componentIDs []string) []string {
	seen := make(map[string]bool)
	var tags []string
	for _, id := range componentIDs {
		comp, ok := tr.componentIndex[id]
		if !ok {
			continue
		}
		for _, tag := range comp.Tags {
			if !seen[tag] {
				seen[tag] = true
				tags = append(tags, tag)
			}
		}
	}
	return tags
}

// ResolveEnergyTags resolves energy source IDs to their combined tag set.
func (tr *TagResolver) ResolveEnergyTags(energyIDs []string) []string {
	seen := make(map[string]bool)
	var tags []string
	for _, id := range energyIDs {
		src, ok := tr.energyIndex[id]
		if !ok {
			continue
		}
		for _, tag := range src.Tags {
			if !seen[tag] {
				seen[tag] = true
				tags = append(tags, tag)
			}
		}
	}
	return tags
}

// tagSynonyms maps short pattern-side tag names to the canonical
// library-side tags. The library uses descriptive identifiers
// ("electrical_energy") while many patterns were authored with short
// forms ("electrical"). Without this map, the pattern's RequiredTag
// "electrical" never matches a real component's "electrical_energy",
// and the entire pattern silently never fires. The audit (Method A)
// surfaced ~40 such ghost-patterns.
//
// Each entry expands the parser's tag set when a known synonym appears,
// so both forms work for matching. This is the least-invasive fix —
// no pattern bodies are touched. The long-term goal is to converge
// on a single canonical vocabulary; until then the map documents which
// pairs are considered equivalent.
var tagSynonyms = map[string][]string{
	"electrical_energy":   {"electrical"},
	"pneumatic_pressure":  {"pneumatic"},
	"hydraulic_pressure":  {"hydraulic"},
	"electrical":          {"electrical_energy"},
	"pneumatic":           {"pneumatic_pressure"},
	"hydraulic":           {"hydraulic_pressure"},
}

// ResolveTags combines component, energy, and custom tags into a unified set,
// applying the synonym map so patterns authored with either tag form match.
func (tr *TagResolver) ResolveTags(componentIDs, energyIDs, customTags []string) []string {
	seen := make(map[string]bool)
	var all []string

	add := func(tags []string) {
		for _, t := range tags {
			if !seen[t] {
				seen[t] = true
				all = append(all, t)
			}
			for _, syn := range tagSynonyms[t] {
				if !seen[syn] {
					seen[syn] = true
					all = append(all, syn)
				}
			}
		}
	}

	add(tr.ResolveComponentTags(componentIDs))
	add(tr.ResolveEnergyTags(energyIDs))
	// Expand declared components to their typical energy sources: naming a
	// component (e.g. an electric motor) implies its energy capability even
	// when no energy source was declared separately. This makes structured
	// (component-picker) projects as complete as narrative ones. Domain leakage
	// stays blocked — cross-domain patterns gate on dom_* tags, not energy.
	var compEnergyIDs []string
	for _, id := range componentIDs {
		if c, ok := tr.componentIndex[id]; ok {
			compEnergyIDs = append(compEnergyIDs, c.TypicalEnergySources...)
		}
	}
	add(tr.ResolveEnergyTags(compEnergyIDs))
	add(customTags)
	return all
}

// FindHazardsByTags returns hazard library entries that have any matching tag.
func (tr *TagResolver) FindHazardsByTags(tags []string) []HazardLibraryEntry {
	tagSet := toSet(tags)
	var matched []HazardLibraryEntry
	for _, h := range GetBuiltinHazardLibrary() {
		if h.Tags == nil {
			continue
		}
		for _, t := range h.Tags {
			if tagSet[t] {
				matched = append(matched, h)
				break
			}
		}
	}
	return matched
}

// FindMeasuresByTags returns protective measure entries that have any matching tag.
func (tr *TagResolver) FindMeasuresByTags(tags []string) []ProtectiveMeasureEntry {
	tagSet := toSet(tags)
	var matched []ProtectiveMeasureEntry
	for _, m := range GetProtectiveMeasureLibrary() {
		if m.Tags == nil {
			continue
		}
		for _, t := range m.Tags {
			if tagSet[t] {
				matched = append(matched, m)
				break
			}
		}
	}
	return matched
}

// FindEvidenceByTags returns evidence type entries that have any matching tag.
func (tr *TagResolver) FindEvidenceByTags(tags []string) []EvidenceTypeInfo {
	tagSet := toSet(tags)
	var matched []EvidenceTypeInfo
	for _, e := range GetEvidenceTypeLibrary() {
		for _, t := range e.Tags {
			if tagSet[t] {
				matched = append(matched, e)
				break
			}
		}
	}
	return matched
}

// toSet converts a string slice to a map for O(1) lookup.
func toSet(s []string) map[string]bool {
	m := make(map[string]bool, len(s))
	for _, v := range s {
		m[v] = true
	}
	return m
}

// GetEvidenceTypeLibrary returns built-in evidence types with tags for tag resolution.
func GetEvidenceTypeLibrary() []EvidenceTypeInfo {
	return []EvidenceTypeInfo{
		{ID: "E01", Category: "design", LabelDE: "Risikobeurteilung", LabelEN: "Risk Assessment Document", Tags: []string{"design_evidence"}, Sort: 1},
		{ID: "E02", Category: "design", LabelDE: "FMEA-Dokument", LabelEN: "FMEA Document", Tags: []string{"design_evidence", "analysis_evidence"}, Sort: 2},
		{ID: "E03", Category: "design", LabelDE: "Sicherheitskonzept", LabelEN: "Safety Concept", Tags: []string{"design_evidence"}, Sort: 3},
		{ID: "E04", Category: "design", LabelDE: "Schaltplan", LabelEN: "Circuit Diagram", Tags: []string{"design_evidence"}, Sort: 4},
		{ID: "E05", Category: "design", LabelDE: "Hydraulikschaltplan", LabelEN: "Hydraulic Diagram", Tags: []string{"design_evidence"}, Sort: 5},
		{ID: "E06", Category: "design", LabelDE: "Pneumatikschaltplan", LabelEN: "Pneumatic Diagram", Tags: []string{"design_evidence"}, Sort: 6},
		{ID: "E07", Category: "design", LabelDE: "SIL/PL-Berechnung", LabelEN: "SIL/PL Calculation", Tags: []string{"design_evidence", "analysis_evidence"}, Sort: 7},
		{ID: "E08", Category: "test", LabelDE: "Funktionspruefung Schutzeinrichtung", LabelEN: "Guard Function Test", Tags: []string{"test_evidence", "guard_measure"}, Sort: 8},
		{ID: "E09", Category: "test", LabelDE: "Not-Halt-Test", LabelEN: "Emergency Stop Test", Tags: []string{"test_evidence"}, Sort: 9},
		{ID: "E10", Category: "test", LabelDE: "Elektrische Sicherheitspruefung", LabelEN: "Electrical Safety Test", Tags: []string{"test_evidence"}, Sort: 10},
		{ID: "E11", Category: "test", LabelDE: "Druckpruefung", LabelEN: "Pressure Test", Tags: []string{"test_evidence"}, Sort: 11},
		{ID: "E12", Category: "test", LabelDE: "Laermmessung", LabelEN: "Noise Measurement", Tags: []string{"test_evidence"}, Sort: 12},
		{ID: "E13", Category: "test", LabelDE: "Vibrationsmessung", LabelEN: "Vibration Measurement", Tags: []string{"test_evidence"}, Sort: 13},
		{ID: "E14", Category: "test", LabelDE: "Software-Testprotokoll", LabelEN: "Software Test Protocol", Tags: []string{"test_evidence", "software_safety_measure"}, Sort: 14},
		{ID: "E15", Category: "test", LabelDE: "KI-Validierungsbericht", LabelEN: "AI Validation Report", Tags: []string{"test_evidence", "ai_risk"}, Sort: 15},
		{ID: "E16", Category: "cyber", LabelDE: "Penetrationstest-Bericht", LabelEN: "Penetration Test Report", Tags: []string{"cyber_evidence", "test_evidence"}, Sort: 16},
		{ID: "E17", Category: "cyber", LabelDE: "Netzwerk-Segmentierungsnachweis", LabelEN: "Network Segmentation Evidence", Tags: []string{"cyber_evidence"}, Sort: 17},
		{ID: "E18", Category: "cyber", LabelDE: "SBOM (Software Bill of Materials)", LabelEN: "SBOM", Tags: []string{"cyber_evidence"}, Sort: 18},
		{ID: "E19", Category: "cyber", LabelDE: "Patch-Management-Nachweis", LabelEN: "Patch Management Evidence", Tags: []string{"cyber_evidence"}, Sort: 19},
		{ID: "E20", Category: "inspection", LabelDE: "Abnahmeprotokoll", LabelEN: "Acceptance Protocol", Tags: []string{"inspection_evidence"}, Sort: 20},
		{ID: "E21", Category: "inspection", LabelDE: "Wartungscheckliste (ausgefuellt)", LabelEN: "Maintenance Checklist (completed)", Tags: []string{"inspection_evidence", "operational_evidence"}, Sort: 21},
		{ID: "E22", Category: "inspection", LabelDE: "CE-Konformitaetserklaerung", LabelEN: "CE Declaration of Conformity", Tags: []string{"certification_evidence"}, Sort: 22},
		{ID: "E23", Category: "inspection", LabelDE: "Typenpruefzertifikat", LabelEN: "Type Examination Certificate", Tags: []string{"certification_evidence"}, Sort: 23},
		{ID: "E24", Category: "training", LabelDE: "Schulungsnachweis Bediener", LabelEN: "Operator Training Record", Tags: []string{"training_evidence"}, Sort: 24},
		{ID: "E25", Category: "training", LabelDE: "Sicherheitsunterweisung (Protokoll)", LabelEN: "Safety Briefing Record", Tags: []string{"training_evidence"}, Sort: 25},
		// ── Phase 2: Erweiterte Evidenztypen (E26-E50) ───────────────
		{ID: "E26", Category: "test", LabelDE: "Materialzertifikat/Werkstoffzeugnis", LabelEN: "Material Certificate", Tags: []string{"test_evidence", "design_evidence"}, Sort: 26},
		{ID: "E27", Category: "test", LabelDE: "EMV-Pruefprotokoll", LabelEN: "EMC Test Report", Tags: []string{"test_evidence"}, Sort: 27},
		{ID: "E28", Category: "test", LabelDE: "Druckpruefungsprotokoll (DGRL/PED)", LabelEN: "Pressure Test Protocol (PED)", Tags: []string{"test_evidence"}, Sort: 28},
		{ID: "E29", Category: "test", LabelDE: "Laerm-Expositionsbericht", LabelEN: "Noise Exposure Report", Tags: []string{"test_evidence"}, Sort: 29},
		{ID: "E30", Category: "test", LabelDE: "Ergonomie-Bewertung", LabelEN: "Ergonomic Assessment", Tags: []string{"test_evidence", "inspection_evidence"}, Sort: 30},
		{ID: "E31", Category: "test", LabelDE: "Thermografie-Bericht", LabelEN: "Thermography Report", Tags: []string{"test_evidence"}, Sort: 31},
		{ID: "E32", Category: "inspection", LabelDE: "ATEX-Konformitaetsbewertung", LabelEN: "ATEX Conformity Assessment", Tags: []string{"certification_evidence"}, Sort: 32},
		{ID: "E33", Category: "test", LabelDE: "SIL/PL-Validierungsbericht", LabelEN: "SIL/PL Validation Report", Tags: []string{"test_evidence", "design_evidence"}, Sort: 33},
		{ID: "E34", Category: "design", LabelDE: "Betriebsanleitung (EN IEC 82079-1)", LabelEN: "Operating Instructions (IEC 82079-1)", Tags: []string{"design_evidence"}, Sort: 34},
		{ID: "E35", Category: "inspection", LabelDE: "Ex-Schutz-Dokument", LabelEN: "Explosion Protection Document", Tags: []string{"certification_evidence", "inspection_evidence"}, Sort: 35},
		{ID: "E36", Category: "test", LabelDE: "Schweissnaht-Pruefprotokoll", LabelEN: "Weld Seam Test Protocol", Tags: []string{"test_evidence"}, Sort: 36},
		{ID: "E37", Category: "test", LabelDE: "Oberflaechen-Rauheitsmessung", LabelEN: "Surface Roughness Measurement", Tags: []string{"test_evidence"}, Sort: 37},
		{ID: "E38", Category: "test", LabelDE: "Leckagepruefung Hydraulik/Pneumatik", LabelEN: "Leakage Test Hydraulic/Pneumatic", Tags: []string{"test_evidence"}, Sort: 38},
		{ID: "E39", Category: "test", LabelDE: "Schallemissionsmessung", LabelEN: "Sound Emission Measurement", Tags: []string{"test_evidence"}, Sort: 39},
		{ID: "E40", Category: "design", LabelDE: "Standsicherheitsnachweis", LabelEN: "Stability Proof", Tags: []string{"design_evidence", "analysis_evidence"}, Sort: 40},
		{ID: "E41", Category: "test", LabelDE: "Bremsentest-Protokoll", LabelEN: "Brake Test Protocol", Tags: []string{"test_evidence"}, Sort: 41},
		{ID: "E42", Category: "test", LabelDE: "Vibrationsmessung Hand-Arm", LabelEN: "Hand-Arm Vibration Measurement", Tags: []string{"test_evidence"}, Sort: 42},
		{ID: "E43", Category: "design", LabelDE: "Kurzschlussstrom-Berechnung", LabelEN: "Short Circuit Current Calculation", Tags: []string{"design_evidence", "analysis_evidence"}, Sort: 43},
		{ID: "E44", Category: "design", LabelDE: "Schutzabstands-Berechnung (ISO 13857)", LabelEN: "Safety Distance Calculation", Tags: []string{"design_evidence", "analysis_evidence"}, Sort: 44},
		{ID: "E45", Category: "test", LabelDE: "Nachlaufweg-Messung", LabelEN: "Overrun Distance Measurement", Tags: []string{"test_evidence"}, Sort: 45},
		{ID: "E46", Category: "test", LabelDE: "Kraftmessung Schutztuer", LabelEN: "Guard Door Force Measurement", Tags: []string{"test_evidence", "guard_measure"}, Sort: 46},
		{ID: "E47", Category: "test", LabelDE: "Anlaufstrom-Messung", LabelEN: "Inrush Current Measurement", Tags: []string{"test_evidence"}, Sort: 47},
		{ID: "E48", Category: "cyber", LabelDE: "Software-Versionsmanagement-Nachweis", LabelEN: "Software Version Management Evidence", Tags: []string{"cyber_evidence"}, Sort: 48},
		{ID: "E49", Category: "cyber", LabelDE: "Vulnerability-Scan-Bericht", LabelEN: "Vulnerability Scan Report", Tags: []string{"cyber_evidence", "test_evidence"}, Sort: 49},
		{ID: "E50", Category: "cyber", LabelDE: "SBOM-Vollstaendigkeitsnachweis", LabelEN: "SBOM Completeness Evidence", Tags: []string{"cyber_evidence"}, Sort: 50},
		// ── Phase 3: Metalworking-Evidenztypen (E51-E55) ─────────────
		{ID: "E51", Category: "test", LabelDE: "KSS-Analyseprotokoll", LabelEN: "MWF Analysis Protocol", Tags: []string{"test_evidence"}, Sort: 51},
		{ID: "E52", Category: "test", LabelDE: "Schleifscheiben-Pruefprotokoll", LabelEN: "Grinding Wheel Test Protocol", Tags: []string{"test_evidence"}, Sort: 52},
		{ID: "E53", Category: "test", LabelDE: "Spannmittel-Pruefprotokoll", LabelEN: "Clamping Device Test Protocol", Tags: []string{"test_evidence"}, Sort: 53},
		{ID: "E54", Category: "inspection", LabelDE: "Schweissnaht-Qualifikationsnachweis", LabelEN: "Weld Qualification Record", Tags: []string{"certification_evidence"}, Sort: 54},
		{ID: "E55", Category: "inspection", LabelDE: "KSS-Hautschutzplan (ausgefuellt)", LabelEN: "MWF Skin Protection Plan (completed)", Tags: []string{"inspection_evidence"}, Sort: 55},
	}
}
