package plugin

import (
	"strings"
	"testing"
)

// ── Display Tests ───────────────────────────────────────────────────────────

func TestLuigiShopGreeting_Basic(t *testing.T) {
	equip := map[EquipmentSlot]*AdvEquipment{
		SlotWeapon: {Tier: 2, Condition: 100},
	}
	text := luigiShopGreeting("@user:test", equip, 5000, false, 0)

	if !strings.Contains(text, "Luigi's") {
		t.Error("greeting should contain Luigi's")
	}
	if !strings.Contains(text, "€5000") {
		t.Error("greeting should show balance")
	}
	if !strings.Contains(text, "Weapons") {
		t.Error("greeting should show category grid")
	}
	if !strings.Contains(text, "Reply with a category") {
		t.Error("greeting should prompt for category")
	}
}

func TestLuigiShopGreeting_MaxedOut(t *testing.T) {
	equip := map[EquipmentSlot]*AdvEquipment{
		SlotWeapon: {Tier: 5, Condition: 100},
		SlotArmor:  {Tier: 5, Condition: 100},
		SlotHelmet: {Tier: 5, Condition: 100},
		SlotBoots:  {Tier: 5, Condition: 100},
		SlotTool:   {Tier: 5, Condition: 100},
	}
	text := luigiShopGreeting("@user:test", equip, 99999, false, 0)

	// Should NOT show category grid.
	if strings.Contains(text, "Reply with a category") {
		t.Error("maxed-out greeting should not show category prompt")
	}
	// Should use maxed-out flavor.
	if !strings.Contains(text, "fully kitted") {
		t.Error("maxed-out greeting should mention being fully kitted")
	}
}

func TestLuigiShopGreeting_ShowAll(t *testing.T) {
	equip := map[EquipmentSlot]*AdvEquipment{}
	text := luigiShopGreeting("@user:test", equip, 1000, true, 0)

	// Should contain a show-all comment.
	if !strings.Contains(text, "judgment") && !strings.Contains(text, "thoroughness") {
		t.Error("show all greeting should contain a show-all comment")
	}
}

func TestLuigiCategoryView_UpgradeIndicators(t *testing.T) {
	equip := map[EquipmentSlot]*AdvEquipment{
		SlotWeapon: {Tier: 2, Condition: 100, Name: "Dull Steel Sword of Mediocrity"},
	}
	text := luigiCategoryView("@user:test", SlotWeapon, equip, 50000, false)

	// Should show current equipped.
	if !strings.Contains(text, "🟢") {
		t.Error("should show 🟢 for currently equipped item")
	}
	// Should show upgrade indicators.
	if !strings.Contains(text, "⬆️") {
		t.Error("should show ⬆️ for items above current tier")
	}
	// Should NOT show T1 (below current tier) by default.
	if strings.Contains(text, "Sad Iron Sword") {
		t.Error("should not show items below current tier when showAll=false")
	}
}

func TestLuigiCategoryView_ShowAll(t *testing.T) {
	equip := map[EquipmentSlot]*AdvEquipment{
		SlotWeapon: {Tier: 3, Condition: 100, Name: "Sword (It's Fine)"},
	}
	text := luigiCategoryView("@user:test", SlotWeapon, equip, 50000, true)

	// Should show items below current tier.
	if !strings.Contains(text, "Sad Iron Sword") {
		t.Error("show all should include items below current tier")
	}
	// Below-tier items should show ⬇️.
	if !strings.Contains(text, "⬇️") {
		t.Error("show all should show ⬇️ for items below current tier")
	}
}

func TestLuigiCategoryView_Affordability(t *testing.T) {
	equip := map[EquipmentSlot]*AdvEquipment{
		SlotWeapon: {Tier: 0, Condition: 100, Name: "Basic Ass Sword"},
	}
	// Can afford T1 (€100) but not T2 (€450).
	text := luigiCategoryView("@user:test", SlotWeapon, equip, 200, false)

	if !strings.Contains(text, "✅") {
		t.Error("should show ✅ for affordable items")
	}
	if !strings.Contains(text, "💸") {
		t.Error("should show 💸 for unaffordable items")
	}
}

