local ____lualib = require("lualib_bundle")
local __TS__ArrayFind = ____lualib.__TS__ArrayFind
local __TS__ArraySome = ____lualib.__TS__ArraySome
local __TS__ObjectKeys = ____lualib.__TS__ObjectKeys
local ____exports = {}
local ____isaac_2Dtypescript_2Ddefinitions = require("isaac-typescript-definitions")
local ActiveSlot = ____isaac_2Dtypescript_2Ddefinitions.ActiveSlot
local CardType = ____isaac_2Dtypescript_2Ddefinitions.CardType
local CollectibleType = ____isaac_2Dtypescript_2Ddefinitions.CollectibleType
local PillColor = ____isaac_2Dtypescript_2Ddefinitions.PillColor
local PlayerType = ____isaac_2Dtypescript_2Ddefinitions.PlayerType
local ____cachedEnumValues = require("cachedEnumValues")
local POCKET_ITEM_SLOT_VALUES = ____cachedEnumValues.POCKET_ITEM_SLOT_VALUES
local ____PocketItemType = require("enums.PocketItemType")
local PocketItemType = ____PocketItemType.PocketItemType
local ____players = require("functions.players")
local isCharacter = ____players.isCharacter
--- Use this helper function as a workaround for the `EntityPlayer.GetPocketItem` method not working
-- correctly.
-- 
-- Note that due to API limitations, there is no way to determine the location of a Dice Bag trinket
-- dice. Furthermore, when the player has a Dice Bag trinket dice and a pocket active at the same
-- time, there is no way to determine the location of the pocket active item. If this function
-- cannot determine the identity of a particular slot, it will mark the type of the slot as
-- `PocketItemType.UNDETERMINABLE`.
function ____exports.getPocketItems(self, player)
    local pocketItem = player:GetActiveItem(ActiveSlot.POCKET)
    local hasPocketItem = pocketItem ~= CollectibleType.NULL
    local pocketItem2 = player:GetActiveItem(ActiveSlot.POCKET_SINGLE_USE)
    local hasPocketItem2 = pocketItem2 ~= CollectibleType.NULL
    local maxPocketItems = player:GetMaxPocketItems()
    local pocketItems = {}
    local pocketItemIdentified = false
    local pocketItem2Identified = false
    for ____, slot in ipairs(POCKET_ITEM_SLOT_VALUES) do
        local cardType = player:GetCard(slot)
        local pillColor = player:GetPill(slot)
        if cardType ~= CardType.NULL then
            pocketItems[#pocketItems + 1] = {slot = slot, type = PocketItemType.CARD, subType = cardType}
        elseif pillColor ~= PillColor.NULL then
            pocketItems[#pocketItems + 1] = {slot = slot, type = PocketItemType.PILL, subType = pillColor}
        elseif hasPocketItem and not hasPocketItem2 and not pocketItemIdentified then
            pocketItemIdentified = true
            pocketItems[#pocketItems + 1] = {slot = slot, type = PocketItemType.ACTIVE_ITEM, subType = pocketItem}
        elseif not hasPocketItem and hasPocketItem2 and not pocketItem2Identified then
            pocketItem2Identified = true
            pocketItems[#pocketItems + 1] = {slot = slot, type = PocketItemType.DICE_BAG_DICE, subType = pocketItem2}
        elseif hasPocketItem and hasPocketItem2 then
            pocketItems[#pocketItems + 1] = {slot = slot, type = PocketItemType.UNDETERMINABLE, subType = 0}
        else
            pocketItems[#pocketItems + 1] = {slot = slot, type = PocketItemType.EMPTY, subType = 0}
        end
        if slot + 1 == maxPocketItems then
            break
        end
    end
    return pocketItems
end
--- Helper function to get the `PocketItemSlot` that the player's pocket active collectible item is
-- in, if any. Returns undefined if the player does not have a pocket active item.
function ____exports.getActivePocketItemSlot(self, player)
    local pocketItems = ____exports.getPocketItems(nil, player)
    for ____, pocketItem in ipairs(pocketItems) do
        if pocketItem.type == PocketItemType.ACTIVE_ITEM then
            return pocketItem.slot
        end
    end
    return nil
end
--- Helper item to get the first card that a player is holding in their pocket item slots.
function ____exports.getFirstCard(self, player)
    local pocketItems = ____exports.getPocketItems(nil, player)
    return __TS__ArrayFind(
        pocketItems,
        function(____, pocketItem) return pocketItem.type == PocketItemType.CARD end
    )
end
--- Helper item to get the first card or pill that a player is holding in their pocket item slots.
function ____exports.getFirstCardOrPill(self, player)
    local pocketItems = ____exports.getPocketItems(nil, player)
    return __TS__ArrayFind(
        pocketItems,
        function(____, pocketItem) return pocketItem.type == PocketItemType.CARD or pocketItem.type == PocketItemType.PILL end
    )
end
--- Helper item to get the first pill that a player is holding in their pocket item slots.
function ____exports.getFirstPill(self, player)
    local pocketItems = ____exports.getPocketItems(nil, player)
    return __TS__ArrayFind(
        pocketItems,
        function(____, pocketItem) return pocketItem.type == PocketItemType.PILL end
    )
end
--- Returns whether the player can hold an additional pocket item, beyond what they are currently
-- carrying. This takes into account items that modify the max number of pocket items, like Starter
-- Deck.
-- 
-- If the player is the Tainted Soul, this always returns false, since that character cannot pick up
-- items. (Only Tainted Forgotten can pick up items.)
function ____exports.hasOpenPocketItemSlot(self, player)
    if isCharacter(nil, player, PlayerType.SOUL_B) then
        return false
    end
    local pocketItems = ____exports.getPocketItems(nil, player)
    return __TS__ArraySome(
        pocketItems,
        function(____, pocketItem) return pocketItem.type == PocketItemType.EMPTY end
    )
end
--- Helper function to determine whether the player's "active" pocket item slot is set to their
-- pocket active item.
function ____exports.isFirstSlotPocketActiveItem(self, player)
    local pocketItems = ____exports.getPocketItems(nil, player)
    local firstPocketItem = pocketItems[1]
    if firstPocketItem == nil then
        return false
    end
    return firstPocketItem.type == PocketItemType.ACTIVE_ITEM
end
--- Helper function to see if two sets of pocket item descriptions are identical.
function ____exports.pocketItemsEquals(self, pocketItems1, pocketItems2)
    if #pocketItems1 ~= #pocketItems2 then
        return false
    end
    do
        local i = 0
        while i < #pocketItems1 do
            local pocketItem1 = pocketItems1[i + 1]
            local pocketItem2 = pocketItems2[i + 1]
            local keys = __TS__ObjectKeys(pocketItem1)
            for ____, key in ipairs(keys) do
                if pocketItem1[key] ~= pocketItem2[key] then
                    return false
                end
            end
            i = i + 1
        end
    end
    return true
end
return ____exports
