package ucca

import (
	"testing"
	"time"
)

func makeTestRegulations() map[string]*V2RegulationFile {
	future30 := time.Now().AddDate(0, 0, 30).Format("2006-01-02")
	future90 := time.Now().AddDate(0, 0, 90).Format("2006-01-02")
	past := time.Now().AddDate(0, 0, -10).Format("2006-01-02")

	return map[string]*V2RegulationFile{
		"TestReg": {
			Regulation: "TestReg",
			Obligations: []V2Obligation{
				{
					ID: "TR-001", Title: "Upcoming Critical",
					Deadline: &V2Deadline{Date: future30},
					News: &V2ObligationNews{
						Headline: "Critical Deadline", Summary: "Test summary",
						ActionRequired: "Do something", Affected: "All", ActionLink: "/sdk/test",
					},
					LegalBasis: []V2LegalBasis{{Norm: "TestLaw", Article: "Art. 1"}},
				},
				{
					ID: "TR-002", Title: "Upcoming Medium",
					Description: "Medium priority regulation change.",
					Deadline: &V2Deadline{Date: future90},
					LegalBasis: []V2LegalBasis{{Norm: "TestLaw", Article: "Art. 2"}},
				},
				{
					ID: "TR-003", Title: "Past Deadline",
					Deadline: &V2Deadline{Date: past},
				},
				{
					ID: "TR-004", Title: "No Deadline",
				},
			},
		},
	}
}

func TestGetRegulatoryNews_SortedByUrgency(t *testing.T) {
	regs := makeTestRegulations()
	items := GetRegulatoryNews(regs, RegulatoryNewsFilter{Limit: 10})

	if len(items) != 2 {
		t.Fatalf("expected 2 items (future only), got %d", len(items))
	}
	// First item should be the more urgent one (30 days)
	if items[0].ID != "TR-001" {
		t.Errorf("expected TR-001 first (most urgent), got %s", items[0].ID)
	}
	if items[1].ID != "TR-002" {
		t.Errorf("expected TR-002 second, got %s", items[1].ID)
	}
}

func TestGetRegulatoryNews_UsesNewsField(t *testing.T) {
	regs := makeTestRegulations()
	items := GetRegulatoryNews(regs, RegulatoryNewsFilter{Limit: 10})

	// TR-001 has hand-crafted news
	if items[0].Headline != "Critical Deadline" {
		t.Errorf("expected hand-crafted headline, got %q", items[0].Headline)
	}
	if items[0].ActionLink != "/sdk/test" {
		t.Errorf("expected /sdk/test, got %q", items[0].ActionLink)
	}
}

func TestGetRegulatoryNews_AutoGeneratesWithoutNews(t *testing.T) {
	regs := makeTestRegulations()
	items := GetRegulatoryNews(regs, RegulatoryNewsFilter{Limit: 10})

	// TR-002 has no news field — should auto-generate
	if items[1].Headline == "" {
		t.Error("expected auto-generated headline")
	}
	if items[1].Summary == "" {
		t.Error("expected auto-generated summary from description")
	}
}

func TestGetRegulatoryNews_ExcludesPastDeadlines(t *testing.T) {
	regs := makeTestRegulations()
	items := GetRegulatoryNews(regs, RegulatoryNewsFilter{Limit: 10})

	for _, item := range items {
		if item.ID == "TR-003" {
			t.Error("past deadline should be excluded")
		}
		if item.ID == "TR-004" {
			t.Error("no-deadline obligation should be excluded")
		}
	}
}

func TestGetRegulatoryNews_LimitWorks(t *testing.T) {
	regs := makeTestRegulations()
	items := GetRegulatoryNews(regs, RegulatoryNewsFilter{Limit: 1})

	if len(items) != 1 {
		t.Errorf("expected 1 item with limit=1, got %d", len(items))
	}
}

func TestComputeUrgency(t *testing.T) {
	tests := []struct {
		days     int
		expected string
	}{
		{5, "critical"},
		{30, "critical"},
		{31, "high"},
		{90, "high"},
		{91, "medium"},
		{180, "medium"},
		{181, "low"},
		{365, "low"},
	}
	for _, tc := range tests {
		got := computeUrgency(tc.days)
		if got != tc.expected {
			t.Errorf("computeUrgency(%d) = %q, want %q", tc.days, got, tc.expected)
		}
	}
}

func TestResolveDeadline_DeadlineDate(t *testing.T) {
	obl := V2Obligation{Deadline: &V2Deadline{Date: "2026-06-19"}}
	d, ok := resolveDeadline(obl)
	if !ok {
		t.Fatal("expected deadline resolved")
	}
	if d.Format("2006-01-02") != "2026-06-19" {
		t.Errorf("got %s", d.Format("2006-01-02"))
	}
}

func TestResolveDeadline_ValidFrom(t *testing.T) {
	obl := V2Obligation{ValidFrom: "2026-08-02"}
	d, ok := resolveDeadline(obl)
	if !ok {
		t.Fatal("expected deadline resolved from valid_from")
	}
	if d.Format("2006-01-02") != "2026-08-02" {
		t.Errorf("got %s", d.Format("2006-01-02"))
	}
}

func TestResolveDeadline_NoDate(t *testing.T) {
	obl := V2Obligation{}
	_, ok := resolveDeadline(obl)
	if ok {
		t.Error("expected no deadline for empty obligation")
	}
}

func TestFormatLegalReference(t *testing.T) {
	bases := []V2LegalBasis{
		{Norm: "DSGVO", Article: "Art. 22"},
		{Norm: "BGB", Article: "§ 356a"},
	}
	ref := formatLegalReference(bases)
	if ref != "Art. 22 DSGVO, § 356a BGB" {
		t.Errorf("got %q", ref)
	}
}

func TestGetRegulatoryNews_FromRealFiles(t *testing.T) {
	regs, err := LoadAllV2Regulations()
	if err != nil {
		t.Skipf("could not load v2 regulations: %v", err)
	}
	// Fixed reference date so the test is deterministic regardless of the wall clock:
	// VBR-OBL-001 (deadline 2026-06-19) must fall within [ref, ref+730d].
	ref := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
	items := GetRegulatoryNewsAt(regs, RegulatoryNewsFilter{Limit: 20, HorizonDays: 730}, ref)
	// Should find at least the Widerrufsbutton obligation
	found := false
	for _, item := range items {
		if item.ID == "VBR-OBL-001" {
			found = true
			if item.Headline != "Widerrufsbutton-Pflicht ab 19. Juni 2026" {
				t.Errorf("unexpected headline: %q", item.Headline)
			}
		}
	}
	if !found {
		t.Error("expected VBR-OBL-001 in regulatory news")
	}
}
