package alert

import (
	"strings"
	"testing"
)

func goodAlert() *Alert {
	return &Alert{
		CompanyID: "acme-001",
		SourceID:  "prom-prod",
		Severity:  SeverityCritical,
		Category:  "storage",
		Title:     "Disk full on db-prod-03",
		Body:      "92% used",
		Data:      map[string]string{"host": "db-prod-03", "used_pct": "92"},
		DedupeKey: "disk:db-prod-03:full",
	}
}

func TestValidate_OK(t *testing.T) {
	if err := goodAlert().Validate(); err != nil {
		t.Fatalf("expected nil, got %v", err)
	}
}

func TestValidate_BadCompanyID(t *testing.T) {
	a := goodAlert()
	a.CompanyID = "ACME-001" // uppercase not allowed
	if err := a.Validate(); err == nil {
		t.Fatal("expected error for uppercase company_id")
	}
}

func TestValidate_UnknownSeverity(t *testing.T) {
	a := goodAlert()
	a.Severity = "emergency"
	err := a.Validate()
	if err == nil {
		t.Fatal("expected error for unknown severity")
	}
	if !IsInvalid(err) {
		t.Fatalf("expected *ErrInvalid, got %T", err)
	}
	if !strings.Contains(err.Error(), "severity") {
		t.Fatalf("expected severity reason, got %v", err)
	}
}

func TestValidate_DedupeKeyTooLong(t *testing.T) {
	a := goodAlert()
	a.DedupeKey = strings.Repeat("a", 129)
	if err := a.Validate(); err == nil {
		t.Fatal("expected error for long dedupe_key")
	}
}

func TestValidate_DataKeyTooLong(t *testing.T) {
	a := goodAlert()
	a.Data = map[string]string{strings.Repeat("k", 65): "v"}
	if err := a.Validate(); err == nil {
		t.Fatal("expected error for long data key")
	}
}

func TestValidate_TooManyDataKeys(t *testing.T) {
	a := goodAlert()
	a.Data = make(map[string]string, MaxDataKeys+1)
	for i := 0; i < MaxDataKeys+1; i++ {
		a.Data[shortKey(i)] = "v"
	}
	if err := a.Validate(); err == nil {
		t.Fatal("expected error for too many data keys")
	}
}

func TestInminentColapseBypass(t *testing.T) {
	if !SeverityInminentColapse.InminentColapseBypass() {
		t.Fatal("inminent_colapse must bypass quiet hours")
	}
	if SeverityCritical.InminentColapseBypass() {
		t.Fatal("critical must NOT bypass quiet hours")
	}
}

func TestNewID_UniqueAndSortable(t *testing.T) {
	a := NewID()
	b := NewID()
	if a == b {
		t.Fatalf("ids collided: %s", a)
	}
	if len(a) != 26 {
		t.Fatalf("id length expected 26, got %d (%q)", len(a), a)
	}
}

func shortKey(i int) string {
	const alphabet = "abcdefghijklmnopqrstuvwxyz"
	if i < len(alphabet) {
		return string(alphabet[i])
	}
	return shortKey(i/len(alphabet)) + string(alphabet[i%len(alphabet)])
}

func TestSeverityRank(t *testing.T) {
	cases := []struct {
		sev  Severity
		want int
	}{
		{SeverityInfo, 0},
		{SeverityWarning, 1},
		{SeverityCritical, 2},
		{SeverityInminentColapse, 3},
		{Severity("bogus"), -1},
	}
	for _, tc := range cases {
		if got := tc.sev.Rank(); got != tc.want {
			t.Errorf("Severity(%q).Rank() = %d, want %d", tc.sev, got, tc.want)
		}
	}
}

func TestMinSeverityRank(t *testing.T) {
	if MinSeverityRank("") != 0 {
		t.Error("empty min_severity should default to rank 0 (info and above)")
	}
	if MinSeverityRank("critical") != 2 {
		t.Error("critical should be rank 2")
	}
	if MinSeverityRank("inminent_colapse") != 3 {
		t.Error("inminent_colapse should be rank 3")
	}
}
