package plugin

import (
	"log/slog"
	"sort"

	"maunium.net/go/mautrix/id"
)

// Auto-consumable rule (kept deliberately simple): the only pre-fight
// auto-pick is the panic heal. Other consumables (Coal Bombs, Ink Vials,
// Wards, etc.) sit in inventory until the player explicitly engages them
// — no threat-assessor magic deciding to burn a Voidstone Shard on a
// shadow.
//
// Heal triggers in the engine when player HP drops below 60% MaxHP. Each
// trigger consumes one charge; charges = number of healing consumables
// in the inventory. Post-combat, that many heal items are removed from
// the inventory bag (cheapest tier first so players burn through low
// stock before high-tier potions).
//
// The HealItem mod amount is the BEST heal value in inventory — every
// fire heals at the highest-tier-available rate. Slight balance pad
// (favors player), big simplification (engine doesn't need a per-charge
// values slice).

// setupAutoHealFromInventory wires the heal-on-low-HP behavior from the
// player's current consumable inventory. Returns the count of charges
// it set up (0 if no healing items at all).
func setupAutoHealFromInventory(consumables []ConsumableItem, mods *CombatModifiers) int {
	bestValue := 0
	count := 0
	for i := range consumables {
		c := &consumables[i]
		if c.Def == nil || c.Def.Effect != EffectHeal {
			continue
		}
		count++
		if v := int(c.Def.Value); v > bestValue {
			bestValue = v
		}
	}
	if count == 0 {
		return 0
	}
	mods.HealItem = bestValue
	if mods.HealItemCharges < count {
		mods.HealItemCharges = count
	}
	return count
}

// isBossPhases compares by slice header (same backing array) — boss fights
// are routed through bossCombatPhases (defined in combat_engine.go) and the
// caller passes that exact reference.
func isBossPhases(phases []CombatPhase) bool {
	if len(phases) != len(bossCombatPhases) {
		return false
	}
	if len(phases) == 0 {
		return false
	}
	return &phases[0] == &bossCombatPhases[0]
}

// countHealEventsFired counts how many heal_item events the engine emitted
// during this fight — equals the number of heal charges actually consumed
// and therefore the number of inventory items to remove.
func countHealEventsFired(result CombatResult) int {
	n := 0
	for _, e := range result.Events {
		if e.Action == "heal_item" {
			n++
		}
	}
	return n
}

// consumeFiredHealingItems removes `fired` healing consumables from the
// player's inventory, cheapest-tier first so players burn cheap stock
// before high-tier potions. No-op if fired <= 0.
func consumeFiredHealingItems(userID id.UserID, fired int) {
	if fired <= 0 {
		return
	}
	items, err := loadAdvInventory(userID)
	if err != nil {
		slog.Error("auto-heal cleanup: load inventory failed", "user", userID, "err", err)
		return
	}
	// Filter to heal items, sort cheapest-tier-first.
	type entry struct {
		id   int64
		tier int
		name string
	}
	var heals []entry
	for _, item := range items {
		if item.Type != "consumable" {
			continue
		}
		def := consumableDefByName(item.Name)
		if def == nil || def.Effect != EffectHeal {
			continue
		}
		heals = append(heals, entry{id: item.ID, tier: def.Tier, name: item.Name})
	}
	sort.SliceStable(heals, func(i, j int) bool { return heals[i].tier < heals[j].tier })
	removed := 0
	for _, h := range heals {
		if removed >= fired {
			break
		}
		if rerr := removeAdvInventoryItem(h.id); rerr != nil {
			slog.Error("auto-heal cleanup: remove failed", "user", userID, "item", h.name, "err", rerr)
			continue
		}
		removed++
	}
	if removed < fired {
		slog.Warn("auto-heal cleanup: short on inventory",
			"user", userID, "wanted", fired, "removed", removed)
	}
}
