package iace

import "testing"

// TestControlsLibrary_UniqueIDs verifies all control IDs are unique.
func TestControlsLibrary_UniqueIDs(t *testing.T) {
	seen := make(map[string]bool)
	for _, e := range GetControlsLibrary() {
		if e.ID == "" {
			t.Errorf("control has empty ID")
			continue
		}
		if seen[e.ID] {
			t.Errorf("duplicate control ID: %s", e.ID)
		}
		seen[e.ID] = true
	}
}

// TestProtectiveMeasures_HasExamples verifies measures have examples.
func TestProtectiveMeasures_HasExamples(t *testing.T) {
	withExamples := 0
	for _, e := range GetProtectiveMeasureLibrary() {
		if len(e.Examples) > 0 {
			withExamples++
		}
	}
	total := len(GetProtectiveMeasureLibrary())
	threshold := total * 80 / 100
	if withExamples < threshold {
		t.Errorf("only %d/%d measures have examples, want at least %d", withExamples, total, threshold)
	}
}

// TestProtectiveMeasures_ThreeReductionTypesPresent verifies all 3 types exist.
func TestProtectiveMeasures_ThreeReductionTypesPresent(t *testing.T) {
	types := make(map[string]int)
	for _, e := range GetProtectiveMeasureLibrary() {
		types[e.ReductionType]++
	}
	// Accept both naming variants
	designCount := types["design"]
	protectiveCount := types["protective"] + types["protection"]
	infoCount := types["information"]

	if designCount == 0 {
		t.Error("no measures with reduction type design")
	}
	if protectiveCount == 0 {
		t.Error("no measures with reduction type protective/protection")
	}
	if infoCount == 0 {
		t.Error("no measures with reduction type information")
	}
}

// TestProtectiveMeasures_TagFieldAccessible verifies the Tags field is accessible.
func TestProtectiveMeasures_TagFieldAccessible(t *testing.T) {
	measures := GetProtectiveMeasureLibrary()
	if len(measures) == 0 {
		t.Fatal("no measures returned")
	}
	// Tags field exists but may not be populated yet
	_ = measures[0].Tags
}

// TestProtectiveMeasures_HazardCategoryNotEmpty verifies HazardCategory is populated.
func TestProtectiveMeasures_HazardCategoryNotEmpty(t *testing.T) {
	for _, e := range GetProtectiveMeasureLibrary() {
		if e.HazardCategory == "" {
			t.Errorf("measure %s (%s): HazardCategory is empty", e.ID, e.Name)
		}
	}
}

// TestProtectiveMeasures_Count241 verifies at least 241 measures exist (200 base + 25 mandatory + 16 Phase1B).
func TestProtectiveMeasures_Count241(t *testing.T) {
	entries := GetProtectiveMeasureLibrary()
	if len(entries) < 241 {
		t.Fatalf("got %d protective measures, want at least 241", len(entries))
	}
}

// TestProtectiveMeasures_Count160 verifies at least 160 measures exist (legacy gate).
func TestProtectiveMeasures_Count160(t *testing.T) {
	entries := GetProtectiveMeasureLibrary()
	if len(entries) < 160 {
		t.Fatalf("got %d protective measures, want at least 160", len(entries))
	}
}

// TestProtectiveMeasures_NormReferencesPopulated verifies most measures have norm refs.
func TestProtectiveMeasures_NormReferencesPopulated(t *testing.T) {
	withRefs := 0
	for _, e := range GetProtectiveMeasureLibrary() {
		if len(e.NormReferences) > 0 {
			withRefs++
		}
	}
	total := len(GetProtectiveMeasureLibrary())
	threshold := total * 90 / 100
	if withRefs < threshold {
		t.Errorf("only %d/%d measures have NormReferences, want at least %d", withRefs, total, threshold)
	}
}

// TestProtectiveMeasures_DesignProtectionInfoDistribution verifies balanced distribution.
func TestProtectiveMeasures_DesignProtectionInfoDistribution(t *testing.T) {
	types := make(map[string]int)
	for _, e := range GetProtectiveMeasureLibrary() {
		types[e.ReductionType]++
	}
	design := types["design"]
	protection := types["protection"]
	information := types["information"]

	if design < 50 {
		t.Errorf("design measures: %d, want >= 50", design)
	}
	if protection < 70 {
		t.Errorf("protection measures: %d, want >= 70", protection)
	}
	if information < 50 {
		t.Errorf("information measures: %d, want >= 50", information)
	}
	t.Logf("Distribution: design=%d, protection=%d, information=%d", design, protection, information)
}

// TestProtectiveMeasures_UniqueIDs verifies all measure IDs are unique.
func TestProtectiveMeasures_UniqueIDs(t *testing.T) {
	entries := GetProtectiveMeasureLibrary()
	seen := make(map[string]bool)
	for _, e := range entries {
		if seen[e.ID] {
			t.Errorf("duplicate measure ID: %s", e.ID)
		}
		seen[e.ID] = true
		if e.ID == "" {
			t.Error("empty measure ID found")
		}
	}
}

func padID(n int) string {
	if n < 10 {
		return "00" + itoa(n)
	}
	if n < 100 {
		return "0" + itoa(n)
	}
	return itoa(n)
}

func itoa(n int) string {
	if n == 0 {
		return "0"
	}
	s := ""
	for n > 0 {
		s = string(rune('0'+n%10)) + s
		n /= 10
	}
	return s
}

// TestProtectiveMeasures_SubTypesPresent verifies subtypes are used.
func TestProtectiveMeasures_SubTypesPresent(t *testing.T) {
	subtypes := make(map[string]int)
	for _, e := range GetProtectiveMeasureLibrary() {
		if e.SubType != "" {
			subtypes[e.SubType]++
		}
	}
	if len(subtypes) < 3 {
		t.Errorf("expected at least 3 different subtypes, got %d: %v", len(subtypes), subtypes)
	}
}
