package items

import (
	"fmt"
	"log"
)

// NewPlayerItemList creates a new player item list
func NewPlayerItemList() *PlayerItemList {
	return &PlayerItemList{
		indexedItems:  make(map[int32]*Item),
		items:         make(map[int32]map[int8]map[int16]*Item),
		overflowItems: make([]*Item, 0),
	}
}

// SetMaxItemIndex sets and returns the maximum saved item index
func (pil *PlayerItemList) SetMaxItemIndex() int32 {
	pil.mutex.Lock()
	defer pil.mutex.Unlock()

	maxIndex := int32(0)
	for index := range pil.indexedItems {
		if index > maxIndex {
			maxIndex = index
		}
	}

	pil.maxSavedIndex = maxIndex
	return maxIndex
}

// SharedBankAddAllowed checks if an item can be added to shared bank
func (pil *PlayerItemList) SharedBankAddAllowed(item *Item) bool {
	if item == nil {
		return false
	}

	// Check item flags that prevent shared bank storage
	if item.CheckFlag(NoTrade) || item.CheckFlag(Attuned) || item.CheckFlag(LoreEquip) {
		return false
	}

	// Check heirloom flag
	if item.CheckFlag2(Heirloom) {
		return true // Heirloom items can go in shared bank
	}

	return true
}

// GetItemsFromBagID gets all items from a specific bag
func (pil *PlayerItemList) GetItemsFromBagID(bagID int32) []*Item {
	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	var bagItems []*Item

	if bagMap, exists := pil.items[bagID]; exists {
		for _, slotMap := range bagMap {
			for _, item := range slotMap {
				if item != nil {
					bagItems = append(bagItems, item)
				}
			}
		}
	}

	return bagItems
}

// GetItemsInBag gets all items inside a bag item
func (pil *PlayerItemList) GetItemsInBag(bag *Item) []*Item {
	if bag == nil || !bag.IsBag() {
		return nil
	}

	return pil.GetItemsFromBagID(bag.Details.BagID)
}

// GetBag gets a bag from an inventory slot
func (pil *PlayerItemList) GetBag(inventorySlot int8, lock bool) *Item {
	if lock {
		pil.mutex.RLock()
		defer pil.mutex.RUnlock()
	}

	// Check main inventory slots
	for bagID := int32(0); bagID < NumInvSlots; bagID++ {
		if bagMap, exists := pil.items[bagID]; exists {
			if slot0Map, exists := bagMap[0]; exists {
				if item, exists := slot0Map[int16(inventorySlot)]; exists && item != nil && item.IsBag() {
					return item
				}
			}
		}
	}

	return nil
}