func TestLuigiCategoryView_MasterworkAck(t *testing.T) {
	equip := map[EquipmentSlot]*AdvEquipment{
		SlotWeapon: {Tier: 3, Condition: 100, Name: "MW Blade", Masterwork: true},
	}
	text := luigiCategoryView("@user:test", SlotWeapon, equip, 50000, false)

	if !strings.Contains(text, "⭐") {
		t.Error("should show ⭐ for masterwork gear")
	}
	// The masterwork acknowledgement pool has varied text — just check it's referenced.
	hasMWAck := strings.Contains(text, "Masterwork") || strings.Contains(text, "Arena gear") || strings.Contains(text, "can't beat that")
	if !hasMWAck {
		t.Error("should acknowledge masterwork/arena gear")
	}
}

func TestLuigiCategoryView_MaxedSlot(t *testing.T) {
	equip := map[EquipmentSlot]*AdvEquipment{
		SlotWeapon: {Tier: 5, Condition: 100, Name: "Vorpal Sword"},
	}
	text := luigiCategoryView("@user:test", SlotWeapon, equip, 50000, false)

	if !strings.Contains(text, "max tier") {
		t.Error("should show max-tier message when nothing to buy")
	}
}

// ── Item Confirm Tests ──────────────────────────────────────────────���───────

func TestLuigiItemConfirm_Upgrade(t *testing.T) {
	def := &EquipmentDef{Name: "Silver Blade", Tier: 3, Price: 1500}
	current := &AdvEquipment{Tier: 2, Name: "Dull Steel Sword"}
	text := luigiItemConfirm("@user:test", SlotWeapon, def, current, 5000)

	if !strings.Contains(text, "⬆️") {
		t.Error("should show upgrade indicator")
	}
	if !strings.Contains(text, "upgrade from") {
		t.Error("should mention it's an upgrade")
	}
	if !strings.Contains(text, "€5000") {
		t.Error("should show current balance")
	}
	if !strings.Contains(text, "€3500") {
		t.Error("should show balance after purchase")
	}
	if !strings.Contains(text, "Confirm?") {
		t.Error("should prompt for confirmation")
	}
}

func TestLuigiItemConfirm_NoCurrent(t *testing.T) {
	def := &EquipmentDef{Name: "Sad Iron Sword", Tier: 1, Price: 100}
	text := luigiItemConfirm("@user:test", SlotWeapon, def, nil, 1000)

	if !strings.Contains(text, "upgrade from") {
		t.Error("should say upgrade from None")
	}
}

// ── Item Lookup Tests ──────────────────────────────────────────────��────────

func TestAdvFindShopItemInSlot_ExactMatch(t *testing.T) {
	slot, def, ok := advFindShopItemInSlot("Enchanted Plate", SlotArmor)
	if !ok {
		t.Fatal("should find Enchanted Plate in armor slot")
	}
	if slot != SlotArmor {
		t.Errorf("slot should be armor, got %s", slot)
	}
	if def.Tier != 4 {
		t.Errorf("Enchanted Plate should be tier 4, got %d", def.Tier)
	}
}

func TestAdvFindShopItemInSlot_WrongSlot(t *testing.T) {
	_, _, ok := advFindShopItemInSlot("Dragonscale", SlotWeapon)
	if ok {
		t.Error("should not find armor item in weapon slot")
	}
}

func TestAdvFindShopItemInSlot_PartialMatch(t *testing.T) {
	slot, def, ok := advFindShopItemInSlot("Enchanted Blade", SlotWeapon)
	if !ok {
		t.Fatal("should find Enchanted Blade by partial match")
	}
	if slot != SlotWeapon {
		t.Errorf("slot should be weapon, got %s", slot)
	}
	if def.Tier != 4 {
		t.Errorf("Enchanted Blade should be tier 4, got %d", def.Tier)
	}
}

func TestAdvFindShopItemInSlot_CaseInsensitive(t *testing.T) {
	_, _, ok := advFindShopItemInSlot("enchanted blade", SlotWeapon)
	if !ok {
		t.Error("should find item case-insensitively")
	}
}

func TestAdvFindShopItemInSlot_NoTier0(t *testing.T) {
	_, _, ok := advFindShopItemInSlot("Basic Ass Sword", SlotWeapon)
	if ok {
		t.Error("should not find tier 0 items (price 0)")
	}
}

func TestAdvFindShopItem_TierShorthand(t *testing.T) {
	slot, def, ok := advFindShopItem("3 sword")
	if !ok {
		t.Fatal("should find via tier shorthand")
	}
	if slot != SlotWeapon {
		t.Errorf("slot should be weapon, got %s", slot)
	}
	if def.Tier != 3 {
		t.Errorf("tier should be 3, got %d", def.Tier)
	}
}

