package award

import (
	"testing"
	"time"

	"hamlog/internal/qso"
)

func day(s string) time.Time {
	t, err := time.Parse("2006-01-02", s)
	if err != nil {
		panic(err)
	}
	return t
}

// A reference is not forever. A park is delisted, a district is merged, a castle
// loses its number. A contact made while it existed still counts — it was a
// valid contact on the day — and one made after it stopped existing does not.
func TestRefValidityWindow(t *testing.T) {
	m := RefMeta{Code: "KL-01", Valid: true, ValidTo: "2025-08-31"}
	for _, tc := range []struct {
		day  string
		want bool
	}{
		{"2019-01-01", true},
		{"2025-08-31", true}, // the last day it existed still counts
		{"2025-09-01", false},
		{"2026-08-12", false},
	} {
		if got := m.activeOn(tc.day); got != tc.want {
			t.Errorf("KL-01 on %s: active=%v, want %v", tc.day, got, tc.want)
		}
	}

	// A reference that only came into being partway through.
	n := RefMeta{Code: "KL-99", Valid: true, ValidFrom: "2025-01-15"}
	if n.activeOn("2025-01-14") {
		t.Error("counted a QSO from before the reference existed")
	}
	if !n.activeOn("2025-01-15") {
		t.Error("the first day it existed must count")
	}

	// No window of its own: the award's own dates govern, as they already do for
	// every QSO in the award. Nothing here may narrow that.
	if !(RefMeta{Code: "X", Valid: true}).activeOn("1970-01-01") {
		t.Error("a reference with no window must count on any date")
	}
}

// The whole point: the same QSO counts before the cutoff and does not after.
func TestExpiredRefStopsCountingForLaterQSOs(t *testing.T) {
	d := &Def{
		Code: "RDA", Name: "Russian District Award", Valid: true,
		Type: TypeQSOFields, Field: "note", MatchBy: "code",
		Confirm: []string{"lotw"},
	}
	metas := []RefMeta{
		{Code: "KL-01", Name: "Petrozavodsk", Valid: true, ValidTo: "2025-08-31"},
		{Code: "KL-04", Name: "Kostomuksha", Valid: true},
	}

	q := func(ref, on string) *qso.QSO {
		return &qso.QSO{Callsign: "RA1ABC", Band: "20m", Notes: ref, QSODate: day(on)}
	}

	if got := MatchQSO(*d, metas, q("KL-01", "2025-06-01")); len(got) != 1 || got[0] != "KL-01" {
		t.Errorf("a QSO made while KL-01 existed must count: got %v", got)
	}
	if got := MatchQSO(*d, metas, q("KL-01", "2025-09-15")); len(got) != 0 {
		t.Errorf("a QSO made after KL-01 ceased to exist must not count: got %v", got)
	}
	if got := MatchQSO(*d, metas, q("KL-04", "2025-09-15")); len(got) != 1 || got[0] != "KL-04" {
		t.Errorf("a reference with no window is unaffected: got %v", got)
	}
}

// The claim that an empty per-reference window "inherits the award's" has to be
// a fact about the code, not a comment. Compute and MatchQSO both gate on
// inScope, which enforces the award's own dates — so a reference with no window
// of its own is already bounded by them, and duplicating the check per reference
// would only create a second place for the same dates to disagree.
func TestEmptyRefWindowInheritsTheAward(t *testing.T) {
	d := Def{
		Code: "RDA", Name: "Russian District Award", Valid: true,
		Type: TypeQSOFields, Field: "note", MatchBy: "code",
		Confirm:   []string{"lotw"},
		ValidFrom: "1991-06-12", // the award itself starts here
	}
	metas := []RefMeta{{Code: "KL-04", Name: "Kostomuksha", Valid: true}} // no window of its own

	q := func(on string) *qso.QSO {
		return &qso.QSO{Callsign: "RA1ABC", Band: "20m", Notes: "KL-04", QSODate: day(on)}
	}
	if got := MatchQSO(d, metas, q("1991-06-11")); len(got) != 0 {
		t.Errorf("a QSO before the AWARD's start counted for a reference with no window of its own: %v", got)
	}
	if got := MatchQSO(d, metas, q("1991-06-12")); len(got) != 1 {
		t.Errorf("a QSO on the award's first day must count: %v", got)
	}

	// And a reference window NARROWER than the award's still applies on top.
	metas[0].ValidTo = "2025-08-31"
	if got := MatchQSO(d, metas, q("2025-09-01")); len(got) != 0 {
		t.Errorf("the reference's own end date was ignored: %v", got)
	}
}
