package items

import (
	"fmt"
	"log"
)

// NewEquipmentItemList creates a new equipment item list
func NewEquipmentItemList() *EquipmentItemList {
	return &EquipmentItemList{
		items:          [NumSlots]*Item{},
		appearanceType: BaseEquipment,
	}
}

// NewEquipmentItemListFromCopy creates a copy of an equipment list
func NewEquipmentItemListFromCopy(source *EquipmentItemList) *EquipmentItemList {
	if source == nil {
		return NewEquipmentItemList()
	}

	source.mutex.RLock()
	defer source.mutex.RUnlock()

	equipment := &EquipmentItemList{
		appearanceType: source.appearanceType,
	}

	// Copy all equipped items
	for i, item := range source.items {
		if item != nil {
			equipment.items[i] = item.Copy()
		}
	}

	return equipment
}

// GetAllEquippedItems returns all equipped items
func (eil *EquipmentItemList) GetAllEquippedItems() []*Item {
	eil.mutex.RLock()
	defer eil.mutex.RUnlock()

	var equippedItems []*Item

	for _, item := range eil.items {
		if item != nil {
			equippedItems = append(equippedItems, item)
		}
	}

	return equippedItems
}

// ResetPackets resets packet data
func (eil *EquipmentItemList) ResetPackets() {
	eil.mutex.Lock()
	defer eil.mutex.Unlock()

	eil.xorPacket = nil
	eil.origPacket = nil
}

// HasItem checks if a specific item ID is equipped
func (eil *EquipmentItemList) HasItem(itemID int32) bool {
	eil.mutex.RLock()
	defer eil.mutex.RUnlock()

	for _, item := range eil.items {
		if item != nil && item.Details.ItemID == itemID {
			return true
		}
	}

	return false
}

// GetNumberOfItems returns the number of equipped items
func (eil *EquipmentItemList) GetNumberOfItems() int8 {
	eil.mutex.RLock()
	defer eil.mutex.RUnlock()

	count := int8(0)
	for _, item := range eil.items {
		if item != nil {
			count++
		}
	}

	return count
}

// GetWeight returns the total weight of equipped items
func (eil *EquipmentItemList) GetWeight() int32 {
	eil.mutex.RLock()
	defer eil.mutex.RUnlock()

	totalWeight := int32(0)
	for _, item := range eil.items {
		if item != nil {
			totalWeight += item.GenericInfo.Weight * int32(item.Details.Count)
		}
	}

	return totalWeight
}

// GetItemFromUniqueID gets an equipped item by unique ID
func (eil *EquipmentItemList) GetItemFromUniqueID(uniqueID int32) *Item {
	eil.mutex.RLock()
	defer eil.mutex.RUnlock()

	for _, item := range eil.items {
		if item != nil && int32(item.Details.UniqueID) == uniqueID {
			return item
		}
	}

	return nil
}

// GetItemFromItemID gets an equipped item by item template ID
func (eil *EquipmentItemList) GetItemFromItemID(itemID int32) *Item {
	eil.mutex.RLock()
	defer eil.mutex.RUnlock()

	for _, item := range eil.items {
		if item != nil && item.Details.ItemID == itemID {
			return item
		}
	}

	return nil
}

// SetItem sets an item in a specific equipment slot
func (eil *EquipmentItemList) SetItem(slotID int8, item *Item, locked bool) {
	if slotID < 0 || slotID >= NumSlots {
		return
	}

	if !locked {
		eil.mutex.Lock()
		defer eil.mutex.Unlock()
	}

	eil.items[slotID] = item

	if item != nil {
		item.Details.SlotID = int16(slotID)
		item.Details.AppearanceType = int16(eil.appearanceType)
	}
}

// RemoveItem removes an item from a specific slot
func (eil *EquipmentItemList) RemoveItem(slot int8, deleteItem bool) {
	if slot < 0 || slot >= NumSlots {
		return
	}

	eil.mutex.Lock()
	defer eil.mutex.Unlock()

	item := eil.items[slot]
	eil.items[slot] = nil

	if deleteItem && item != nil {
		item.NeedsDeletion = true
	}
}

// GetItem gets an item from a specific slot
func (eil *EquipmentItemList) GetItem(slotID int8) *Item {
	if slotID < 0 || slotID >= NumSlots {
		return nil
	}

	eil.mutex.RLock()
	defer eil.mutex.RUnlock()

	return eil.items[slotID]
}

