package iace

import (
	"sort"
	"strings"
	"testing"
)

// The cross-domain term list lives in gt_benchmark_harness_test.go
// (foreignDomainTerms, term → home domain). This precision guard reuses it and,
// unlike the diagnostic TestGT_DomainLeakage, runs the FULL production gating
// path including the relevance backstop, then ASSERTS zero leaks. It catches
// machine-type wiring regressions and weak-tag (structural_part) leaks in CI.

// firedHazardsForCase runs the exact production gating path (parse → engine match
// → relevance backstop) for one GT case and returns the surviving patterns.
func firedHazardsForCase(c gtCase) []PatternMatch {
	narrative := c.narrativeOverride
	pr := ParseNarrative(narrative, c.machineType)
	input := parseResultToMatchInput(pr, c.machineType)

	compNames := make([]string, 0, len(pr.Components))
	for _, comp := range pr.Components {
		if comp.Negated {
			continue
		}
		compNames = append(compNames, NormalizeDEPublic(comp.NameDE))
	}

	out := NewPatternEngine().Match(input)
	fired := make([]PatternMatch, 0, len(out.MatchedPatterns))
	for _, mp := range out.MatchedPatterns {
		if IsPatternRelevant(mp, narrative, compNames) {
			fired = append(fired, mp)
		}
	}
	return fired
}

// TestCrossDomainPrecision asserts that no fired pattern is foreign to the
// machine — neither machine-type-incompatible nor matching a foreign-domain
// term. Runs over the 2 ground truths AND the 4 Grenzen-only machines
// (press/cobot/motor/welding), so the gating guard is validated across six
// machine classes. A term whose domain is in the case's homeDomains is its
// OWN domain and never counts as a leak.
func TestCrossDomainPrecision(t *testing.T) {
	cases := append(append([]gtCase{}, gtBenchmarkCases...), precisionOnlyCases...)
	for _, c := range cases {
		c := c
		home := make(map[string]bool, len(c.homeDomains))
		for _, d := range c.homeDomains {
			home[d] = true
		}
		t.Run(c.name, func(t *testing.T) {
			fired := firedHazardsForCase(c)
			t.Logf("%s (%s): %d patterns fired", c.name, c.machineType, len(fired))

			var domainLeaks []string
			for _, mp := range fired {
				text := normalizeDE(mp.PatternName + " " + mp.ZoneDE + " " + mp.ScenarioDE)
				for term, domain := range foreignDomainTerms {
					if home[domain] {
						continue // this domain is native to the machine
					}
					if strings.Contains(text, term) {
						domainLeaks = append(domainLeaks, domain+"/"+term+" → "+mp.PatternName)
						break
					}
				}
			}
			sort.Strings(domainLeaks)
			for _, l := range domainLeaks {
				t.Logf("  FOREIGN-DOMAIN: %s", l)
			}
			if len(domainLeaks) > 0 {
				t.Errorf("%s: %d cross-domain leak(s) — patterns from foreign machine classes fired", c.name, len(domainLeaks))
			}
		})
	}
}
