package banview

import (
	"testing"
	"time"
)

func viewAt(clk *time.Time) *View {
	v := New()
	v.now = func() time.Time { return *clk }
	return v
}

func TestIngestRecentDropsExpired(t *testing.T) {
	clk := time.Date(2026, 6, 21, 12, 0, 0, 0, time.UTC)
	v := viewAt(&clk)
	v.Ingest([]Ban{
		{IP: "1.1.1.1", Reason: "tripwire", Since: clk, Expires: clk.Add(time.Hour)},
		{IP: "2.2.2.2", Reason: "rejections", Since: clk.Add(-2 * time.Hour), Expires: clk.Add(-time.Hour)}, // expired
		{IP: "", Reason: "x", Since: clk, Expires: clk.Add(time.Hour)},                                      // empty IP
	})
	got := v.Recent()
	if len(got) != 1 || got[0].IP != "1.1.1.1" || got[0].Reason != "tripwire" {
		t.Fatalf("Recent = %+v, want one live ban for 1.1.1.1", got)
	}
}

func TestIngestReplaces(t *testing.T) {
	clk := time.Date(2026, 6, 21, 12, 0, 0, 0, time.UTC)
	v := viewAt(&clk)
	v.Ingest([]Ban{{IP: "1.1.1.1", Since: clk, Expires: clk.Add(time.Hour)}})
	v.Ingest([]Ban{{IP: "2.2.2.2", Since: clk, Expires: clk.Add(time.Hour)}})
	got := v.Recent()
	if len(got) != 1 || got[0].IP != "2.2.2.2" {
		t.Fatalf("Recent = %+v, want only the latest report (2.2.2.2)", got)
	}
}

func TestRecentOrdersBySince(t *testing.T) {
	clk := time.Date(2026, 6, 21, 12, 0, 0, 0, time.UTC)
	v := viewAt(&clk)
	v.Ingest([]Ban{
		{IP: "old", Since: clk.Add(-10 * time.Minute), Expires: clk.Add(time.Hour)},
		{IP: "new", Since: clk.Add(-1 * time.Minute), Expires: clk.Add(time.Hour)},
	})
	got := v.Recent()
	if len(got) != 2 || got[0].IP != "new" || got[1].IP != "old" {
		t.Fatalf("Recent order = %+v, want most recent first", got)
	}
}

func TestUnbanRoundTrip(t *testing.T) {
	clk := time.Date(2026, 6, 21, 12, 0, 0, 0, time.UTC)
	v := viewAt(&clk)
	v.RequestUnban("3.3.3.3")
	v.RequestUnban("") // ignored
	drained := v.DrainUnbans()
	if len(drained) != 1 || drained[0] != "3.3.3.3" {
		t.Fatalf("DrainUnbans = %v, want [3.3.3.3]", drained)
	}
	if again := v.DrainUnbans(); again != nil {
		t.Fatalf("second DrainUnbans = %v, want nil (cleared)", again)
	}
}