// AddItem adds an item to the equipment (finds appropriate slot)
func (eil *EquipmentItemList) AddItem(slot int8, item *Item) bool {
	if item == nil {
		return false
	}

	// Check if the specific slot is requested and valid
	if slot >= 0 && slot < NumSlots {
		eil.mutex.Lock()
		defer eil.mutex.Unlock()

		if eil.items[slot] == nil {
			eil.items[slot] = item
			item.Details.SlotID = int16(slot)
			item.Details.AppearanceType = int16(eil.appearanceType)
			return true
		}
	}

	// Find a free slot that the item can be equipped in
	freeSlot := eil.GetFreeSlot(item, slot, 0)
	if freeSlot < NumSlots {
		eil.SetItem(freeSlot, item, false)
		return true
	}

	return false
}

// CheckEquipSlot checks if an item can be equipped in a specific slot
func (eil *EquipmentItemList) CheckEquipSlot(item *Item, slot int8) bool {
	if item == nil || slot < 0 || slot >= NumSlots {
		return false
	}

	// Check if item has the required slot data
	return item.HasSlot(slot, -1)
}

// CanItemBeEquippedInSlot checks if an item can be equipped in a slot
func (eil *EquipmentItemList) CanItemBeEquippedInSlot(item *Item, slot int8) bool {
	if item == nil || slot < 0 || slot >= NumSlots {
		return false
	}

	// Check slot compatibility
	if !eil.CheckEquipSlot(item, slot) {
		return false
	}

	// Check if slot is already occupied
	eil.mutex.RLock()
	defer eil.mutex.RUnlock()

	return eil.items[slot] == nil
}

// GetFreeSlot finds a free slot for an item
func (eil *EquipmentItemList) GetFreeSlot(item *Item, preferredSlot int8, version int16) int8 {
	if item == nil {
		return NumSlots // Invalid slot
	}

	eil.mutex.RLock()
	defer eil.mutex.RUnlock()

	// If preferred slot is specified and available, use it
	if preferredSlot >= 0 && preferredSlot < NumSlots {
		if eil.items[preferredSlot] == nil && item.HasSlot(preferredSlot, -1) {
			return preferredSlot
		}
	}

	// Search through all possible slots for this item
	for slot := int8(0); slot < NumSlots; slot++ {
		if eil.items[slot] == nil && item.HasSlot(slot, -1) {
			return slot
		}
	}

	return NumSlots // No free slot found
}

// CheckSlotConflict checks for slot conflicts (lore items, etc.)
func (eil *EquipmentItemList) CheckSlotConflict(item *Item, checkLoreOnly bool, loreStackCount *int16) int32 {
	if item == nil {
		return 0
	}

	eil.mutex.RLock()
	defer eil.mutex.RUnlock()

	// Check for lore conflicts
	if item.CheckFlag(Lore) || item.CheckFlag(LoreEquip) {
		stackCount := int16(0)

		for _, equippedItem := range eil.items {
			if equippedItem != nil && equippedItem.Details.ItemID == item.Details.ItemID {
				stackCount++
			}
		}

		if loreStackCount != nil {
			*loreStackCount = stackCount
		}

		if stackCount > 0 {
			return 1 // Lore conflict
		}
	}

	return 0 // No conflict
}

// GetSlotByItem finds the slot an item is equipped in
func (eil *EquipmentItemList) GetSlotByItem(item *Item) int8 {
	if item == nil {
		return NumSlots
	}

	eil.mutex.RLock()
	defer eil.mutex.RUnlock()

	for slot, equippedItem := range eil.items {
		if equippedItem == item {
			return int8(slot)
		}
	}

	return NumSlots // Not found
}

// CalculateEquipmentBonuses calculates stat bonuses from all equipped items
func (eil *EquipmentItemList) CalculateEquipmentBonuses() *ItemStatsValues {
	return eil.CalculateEquipmentBonusesWithEntity(nil)
}