// HasItem checks if the player has a specific item
func (pil *PlayerItemList) HasItem(itemID int32, includeBank bool) bool {
	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	for bagID, bagMap := range pil.items {
		// Skip bank slots if not including bank
		if !includeBank && bagID >= BankSlot1 && bagID <= BankSlot8 {
			continue
		}

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

	return false
}

// GetItemFromIndex gets an item by its index
func (pil *PlayerItemList) GetItemFromIndex(index int32) *Item {
	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	if item, exists := pil.indexedItems[index]; exists {
		return item
	}

	return nil
}

// MoveItem moves an item to a new location
func (pil *PlayerItemList) MoveItem(item *Item, invSlot int32, slot int16, appearanceType int8, eraseOld bool) {
	if item == nil {
		return
	}

	pil.mutex.Lock()
	defer pil.mutex.Unlock()

	// Remove from old location if requested
	if eraseOld {
		pil.eraseItemInternal(item)
	}

	// Update item location
	item.Details.InvSlotID = invSlot
	item.Details.SlotID = slot
	item.Details.AppearanceType = int16(appearanceType)

	// Add to new location
	pil.addItemToLocationInternal(item, invSlot, appearanceType, slot)
}

// MoveItemByIndex moves an item by index to a new location
func (pil *PlayerItemList) MoveItemByIndex(toBagID int32, fromIndex int16, to int8, appearanceType int8, charges int8) bool {
	pil.mutex.Lock()
	defer pil.mutex.Unlock()

	// Find item by index
	var item *Item
	for _, bagMap := range pil.items {
		for _, slotMap := range bagMap {
			for _, foundItem := range slotMap {
				if foundItem != nil && foundItem.Details.NewIndex == fromIndex {
					item = foundItem
					break
				}
			}
			if item != nil {
				break
			}
		}
		if item != nil {
			break
		}
	}

	if item == nil {
		return false
	}

	// Remove from old location
	pil.eraseItemInternal(item)

	// Update item properties
	item.Details.BagID = toBagID
	item.Details.SlotID = int16(to)
	item.Details.AppearanceType = int16(appearanceType)
	if charges > 0 {
		item.Details.Count = int16(charges)
	}

	// Add to new location
	pil.addItemToLocationInternal(item, toBagID, appearanceType, int16(to))

	return true
}

// EraseItem removes an item from the inventory
func (pil *PlayerItemList) EraseItem(item *Item) {
	if item == nil {
		return
	}

	pil.mutex.Lock()
	defer pil.mutex.Unlock()

	pil.eraseItemInternal(item)
}

// eraseItemInternal removes an item from internal storage (assumes lock is held)
func (pil *PlayerItemList) eraseItemInternal(item *Item) {
	if item == nil {
		return
	}

	// Remove from indexed items
	for index, indexedItem := range pil.indexedItems {
		if indexedItem == item {
			delete(pil.indexedItems, index)
			break
		}
	}

	// Remove from location-based storage
	if bagMap, exists := pil.items[item.Details.BagID]; exists {
		if slotMap, exists := bagMap[int8(item.Details.AppearanceType)]; exists {
			delete(slotMap, item.Details.SlotID)

			// Clean up empty maps
			if len(slotMap) == 0 {
				delete(bagMap, int8(item.Details.AppearanceType))
				if len(bagMap) == 0 {
					delete(pil.items, item.Details.BagID)
				}
			}
		}
	}

	// Remove from overflow items
	for i, overflowItem := range pil.overflowItems {
		if overflowItem == item {
			pil.overflowItems = append(pil.overflowItems[:i], pil.overflowItems[i+1:]...)
			break
		}
	}
}

// GetItemFromUniqueID gets an item by its unique ID
func (pil *PlayerItemList) GetItemFromUniqueID(uniqueID int32, includeBank bool, lock bool) *Item {
	if lock {
		pil.mutex.RLock()
		defer pil.mutex.RUnlock()
	}

	for bagID, bagMap := range pil.items {
		// Skip bank slots if not including bank
		if !includeBank && bagID >= BankSlot1 && bagID <= BankSlot8 {
			continue
		}

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

	// Check overflow items
	for _, item := range pil.overflowItems {
		if item != nil && int32(item.Details.UniqueID) == uniqueID {
			return item
		}
	}

	return nil
}

// GetItemFromID gets an item by its template ID
func (pil *PlayerItemList) GetItemFromID(itemID int32, count int8, includeBank bool, lock bool) *Item {
	if lock {
		pil.mutex.RLock()
		defer pil.mutex.RUnlock()
	}

	for bagID, bagMap := range pil.items {
		// Skip bank slots if not including bank
		if !includeBank && bagID >= BankSlot1 && bagID <= BankSlot8 {
			continue
		}

		for _, slotMap := range bagMap {
			for _, item := range slotMap {
				if item != nil && item.Details.ItemID == itemID {
					if count == 0 || item.Details.Count >= int16(count) {
						return item
					}
				}
			}
		}
	}

	return nil
}

// GetAllStackCountItemFromID gets the total count of all stacks of an item
func (pil *PlayerItemList) GetAllStackCountItemFromID(itemID int32, count int8, includeBank bool, lock bool) int32 {
	if lock {
		pil.mutex.RLock()
		defer pil.mutex.RUnlock()
	}

	totalCount := int32(0)

	for bagID, bagMap := range pil.items {
		// Skip bank slots if not including bank
		if !includeBank && bagID >= BankSlot1 && bagID <= BankSlot8 {
			continue
		}

		for _, slotMap := range bagMap {
			for _, item := range slotMap {
				if item != nil && item.Details.ItemID == itemID {
					totalCount += int32(item.Details.Count)
				}
			}
		}
	}

	return totalCount
}

// AssignItemToFreeSlot assigns an item to the first available free slot
func (pil *PlayerItemList) AssignItemToFreeSlot(item *Item, inventoryOnly bool) bool {
	if item == nil {
		return false
	}

	pil.mutex.Lock()
	defer pil.mutex.Unlock()

	var bagID int32
	var slot int16

	if pil.getFirstFreeSlotInternal(&bagID, &slot, inventoryOnly) {
		item.Details.BagID = bagID
		item.Details.SlotID = slot
		item.Details.AppearanceType = BaseEquipment

		pil.addItemToLocationInternal(item, bagID, BaseEquipment, slot)
		return true
	}

	return false
}

// GetNumberOfFreeSlots returns the number of free inventory slots
func (pil *PlayerItemList) GetNumberOfFreeSlots() int16 {
	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	freeSlots := int16(0)

	// Check main inventory slots
	for bagID := int32(0); bagID < NumInvSlots; bagID++ {
		bag := pil.GetBag(int8(bagID), false)
		if bag != nil && bag.BagInfo != nil {
			// Count free slots in this bag
			usedSlots := 0
			if bagMap, exists := pil.items[bagID]; exists {
				for _, slotMap := range bagMap {
					usedSlots += len(slotMap)
				}
			}
			freeSlots += int16(bag.BagInfo.NumSlots) - int16(usedSlots)
		}
	}

	return freeSlots
}

// GetNumberOfItems returns the total number of items in inventory
func (pil *PlayerItemList) GetNumberOfItems() int16 {
	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	itemCount := int16(0)

	for _, bagMap := range pil.items {
		for _, slotMap := range bagMap {
			itemCount += int16(len(slotMap))
		}
	}

	return itemCount
}

// GetWeight returns the total weight of all items
func (pil *PlayerItemList) GetWeight() int32 {
	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	totalWeight := int32(0)

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

	return totalWeight
}

// HasFreeSlot checks if there's at least one free slot
func (pil *PlayerItemList) HasFreeSlot() bool {
	return pil.GetNumberOfFreeSlots() > 0
}

// HasFreeBagSlot checks if there's a free bag slot in main inventory
func (pil *PlayerItemList) HasFreeBagSlot() bool {
	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	// Check main inventory bag slots
	for bagSlot := int8(0); bagSlot < NumInvSlots; bagSlot++ {
		bag := pil.GetBag(bagSlot, false)
		if bag == nil {
			return true // Empty bag slot
		}
	}

	return false
}

// DestroyItem destroys an item by index
func (pil *PlayerItemList) DestroyItem(index int16) {
	pil.mutex.Lock()
	defer pil.mutex.Unlock()

	// Find and remove item by index
	for _, bagMap := range pil.items {
		for _, slotMap := range bagMap {
			for _, item := range slotMap {
				if item != nil && item.Details.NewIndex == index {
					pil.eraseItemInternal(item)
					return
				}
			}
		}
	}
}

// CanStack checks if an item can be stacked with existing items
func (pil *PlayerItemList) CanStack(item *Item, includeBank bool) *Item {
	if item == nil {
		return nil
	}

	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	for bagID, bagMap := range pil.items {
		// Skip bank slots if not including bank
		if !includeBank && bagID >= BankSlot1 && bagID <= BankSlot8 {
			continue
		}

		for _, slotMap := range bagMap {
			for _, existingItem := range slotMap {
				if existingItem != nil &&
					existingItem.Details.ItemID == item.Details.ItemID &&
					existingItem.Details.Count < existingItem.StackCount &&
					existingItem.Details.UniqueID != item.Details.UniqueID {
					return existingItem
				}
			}
		}
	}

	return nil
}

// GetAllItemsFromID gets all items with a specific ID
func (pil *PlayerItemList) GetAllItemsFromID(itemID int32, includeBank bool, lock bool) []*Item {
	if lock {
		pil.mutex.RLock()
		defer pil.mutex.RUnlock()
	}

	var matchingItems []*Item

	for bagID, bagMap := range pil.items {
		// Skip bank slots if not including bank
		if !includeBank && bagID >= BankSlot1 && bagID <= BankSlot8 {
			continue
		}

		for _, slotMap := range bagMap {
			for _, item := range slotMap {
				if item != nil && item.Details.ItemID == itemID {
					matchingItems = append(matchingItems, item)
				}
			}
		}
	}

	return matchingItems
}

// RemoveItem removes an item from inventory
func (pil *PlayerItemList) RemoveItem(item *Item, deleteItem bool, lock bool) {
	if item == nil {
		return
	}

	if lock {
		pil.mutex.Lock()
		defer pil.mutex.Unlock()
	}

	pil.eraseItemInternal(item)

	if deleteItem {
		// Mark item for deletion
		item.NeedsDeletion = true
	}
}

// AddItem adds an item to the inventory
func (pil *PlayerItemList) AddItem(item *Item) bool {
	if item == nil {
		return false
	}

	pil.mutex.Lock()
	defer pil.mutex.Unlock()

	// Try to stack with existing items first
	stackableItem := pil.CanStack(item, false)
	if stackableItem != nil {
		// Stack with existing item
		stackableItem.Details.Count += item.Details.Count
		if stackableItem.Details.Count > stackableItem.StackCount {
			// Handle overflow
			overflow := stackableItem.Details.Count - stackableItem.StackCount
			stackableItem.Details.Count = stackableItem.StackCount
			item.Details.Count = overflow
			// Continue to add the overflow as a new item
		} else {
			return true // Successfully stacked
		}
	}

	// Try to assign to free slot
	var bagID int32
	var slot int16
	if pil.getFirstFreeSlotInternal(&bagID, &slot, true) {
		item.Details.BagID = bagID
		item.Details.SlotID = slot
		item.Details.AppearanceType = BaseEquipment

		pil.addItemToLocationInternal(item, bagID, BaseEquipment, slot)
		return true
	}

	// Add to overflow if no free slots
	return pil.AddOverflowItem(item)
}

// GetItem gets an item from a specific location
func (pil *PlayerItemList) GetItem(bagSlot int32, slot int16, appearanceType int8) *Item {
	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	if bagMap, exists := pil.items[bagSlot]; exists {
		if slotMap, exists := bagMap[appearanceType]; exists {
			if item, exists := slotMap[slot]; exists {
				return item
			}
		}
	}

	return nil
}

// GetAllItems returns all items in the inventory
func (pil *PlayerItemList) GetAllItems() map[int32]*Item {
	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	// Return a copy of indexed items
	allItems := make(map[int32]*Item)
	for index, item := range pil.indexedItems {
		allItems[index] = item
	}

	return allItems
}

// HasFreeBankSlot checks if there's a free bank slot
func (pil *PlayerItemList) HasFreeBankSlot() bool {
	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	// Check bank bag slots
	for bagSlot := int32(BankSlot1); bagSlot <= BankSlot8; bagSlot++ {
		if _, exists := pil.items[bagSlot]; !exists {
			return true
		}
	}

	return false
}

// FindFreeBankSlot finds the first free bank slot
func (pil *PlayerItemList) FindFreeBankSlot() int8 {
	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	for bagSlot := int32(BankSlot1); bagSlot <= BankSlot8; bagSlot++ {
		if _, exists := pil.items[bagSlot]; !exists {
			return int8(bagSlot - BankSlot1)
		}
	}

	return -1
}

// GetFirstFreeSlot gets the first free slot coordinates
func (pil *PlayerItemList) GetFirstFreeSlot(bagID *int32, slot *int16) bool {
	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	return pil.getFirstFreeSlotInternal(bagID, slot, true)
}

// getFirstFreeSlotInternal gets the first free slot (assumes lock is held)
func (pil *PlayerItemList) getFirstFreeSlotInternal(bagID *int32, slot *int16, inventoryOnly bool) bool {
	// Check main inventory bags first
	for bagSlotID := int32(0); bagSlotID < NumInvSlots; bagSlotID++ {
		bag := pil.GetBag(int8(bagSlotID), false)
		if bag != nil && bag.BagInfo != nil {
			// Check slots in this bag
			bagMap := pil.items[bagSlotID]
			if bagMap == nil {
				bagMap = make(map[int8]map[int16]*Item)
				pil.items[bagSlotID] = bagMap
			}

			slotMap := bagMap[BaseEquipment]
			if slotMap == nil {
				slotMap = make(map[int16]*Item)
				bagMap[BaseEquipment] = slotMap
			}

			for slotID := int16(0); slotID < int16(bag.BagInfo.NumSlots); slotID++ {
				if _, exists := slotMap[slotID]; !exists {
					*bagID = bagSlotID
					*slot = slotID
					return true
				}
			}
		}
	}

	// Check bank bags if not inventory only
	if !inventoryOnly {
		for bagSlotID := int32(BankSlot1); bagSlotID <= BankSlot8; bagSlotID++ {
			bag := pil.GetBankBag(int8(bagSlotID-BankSlot1), false)
			if bag != nil && bag.BagInfo != nil {
				bagMap := pil.items[bagSlotID]
				if bagMap == nil {
					bagMap = make(map[int8]map[int16]*Item)
					pil.items[bagSlotID] = bagMap
				}

				slotMap := bagMap[BaseEquipment]
				if slotMap == nil {
					slotMap = make(map[int16]*Item)
					bagMap[BaseEquipment] = slotMap
				}

				for slotID := int16(0); slotID < int16(bag.BagInfo.NumSlots); slotID++ {
					if _, exists := slotMap[slotID]; !exists {
						*bagID = bagSlotID
						*slot = slotID
						return true
					}
				}
			}
		}
	}

	return false
}

// GetFirstFreeBankSlot gets the first free bank slot coordinates
func (pil *PlayerItemList) GetFirstFreeBankSlot(bagID *int32, slot *int16) bool {
	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	return pil.getFirstFreeSlotInternal(bagID, slot, false)
}

// GetBankBag gets a bank bag by slot
func (pil *PlayerItemList) GetBankBag(inventorySlot int8, lock bool) *Item {
	if lock {
		pil.mutex.RLock()
		defer pil.mutex.RUnlock()
	}

	bagID := int32(BankSlot1) + int32(inventorySlot)
	if bagMap, exists := pil.items[bagID]; exists {
		if slotMap, exists := bagMap[0]; exists {
			if item, exists := slotMap[0]; exists && item != nil && item.IsBag() {
				return item
			}
		}
	}

	return nil
}

// AddOverflowItem adds an item to overflow storage
func (pil *PlayerItemList) AddOverflowItem(item *Item) bool {
	if item == nil {
		return false
	}

	pil.mutex.Lock()
	defer pil.mutex.Unlock()

	pil.overflowItems = append(pil.overflowItems, item)
	return true
}

// GetOverflowItem gets the first overflow item
func (pil *PlayerItemList) GetOverflowItem() *Item {
	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	if len(pil.overflowItems) > 0 {
		return pil.overflowItems[0]
	}

	return nil
}

// RemoveOverflowItem removes an item from overflow storage
func (pil *PlayerItemList) RemoveOverflowItem(item *Item) {
	if item == nil {
		return
	}

	pil.mutex.Lock()
	defer pil.mutex.Unlock()

	for i, overflowItem := range pil.overflowItems {
		if overflowItem == item {
			pil.overflowItems = append(pil.overflowItems[:i], pil.overflowItems[i+1:]...)
			break
		}
	}
}

// GetOverflowItemList returns all overflow items
func (pil *PlayerItemList) GetOverflowItemList() []*Item {
	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	// Return a copy of the overflow list
	overflowCopy := make([]*Item, len(pil.overflowItems))
	copy(overflowCopy, pil.overflowItems)

	return overflowCopy
}

// ResetPackets resets packet data
func (pil *PlayerItemList) ResetPackets() {
	pil.mutex.Lock()
	defer pil.mutex.Unlock()

	pil.xorPacket = nil
	pil.origPacket = nil
	pil.packetCount = 0
}

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

	if lockMutex {
		pil.mutex.RLock()
		defer pil.mutex.RUnlock()
	}

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

		for _, bagMap := range pil.items {
			for _, slotMap := range bagMap {
				for _, existingItem := range slotMap {
					if existingItem != nil && existingItem.Details.ItemID == item.Details.ItemID {
						stackCount++
					}
				}
			}
		}

		if loreStackCount != nil {
			*loreStackCount = stackCount
		}

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

	return 0 // No conflict
}

// GetItemCountInBag returns the number of items in a bag
func (pil *PlayerItemList) GetItemCountInBag(bag *Item) int32 {
	if bag == nil || !bag.IsBag() {
		return 0
	}

	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	count := int32(0)
	if bagMap, exists := pil.items[bag.Details.BagID]; exists {
		for _, slotMap := range bagMap {
			count += int32(len(slotMap))
		}
	}

	return count
}

// GetFirstNewItem gets the index of the first new item
func (pil *PlayerItemList) GetFirstNewItem() int16 {
	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	for _, bagMap := range pil.items {
		for _, slotMap := range bagMap {
			for _, item := range slotMap {
				if item != nil && item.Details.NewItem {
					return item.Details.NewIndex
				}
			}
		}
	}

	return -1
}

// GetNewItemByIndex gets a new item by its index
func (pil *PlayerItemList) GetNewItemByIndex(index int16) int16 {
	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	for _, bagMap := range pil.items {
		for _, slotMap := range bagMap {
			for _, item := range slotMap {
				if item != nil && item.Details.NewItem && item.Details.NewIndex == index {
					return index
				}
			}
		}
	}

	return -1
}

// addItemToLocationInternal adds an item to a specific location (assumes lock is held)
func (pil *PlayerItemList) addItemToLocationInternal(item *Item, bagID int32, appearanceType int8, slot int16) {
	if item == nil {
		return
	}

	// Ensure bag map exists
	if pil.items[bagID] == nil {
		pil.items[bagID] = make(map[int8]map[int16]*Item)
	}

	// Ensure appearance type map exists
	if pil.items[bagID][appearanceType] == nil {
		pil.items[bagID][appearanceType] = make(map[int16]*Item)
	}

	// Add item to location
	pil.items[bagID][appearanceType][slot] = item

	// Add to indexed items
	if item.Details.Index > 0 {
		pil.indexedItems[int32(item.Details.Index)] = item
	}
}

// IsItemInSlotType checks if an item is in a specific slot type
func (pil *PlayerItemList) IsItemInSlotType(item *Item, slotType InventorySlotType, lockItems bool) bool {
	if item == nil {
		return false
	}

	if lockItems {
		pil.mutex.RLock()
		defer pil.mutex.RUnlock()
	}

	bagID := item.Details.BagID

	switch slotType {
	case BaseInventory:
		return bagID >= 0 && bagID < NumInvSlots
	case Bank:
		return bagID >= BankSlot1 && bagID <= BankSlot8
	case SharedBank:
		// TODO: Implement shared bank slot detection
		return false
	case Overflow:
		// Check if item is in overflow list
		for _, overflowItem := range pil.overflowItems {
			if overflowItem == item {
				return true
			}
		}
		return false
	}

	return false
}

// String returns a string representation of the player item list
func (pil *PlayerItemList) String() string {
	pil.mutex.RLock()
	defer pil.mutex.RUnlock()

	return fmt.Sprintf("PlayerItemList{Items: %d, Overflow: %d, MaxIndex: %d}",
		len(pil.indexedItems), len(pil.overflowItems), pil.maxSavedIndex)
}

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