package iace

import (
	"math"
	"testing"
)

func TestMILStd882Severity_OrderedAndComplete(t *testing.T) {
	bands := MILStd882Severity()
	if len(bands) != 4 {
		t.Fatalf("expected 4 severity categories, got %d", len(bands))
	}
	wantCat := []string{"I", "II", "III", "IV"}
	prev := 11
	for i, b := range bands {
		if b.Category != wantCat[i] {
			t.Errorf("band %d: category %q, want %q", i, b.Category, wantCat[i])
		}
		if b.LabelDE == "" || b.Desc == "" {
			t.Errorf("band %s: empty label/desc", b.Category)
		}
		if b.Severity < 1 || b.Severity > 10 {
			t.Errorf("band %s: severity %d out of 1-10", b.Category, b.Severity)
		}
		if b.Severity >= prev {
			t.Errorf("severity not strictly descending at %s (%d >= %d)", b.Category, b.Severity, prev)
		}
		prev = b.Severity
	}
}

func TestMILStd882Probability_OrderedBands(t *testing.T) {
	bands := MILStd882Probability()
	if len(bands) != 6 {
		t.Fatalf("expected 6 probability levels, got %d", len(bands))
	}
	prevOcc, prevLambda := 11, math.Inf(1)
	for _, b := range bands {
		if b.Occurrence < 1 || b.Occurrence > 10 {
			t.Errorf("%s: occurrence %d out of 1-10", b.Level, b.Occurrence)
		}
		if b.Occurrence >= prevOcc {
			t.Errorf("occurrence not descending at %s", b.Level)
		}
		if b.LambdaMax >= prevLambda {
			t.Errorf("lambda_max not descending at %s", b.Level)
		}
		prevOcc, prevLambda = b.Occurrence, b.LambdaMax
	}
}

func TestOccurrenceFromRate(t *testing.T) {
	cases := []struct {
		rate float64
		want int
	}{
		{1.0, 10},  // A frequent
		{0.05, 8},  // B probable (1e-2..1e-1)
		{0.005, 6}, // C occasional (1e-3..1e-2)
		{1e-4, 4},  // D remote (1e-6..1e-3)
		{1e-8, 2},  // E improbable (<1e-6)
		{0, 1},     // F eliminated
		{-5, 1},    // guard
	}
	for _, c := range cases {
		if got := OccurrenceFromRate(c.rate); got != c.want {
			t.Errorf("OccurrenceFromRate(%g) = %d, want %d", c.rate, got, c.want)
		}
	}
}

func TestSeverityForCategory(t *testing.T) {
	if got := SeverityForCategory("I"); got != 10 {
		t.Errorf("Cat I = %d, want 10", got)
	}
	if got := SeverityForCategory("IV"); got != 2 {
		t.Errorf("Cat IV = %d, want 2", got)
	}
	if got := SeverityForCategory("Z"); got != 0 {
		t.Errorf("unknown cat = %d, want 0", got)
	}
}

func TestCriticalityCm(t *testing.T) {
	// Cm = λp·α·β·t = 1e-5 · 0.3 · 1.0 · 1000 = 3e-3
	got := CriticalityCm(1e-5, 0.3, 1.0, 1000)
	if math.Abs(got-3e-3) > 1e-9 {
		t.Errorf("Cm = %g, want 3e-3", got)
	}
	if CriticalityCm(-1, 0.3, 1, 1000) != 0 {
		t.Error("negative input should yield 0")
	}
}
