package plugin

import "testing"

func TestSupplyDailyBurn_AllTiers(t *testing.T) {
	cases := []struct {
		tier ZoneTier
		want float32
	}{
		{ZoneTierBeginner, 1.0},
		{ZoneTierApprentice, 1.5},
		{ZoneTierJourneyman, 2.0},
		{ZoneTierVeteran, 3.0},
		{ZoneTierLegendary, 4.0},
	}
	for _, c := range cases {
		if got := supplyDailyBurn(c.tier); got != c.want {
			t.Errorf("tier %d: got %v, want %v", c.tier, got, c.want)
		}
	}
}

func TestSupplyHarshMultiplier_AllTiers(t *testing.T) {
	cases := []struct {
		tier ZoneTier
		want float32
	}{
		{ZoneTierBeginner, 1.0},
		{ZoneTierApprentice, 1.5},
		{ZoneTierJourneyman, 2.0},
		{ZoneTierVeteran, 2.5},
		{ZoneTierLegendary, 3.0},
	}
	for _, c := range cases {
		if got := supplyHarshMultiplier(c.tier); got != c.want {
			t.Errorf("tier %d: got %v, want %v", c.tier, got, c.want)
		}
	}
}

func TestSupplyDepletion_Brackets(t *testing.T) {
	cases := []struct {
		current float32
		max     float32
		want    SupplyDepletionState
	}{
		{10, 10, SupplyNormal},        // 100%
		{3, 10, SupplyNormal},         // 30%
		{2.5, 10, SupplyNormal},       // 25% — boundary stays normal
		{2, 10, SupplyRationing},      // 20%
		{1, 10, SupplyRationing},      // 10% — boundary stays rationing
		{0.9, 10, SupplySevereRationing},
		{0.1, 10, SupplySevereRationing},
		{0, 10, SupplyStarvation},
	}
	for _, c := range cases {
		s := ExpeditionSupplies{Current: c.current, Max: c.max}
		if got := supplyDepletion(s); got != c.want {
			t.Errorf("%v/%v: got %d, want %d", c.current, c.max, got, c.want)
		}
	}
}

func TestSupplyRollModifier(t *testing.T) {
	cases := map[SupplyDepletionState]int{
		SupplyNormal:          0,
		SupplyRationing:       -1,
		SupplySevereRationing: -2,
		SupplyStarvation:      -2,
	}
	for state, want := range cases {
		if got := supplyRollModifier(state); got != want {
			t.Errorf("state %d: got %d, want %d", state, got, want)
		}
	}
}

func TestSupplyAllowsLongRest(t *testing.T) {
	cases := map[SupplyDepletionState]bool{
		SupplyNormal:          true,
		SupplyRationing:       true,
		SupplySevereRationing: false,
		SupplyStarvation:      false,
	}
	for state, want := range cases {
		if got := supplyAllowsLongRest(state); got != want {
			t.Errorf("state %d: got %v, want %v", state, got, want)
		}
	}
}

func TestSupplyPurchase_Validate(t *testing.T) {
	cases := []struct {
		p       SupplyPurchase
		wantErr bool
	}{
		{SupplyPurchase{StandardPacks: 1}, false},
		{SupplyPurchase{StandardPacks: 3, DeluxePacks: 1}, false}, // max
		{SupplyPurchase{StandardPacks: 4}, true},                  // over standard cap
		{SupplyPurchase{DeluxePacks: 2}, true},                    // over deluxe cap
		{SupplyPurchase{StandardPacks: -1}, true},
		{SupplyPurchase{}, true}, // none purchased
	}
	for _, c := range cases {
		err := c.p.Validate()
		if (err != nil) != c.wantErr {
			t.Errorf("%+v: err = %v, wantErr=%v", c.p, err, c.wantErr)
		}
	}
}

func TestSupplyPurchase_TotalAndCost(t *testing.T) {
	p := SupplyPurchase{StandardPacks: 3, DeluxePacks: 1}
	if p.Total() != 50 {
		t.Errorf("total = %v, want 50", p.Total())
	}
	if p.Cost() != 240 {
		t.Errorf("cost = %d, want 240", p.Cost())
	}
}

func TestMakeSupplies_FillsFromTier(t *testing.T) {
	p := SupplyPurchase{StandardPacks: 2}
	s := makeSupplies(ZoneTierJourneyman, p)
	if s.Max != 20 || s.Current != 20 {
		t.Errorf("supplies: %+v", s)
	}
	if s.DailyBurn != 2.0 {
		t.Errorf("daily burn = %v, want 2", s.DailyBurn)
	}
	if s.PacksStandard != 2 {
		t.Errorf("packs std = %d", s.PacksStandard)
	}
}

func TestApplyDailyBurn_DrainsAndClamps(t *testing.T) {
	s := ExpeditionSupplies{Current: 5, Max: 10, DailyBurn: 2, HarshMod: 1.5, ForagedToday: true}
	s, burn := applyDailyBurn(s, false, false)
	if burn != 2 {
		t.Errorf("burn = %v, want 2", burn)
	}
	if s.Current != 3 {
		t.Errorf("current = %v, want 3", s.Current)
	}
	if s.ForagedToday {
		t.Error("forage flag should reset on day rollover")
	}
	// Harsh active doubles via mult.
	s, burn = applyDailyBurn(s, true, false)
	if burn != 3 { // 2 × 1.5
		t.Errorf("harsh burn = %v, want 3", burn)
	}
	// Siege forces a 2× floor even when HarshMod is below 2 (tier 1).
	t1 := ExpeditionSupplies{Current: 10, Max: 10, DailyBurn: 1, HarshMod: 1}
	_, sb := applyDailyBurn(t1, false, true)
	if sb != 2 {
		t.Errorf("siege tier1 burn = %v, want 2 (forced floor)", sb)
	}
	// Siege at higher tier still uses HarshMod when it exceeds 2.
	t5 := ExpeditionSupplies{Current: 10, Max: 10, DailyBurn: 1, HarshMod: 3}
	_, sb5 := applyDailyBurn(t5, false, true)
	if sb5 != 3 {
		t.Errorf("siege tier5 burn = %v, want 3 (HarshMod)", sb5)
	}
	// Drain to floor.
	for i := 0; i < 5; i++ {
		s, _ = applyDailyBurn(s, false, false)
	}
	if s.Current != 0 {
		t.Errorf("expected current clamped to 0, got %v", s.Current)
	}
}