// CalculateEquipmentBonusesWithEntity calculates stat bonuses from all equipped items with entity modifiers
func (eil *EquipmentItemList) CalculateEquipmentBonusesWithEntity(entity Entity) *ItemStatsValues {
	eil.mutex.RLock()
	defer eil.mutex.RUnlock()

	totalBonuses := &ItemStatsValues{}

	// We need access to the master item list to calculate bonuses
	// This would typically be injected or passed as a parameter
	// For now, we'll just accumulate basic stats from the items
	for _, item := range eil.items {
		if item != nil {
			// TODO: Implement item bonus calculation with master item list
			// This should call mil.CalculateItemBonusesFromItem(item, entity)
			itemBonuses := &ItemStatsValues{} // placeholder
			if itemBonuses != nil {
				// Add item bonuses to total
				totalBonuses.Str += itemBonuses.Str
				totalBonuses.Sta += itemBonuses.Sta
				totalBonuses.Agi += itemBonuses.Agi
				totalBonuses.Wis += itemBonuses.Wis
				totalBonuses.Int += itemBonuses.Int
				totalBonuses.VsSlash += itemBonuses.VsSlash
				totalBonuses.VsCrush += itemBonuses.VsCrush
				totalBonuses.VsPierce += itemBonuses.VsPierce
				totalBonuses.VsPhysical += itemBonuses.VsPhysical
				totalBonuses.VsHeat += itemBonuses.VsHeat
				totalBonuses.VsCold += itemBonuses.VsCold
				totalBonuses.VsMagic += itemBonuses.VsMagic
				totalBonuses.VsMental += itemBonuses.VsMental
				totalBonuses.VsDivine += itemBonuses.VsDivine
				totalBonuses.VsDisease += itemBonuses.VsDisease
				totalBonuses.VsPoison += itemBonuses.VsPoison
				totalBonuses.Health += itemBonuses.Health
				totalBonuses.Power += itemBonuses.Power
				totalBonuses.Concentration += itemBonuses.Concentration
				totalBonuses.AbilityModifier += itemBonuses.AbilityModifier
				totalBonuses.CriticalMitigation += itemBonuses.CriticalMitigation
				totalBonuses.ExtraShieldBlockChance += itemBonuses.ExtraShieldBlockChance
				totalBonuses.BeneficialCritChance += itemBonuses.BeneficialCritChance
				totalBonuses.CritBonus += itemBonuses.CritBonus
				totalBonuses.Potency += itemBonuses.Potency
				totalBonuses.HateGainMod += itemBonuses.HateGainMod
				totalBonuses.AbilityReuseSpeed += itemBonuses.AbilityReuseSpeed
				totalBonuses.AbilityCastingSpeed += itemBonuses.AbilityCastingSpeed
				totalBonuses.AbilityRecoverySpeed += itemBonuses.AbilityRecoverySpeed
				totalBonuses.SpellReuseSpeed += itemBonuses.SpellReuseSpeed
				totalBonuses.SpellMultiAttackChance += itemBonuses.SpellMultiAttackChance
				totalBonuses.DPS += itemBonuses.DPS
				totalBonuses.AttackSpeed += itemBonuses.AttackSpeed
				totalBonuses.MultiAttackChance += itemBonuses.MultiAttackChance
				totalBonuses.Flurry += itemBonuses.Flurry
				totalBonuses.AEAutoattackChance += itemBonuses.AEAutoattackChance
				totalBonuses.Strikethrough += itemBonuses.Strikethrough
				totalBonuses.Accuracy += itemBonuses.Accuracy
				totalBonuses.OffensiveSpeed += itemBonuses.OffensiveSpeed
				totalBonuses.UncontestedParry += itemBonuses.UncontestedParry
				totalBonuses.UncontestedBlock += itemBonuses.UncontestedBlock
				totalBonuses.UncontestedDodge += itemBonuses.UncontestedDodge
				totalBonuses.UncontestedRiposte += itemBonuses.UncontestedRiposte
				totalBonuses.SizeMod += itemBonuses.SizeMod
			}
		}
	}

	return totalBonuses
}

// SetAppearanceType sets the appearance type (normal or appearance equipment)
func (eil *EquipmentItemList) SetAppearanceType(appearanceType int8) {
	eil.mutex.Lock()
	defer eil.mutex.Unlock()

	eil.appearanceType = appearanceType

	// Update all equipped items with new appearance type
	for _, item := range eil.items {
		if item != nil {
			item.Details.AppearanceType = int16(appearanceType)
		}
	}
}

// GetAppearanceType gets the current appearance type
func (eil *EquipmentItemList) GetAppearanceType() int8 {
	eil.mutex.RLock()
	defer eil.mutex.RUnlock()

	return eil.appearanceType
}

// ValidateEquipment validates all equipped items
func (eil *EquipmentItemList) ValidateEquipment() *ItemValidationResult {
	eil.mutex.RLock()
	defer eil.mutex.RUnlock()

	result := &ItemValidationResult{Valid: true}

	for slot, item := range eil.items {
		if item != nil {
			// Validate item
			itemResult := item.Validate()
			if !itemResult.Valid {
				result.Valid = false
				for _, err := range itemResult.Errors {
					result.Errors = append(result.Errors, fmt.Sprintf("Slot %d: %s", slot, err))
				}
			}

			// Check slot compatibility
			if !item.HasSlot(int8(slot), -1) {
				result.Valid = false
				result.Errors = append(result.Errors, fmt.Sprintf("Item %s cannot be equipped in slot %d", item.Name, slot))
			}
		}
	}

	return result
}