func TestAdvFindShopItem_TierPrefix(t *testing.T) {
	_, def, ok := advFindShopItem("tier 5 boots")
	if !ok {
		t.Fatal("should find via 'tier 5 boots'")
	}
	if def.Tier != 5 {
		t.Errorf("tier should be 5, got %d", def.Tier)
	}
}

func TestAdvFindShopItem_TShorthand(t *testing.T) {
	_, def, ok := advFindShopItem("t4 armor")
	if !ok {
		t.Fatal("should find via 't4 armor'")
	}
	if def.Tier != 4 {
		t.Errorf("tier should be 4, got %d", def.Tier)
	}
}

// ── Flavor Coverage Tests ───────────────────────────────────────────────────

func TestLuigiItemDescriptions_Coverage(t *testing.T) {
	for _, slot := range allSlots {
		defs := equipmentTiers[slot]
		for _, def := range defs {
			if def.Price == 0 {
				continue // skip tier 0
			}
			key := luigiItemKey{slot, def.Tier}
			if _, ok := luigiItemDescriptions[key]; !ok {
				t.Errorf("missing Luigi item description for %s tier %d (%s)", slot, def.Tier, def.Name)
			}
			if _, ok := luigiItemOneLiners[key]; !ok {
				t.Errorf("missing Luigi one-liner for %s tier %d (%s)", slot, def.Tier, def.Name)
			}
		}
	}
}

func TestLuigiCategoryIntros_Coverage(t *testing.T) {
	for _, slot := range allSlots {
		intros, ok := luigiCategoryIntros[slot]
		if !ok || len(intros) == 0 {
			t.Errorf("missing Luigi category intros for slot %s", slot)
		}
	}
}

func TestLuigiFlavorPools_NonEmpty(t *testing.T) {
	pools := map[string][]string{
		"luigiGreetings":         luigiGreetings,
		"luigiPurchaseConfirm":   luigiPurchaseConfirm,
		"luigiTier5Confirm":      luigiTier5Confirm,
		"luigiComboConfirm":      luigiComboConfirm,
		"luigiInsufficientFunds": luigiInsufficientFunds,
		"luigiBrowseTimeout":     luigiBrowseTimeout,
		"luigiMaxedOut":          luigiMaxedOut,
		"luigiMasterworkAck":     luigiMasterworkAck,
		"luigiShowAllComment":    luigiShowAllComment,
		"luigiCommentary":        luigiCommentary,
		"luigiCancellation":      luigiCancellation,
	}
	for name, pool := range pools {
		if len(pool) == 0 {
			t.Errorf("flavor pool %s is empty", name)
		}
	}
}

// ── Format String Safety ────────────────────────────────────────────────────

func TestLuigiPurchaseConfirm_FormatStrings(t *testing.T) {
	for i, tmpl := range luigiPurchaseConfirm {
		// Should have %s then %d
		result := strings.Contains(tmpl, "%s") && strings.Contains(tmpl, "%d")
		if !result {
			t.Errorf("luigiPurchaseConfirm[%d] missing %%s or %%d placeholder", i)
		}
	}
}

func TestLuigiTier5Confirm_FormatStrings(t *testing.T) {
	for i, tmpl := range luigiTier5Confirm {
		result := strings.Contains(tmpl, "%s") && strings.Contains(tmpl, "%d")
		if !result {
			t.Errorf("luigiTier5Confirm[%d] missing %%s or %%d placeholder", i)
		}
	}
}

func TestLuigiComboConfirm_FormatStrings(t *testing.T) {
	for i, tmpl := range luigiComboConfirm {
		result := strings.Contains(tmpl, "%s") && strings.Contains(tmpl, "%d")
		if !result {
			t.Errorf("luigiComboConfirm[%d] missing %%s or %%d placeholder", i)
		}
	}
}

// ── Tier Bounds Safety ──────────────────────────────────────────────────────

func TestEquipmentTiers_ConsistentIndexing(t *testing.T) {
	for _, slot := range allSlots {
		defs := equipmentTiers[slot]
		for i, def := range defs {
			if def.Tier != i {
				t.Errorf("slot %s: tier %d at index %d (should match for safe direct indexing)", slot, def.Tier, i)
			}
		}
	}
}

func TestEquipmentTiers_SixTiersPerSlot(t *testing.T) {
	for _, slot := range allSlots {
		defs := equipmentTiers[slot]
		if len(defs) != 6 {
			t.Errorf("slot %s: expected 6 tiers (0-5), got %d", slot, len(defs))
		}
	}
}
