package backupwindow

import "testing"

// Group A — LegTimes derives the three nightly legs at fixed offsets, wrap-safe across midnight.
// Red-proof: drop the modulo in FmtHHMM → the 23:30 case yields "24:30"/"25:15" and fails.
func TestLegTimes(t *testing.T) {
	cases := []struct{ start, db, tier2, offbox string }{
		{"02:30", "02:30", "03:30", "04:15"}, // the default window
		{"23:30", "23:30", "00:30", "01:15"}, // wraps past midnight
		{"22:00", "22:00", "23:00", "23:45"},
		{"00:00", "00:00", "01:00", "01:45"},
		{"2:30", "02:30", "03:30", "04:15"}, // normalizes a missing leading zero
	}
	for _, c := range cases {
		db, tier2, offbox := LegTimes(c.start)
		if db != c.db || tier2 != c.tier2 || offbox != c.offbox {
			t.Errorf("LegTimes(%q) = (%q,%q,%q), want (%q,%q,%q)", c.start, db, tier2, offbox, c.db, c.tier2, c.offbox)
		}
	}
}

// Group A — invalid input is rejected (LegTimes → empty; Valid → error). Callers pass a value
// already resolved through EffectiveWindow, so an empty result is never rendered.
func TestLegTimes_InvalidRejected(t *testing.T) {
	for _, bad := range []string{"25:77", "2200", "", "ab:cd", "24:00", "12:60", "-1:00"} {
		db, tier2, offbox := LegTimes(bad)
		if db != "" || tier2 != "" || offbox != "" {
			t.Errorf("LegTimes(%q) = (%q,%q,%q), want all empty (rejected)", bad, db, tier2, offbox)
		}
		if Valid(bad) == nil {
			t.Errorf("Valid(%q) = nil, want an error", bad)
		}
	}
	if Valid("02:30") != nil {
		t.Error("Valid(02:30) returned an error for a well-formed time")
	}
}

// Group A — the whole-guest gate span is [W+2h, W+6h), wrap-safe.
func TestGateWindow(t *testing.T) {
	if from, to := GateWindow("02:30"); from != "04:30" || to != "08:30" {
		t.Errorf("GateWindow(02:30) = (%q,%q), want (04:30,08:30)", from, to)
	}
	if from, to := GateWindow("23:00"); from != "01:00" || to != "05:00" {
		t.Errorf("GateWindow(23:00) = (%q,%q), want (01:00,05:00) — must wrap", from, to)
	}
	if from, to := GateWindow("bad"); from != "" || to != "" {
		t.Errorf("GateWindow(bad) = (%q,%q), want empties", from, to)
	}
}

// Group B — precedence: a valid settings value wins over a valid yaml value, which wins over the
// "02:30" default; an empty/corrupt settings value falls through the chain.
func TestEffectiveWindow(t *testing.T) {
	cases := []struct{ settingsVal, yamlVal, want string }{
		{"22:00", "02:30", "22:00"},   // settings wins over yaml
		{"", "03:00", "03:00"},        // yaml when settings empty
		{"", "", "02:30"},             // default when both empty
		{"garbage", "03:00", "03:00"}, // corrupt settings → fall through to yaml
		{"garbage", "nope", "02:30"},  // both invalid → default
		{"22:00", "", "22:00"},        // settings valid, yaml empty
	}
	for _, c := range cases {
		if got := EffectiveWindow(c.settingsVal, c.yamlVal); got != c.want {
			t.Errorf("EffectiveWindow(%q,%q) = %q, want %q", c.settingsVal, c.yamlVal, got, c.want)
		}
	}
}