// GetEquippedItemsByType returns equipped items of a specific type
func (eil *EquipmentItemList) GetEquippedItemsByType(itemType int8) []*Item {
	eil.mutex.RLock()
	defer eil.mutex.RUnlock()

	var matchingItems []*Item

	for _, item := range eil.items {
		if item != nil && item.GenericInfo.ItemType == itemType {
			matchingItems = append(matchingItems, item)
		}
	}

	return matchingItems
}

// GetWeapons returns all equipped weapons
func (eil *EquipmentItemList) GetWeapons() []*Item {
	return eil.GetEquippedItemsByType(ItemTypeWeapon)
}

// GetArmor returns all equipped armor pieces
func (eil *EquipmentItemList) GetArmor() []*Item {
	return eil.GetEquippedItemsByType(ItemTypeArmor)
}

// GetJewelry returns all equipped jewelry
func (eil *EquipmentItemList) GetJewelry() []*Item {
	eil.mutex.RLock()
	defer eil.mutex.RUnlock()

	var jewelry []*Item

	// Check ring slots
	if eil.items[EQ2LRingSlot] != nil {
		jewelry = append(jewelry, eil.items[EQ2LRingSlot])
	}
	if eil.items[EQ2RRingSlot] != nil {
		jewelry = append(jewelry, eil.items[EQ2RRingSlot])
	}

	// Check ear slots
	if eil.items[EQ2EarsSlot1] != nil {
		jewelry = append(jewelry, eil.items[EQ2EarsSlot1])
	}
	if eil.items[EQ2EarsSlot2] != nil {
		jewelry = append(jewelry, eil.items[EQ2EarsSlot2])
	}

	// Check neck slot
	if eil.items[EQ2NeckSlot] != nil {
		jewelry = append(jewelry, eil.items[EQ2NeckSlot])
	}

	// Check wrist slots
	if eil.items[EQ2LWristSlot] != nil {
		jewelry = append(jewelry, eil.items[EQ2LWristSlot])
	}
	if eil.items[EQ2RWristSlot] != nil {
		jewelry = append(jewelry, eil.items[EQ2RWristSlot])
	}

	return jewelry
}

// HasWeaponEquipped checks if any weapon is equipped
func (eil *EquipmentItemList) HasWeaponEquipped() bool {
	weapons := eil.GetWeapons()
	return len(weapons) > 0
}

// HasShieldEquipped checks if a shield is equipped
func (eil *EquipmentItemList) HasShieldEquipped() bool {
	item := eil.GetItem(EQ2SecondarySlot)
	return item != nil && item.IsShield()
}

// HasTwoHandedWeapon checks if a two-handed weapon is equipped
func (eil *EquipmentItemList) HasTwoHandedWeapon() bool {
	primaryItem := eil.GetItem(EQ2PrimarySlot)
	if primaryItem != nil && primaryItem.IsWeapon() && primaryItem.WeaponInfo != nil {
		return primaryItem.WeaponInfo.WieldType == ItemWieldTypeTwoHand
	}
	return false
}

// CanDualWield checks if dual wielding is possible with current equipment
func (eil *EquipmentItemList) CanDualWield() bool {
	primaryItem := eil.GetItem(EQ2PrimarySlot)
	secondaryItem := eil.GetItem(EQ2SecondarySlot)

	if primaryItem != nil && secondaryItem != nil {
		// Both items must be weapons that can be dual wielded
		if primaryItem.IsWeapon() && secondaryItem.IsWeapon() {
			if primaryItem.WeaponInfo != nil && secondaryItem.WeaponInfo != nil {
				return primaryItem.WeaponInfo.WieldType == ItemWieldTypeDual &&
					secondaryItem.WeaponInfo.WieldType == ItemWieldTypeDual
			}
		}
	}

	return false
}

// String returns a string representation of the equipment list
func (eil *EquipmentItemList) String() string {
	eil.mutex.RLock()
	defer eil.mutex.RUnlock()

	equippedCount := 0
	for _, item := range eil.items {
		if item != nil {
			equippedCount++
		}
	}

	return fmt.Sprintf("EquipmentItemList{Equipped: %d/%d, AppearanceType: %d}",
		equippedCount, NumSlots, eil.appearanceType)
}

func init() {
	log.Printf("Equipment item list system initialized")
}
