package iace

import (
	"strings"
	"testing"
)

// TestCanonicalMachineType_Folds verifies that fine-grained norm machine-type
// keys fold to the right canonical family — and that the deliberate exclusions
// (pressure_*, treadmill, seesaw, chainsaw, heat_pump, blood_pressure_monitor)
// do NOT fold into a wrong family.
func TestCanonicalMachineType_Folds(t *testing.T) {
	folds := map[string]string{
		"welding_machine": "welding", "arc_welder": "welding",
		"stamping_press": "press", "mechanical_press": "press", "hydraulic_press": "press",
		"band_saw": "circular_saw", "panel_saw": "circular_saw", "saw": "circular_saw",
		"mobile_crane": "crane", "overhead_crane": "crane",
		"robot": "robotics_cobot", "industrial_robot": "robotics_cobot", "cobot": "robotics_cobot",
		"conveyor_belt": "conveyor", "belt_conveyor": "conveyor",
		"food_machine": "food_processing", "bakery_machine": "food_processing",
		"milling_machine": "milling", "grinding_machine": "grinding", "drilling_machine": "drilling",
		"textile_machine": "textile", "weaving_machine": "weaving",
		"glass_processing_machine": "glass_processing", "playground_equipment": "playground",
		"laser_machine": "laser_device", "passenger_lift": "elevator",
		// generic suffix-strip fallback (not in synonym map):
		"packaging_machine": "packaging",
	}
	for in, want := range folds {
		if got := canonicalMachineType(in); got != want {
			t.Errorf("canonicalMachineType(%q) = %q, want %q", in, got, want)
		}
	}

	// Must NOT fold into a wrong family — these keep their own identity.
	noFold := []string{
		"pressure_vessel", "pressure_washer", "blood_pressure_monitor", // not press
		"treadmill",  // not milling
		"seesaw",     // not saw (playground)
		"chainsaw",   // not bench saw (forestry/handheld)
		"heat_pump",  // not the industrial pump dropdown
		"two_roll_mill", // rolling, not milling
	}
	for _, in := range noFold {
		if got := canonicalMachineType(in); got == "press" || got == "milling" || got == "circular_saw" || got == "pump" {
			t.Errorf("canonicalMachineType(%q) = %q — must NOT fold into a wrong family", in, got)
		}
	}
}

// TestNormMachineTypeReconciliation asserts the norm engine now reaches machine-
// specific C-norms via the canonical family (regression guard for the broken
// exact-"==" matching where welding/cobot matched 0 of 605 C-norms).
func TestNormMachineTypeReconciliation(t *testing.T) {
	cases := []struct {
		machineType string
		minCNorms   int
	}{
		{"welding", 8},
		{"press", 8},
		{"mechanical_press", 8},
		{"robotics_cobot", 3},
		{"circular_saw", 10},
		{"crane", 10},
		{"lift", 10},
		{"food_processing", 10},
		{"conveyor", 6},
	}
	for _, tc := range cases {
		res := SuggestNorms(tc.machineType, nil, nil)
		if res == nil {
			t.Fatalf("%s: SuggestNorms returned nil", tc.machineType)
		}
		// Count C-norms suggested via a machine_type source.
		n := 0
		for _, s := range res.CNorms {
			for _, src := range s.Sources {
				if strings.HasPrefix(src, "machine_type") {
					n++
					break
				}
			}
		}
		if n < tc.minCNorms {
			t.Errorf("%s: %d machine-type C-norms suggested, want >= %d", tc.machineType, n, tc.minCNorms)
		}
	}

	// Cross-family guard: a lift must NOT pull welding-specific C-norms.
	lift := SuggestNorms("lift", nil, nil)
	for _, s := range lift.CNorms {
		for _, mt := range s.Norm.MachineTypes {
			if canonicalMachineType(mt) == "welding" {
				t.Errorf("lift project suggested a welding C-norm %q (cross-family leak)", s.Norm.Number)
			}
		}
	}
}
