local ____lualib = require("lualib_bundle")
local __TS__New = ____lualib.__TS__New
local Map = ____lualib.Map
local __TS__Class = ____lualib.__TS__Class
local __TS__ClassExtends = ____lualib.__TS__ClassExtends
local Set = ____lualib.Set
local __TS__Spread = ____lualib.__TS__Spread
local __TS__SparseArrayNew = ____lualib.__TS__SparseArrayNew
local __TS__SparseArrayPush = ____lualib.__TS__SparseArrayPush
local __TS__SparseArraySpread = ____lualib.__TS__SparseArraySpread
local __TS__Iterator = ____lualib.__TS__Iterator
local __TS__ArraySort = ____lualib.__TS__ArraySort
local ____exports = {}
local ____isaac_2Dtypescript_2Ddefinitions = require("isaac-typescript-definitions")
local CollectibleType = ____isaac_2Dtypescript_2Ddefinitions.CollectibleType
local DamageFlag = ____isaac_2Dtypescript_2Ddefinitions.DamageFlag
local ItemType = ____isaac_2Dtypescript_2Ddefinitions.ItemType
local ModCallback = ____isaac_2Dtypescript_2Ddefinitions.ModCallback
local PlayerType = ____isaac_2Dtypescript_2Ddefinitions.PlayerType
local ____cachedEnumValues = require("cachedEnumValues")
local ACTIVE_SLOT_VALUES = ____cachedEnumValues.ACTIVE_SLOT_VALUES
local ____ISCFeature = require("enums.ISCFeature")
local ISCFeature = ____ISCFeature.ISCFeature
local ____ModCallbackCustom = require("enums.ModCallbackCustom")
local ModCallbackCustom = ____ModCallbackCustom.ModCallbackCustom
local ____array = require("functions.array")
local arrayEquals = ____array.arrayEquals
local ____flag = require("functions.flag")
local hasFlag = ____flag.hasFlag
local ____playerDataStructures = require("functions.playerDataStructures")
local defaultMapGetPlayer = ____playerDataStructures.defaultMapGetPlayer
local mapSetPlayer = ____playerDataStructures.mapSetPlayer
local ____players = require("functions.players")
local getPlayerFromPtr = ____players.getPlayerFromPtr
local ____sort = require("functions.sort")
local sortNormal = ____sort.sortNormal
local ____utils = require("functions.utils")
local ____repeat = ____utils["repeat"]
local ____DefaultMap = require("classes.DefaultMap")
local DefaultMap = ____DefaultMap.DefaultMap
local ____Feature = require("classes.private.Feature")
local Feature = ____Feature.Feature
local v = {run = {
    playersCollectibleCount = __TS__New(DefaultMap, 0),
    playersCollectibleMap = __TS__New(
        DefaultMap,
        function() return __TS__New(Map) end
    ),
    playersActiveItemMap = __TS__New(
        DefaultMap,
        function() return __TS__New(Map) end
    )
}}
____exports.PlayerCollectibleDetection = __TS__Class()
local PlayerCollectibleDetection = ____exports.PlayerCollectibleDetection
PlayerCollectibleDetection.name = "PlayerCollectibleDetection"
__TS__ClassExtends(PlayerCollectibleDetection, Feature)
function PlayerCollectibleDetection.prototype.____constructor(self, postPlayerCollectibleAdded, postPlayerCollectibleRemoved, moddedElementSets, runInNFrames)
    Feature.prototype.____constructor(self)
    self.v = v
    self.postUseItemD4 = function(____, _collectibleType, _rng, player)
        self:updateCollectibleMapAndFire(player, nil)
        return nil
    end
    self.entityTakeDmgPlayer = function(____, player, _amount, damageFlags, _source, _countdownFrames)
        if hasFlag(nil, damageFlags, DamageFlag.FAKE) then
            return nil
        end
        local character = player:GetPlayerType()
        if character ~= PlayerType.EDEN_B then
            return nil
        end
        local entityPtr = EntityPtr(player)
        self.runInNFrames:runNextGameFrame(function()
            local futurePlayer = getPlayerFromPtr(nil, entityPtr)
            if futurePlayer ~= nil then
                self:updateCollectibleMapAndFire(player, nil)
            end
        end)
        return nil
    end
    self.postItemPickup = function(____, player, pickingUpItem)
        if pickingUpItem.itemType == ItemType.TRINKET or pickingUpItem.itemType == ItemType.NULL then
            return
        end
        local newCollectibleCount = player:GetCollectibleCount()
        mapSetPlayer(nil, v.run.playersCollectibleCount, player, newCollectibleCount)
        self:updateCollectibleMapAndFire(player, 1)
    end
    self.postPEffectUpdateReordered = function(____, player)
        local oldCollectibleCount = defaultMapGetPlayer(nil, v.run.playersCollectibleCount, player)
        local newCollectibleCount = player:GetCollectibleCount()
        mapSetPlayer(nil, v.run.playersCollectibleCount, player, newCollectibleCount)
        local difference = newCollectibleCount - oldCollectibleCount
        if difference > 0 then
            self:updateCollectibleMapAndFire(player, difference)
        elseif difference < 0 then
            self:updateCollectibleMapAndFire(player, difference * -1)
        elseif difference == 0 then
            self:checkActiveItemsChanged(player)
        end
    end
    self.featuresUsed = {ISCFeature.MODDED_ELEMENT_SETS, ISCFeature.RUN_IN_N_FRAMES}
    self.callbacksUsed = {{ModCallback.POST_USE_ITEM, self.postUseItemD4, {CollectibleType.D4}}}
    self.customCallbacksUsed = {{ModCallbackCustom.ENTITY_TAKE_DMG_PLAYER, self.entityTakeDmgPlayer}, {ModCallbackCustom.POST_ITEM_PICKUP, self.postItemPickup}, {ModCallbackCustom.POST_PEFFECT_UPDATE_REORDERED, self.postPEffectUpdateReordered}}
    self.postPlayerCollectibleAdded = postPlayerCollectibleAdded
    self.postPlayerCollectibleRemoved = postPlayerCollectibleRemoved
    self.moddedElementSets = moddedElementSets
    self.runInNFrames = runInNFrames
end
function PlayerCollectibleDetection.prototype.updateCollectibleMapAndFire(self, player, numCollectiblesChanged)
    local oldCollectibleMap = defaultMapGetPlayer(nil, v.run.playersCollectibleMap, player)
    local newCollectibleMap = self.moddedElementSets:getPlayerCollectibleMap(player)
    mapSetPlayer(nil, v.run.playersCollectibleMap, player, newCollectibleMap)
    local ____Set_1 = Set
    local ____array_0 = __TS__SparseArrayNew(__TS__Spread(oldCollectibleMap:keys()))
    __TS__SparseArrayPush(
        ____array_0,
        __TS__Spread(newCollectibleMap:keys())
    )
    local collectibleTypesSet = __TS__New(
        ____Set_1,
        {__TS__SparseArraySpread(____array_0)}
    )
    local numFired = 0
    for ____, collectibleType in __TS__Iterator(collectibleTypesSet) do
        local oldNum = oldCollectibleMap:get(collectibleType) or 0
        local newNum = newCollectibleMap:get(collectibleType) or 0
        local difference = newNum - oldNum
        local increased = difference > 0
        local absoluteDifference = math.abs(difference)
        ____repeat(
            nil,
            absoluteDifference,
            function()
                if increased then
                    self.postPlayerCollectibleAdded:fire(player, collectibleType)
                else
                    self.postPlayerCollectibleRemoved:fire(player, collectibleType)
                end
                numFired = numFired + 1
            end
        )
        if numFired == numCollectiblesChanged then
            return
        end
    end
end
function PlayerCollectibleDetection.prototype.checkActiveItemsChanged(self, player)
    local activeItemMap = defaultMapGetPlayer(nil, v.run.playersActiveItemMap, player)
    local oldCollectibleTypes = {}
    local newCollectibleTypes = {}
    for ____, activeSlot in ipairs(ACTIVE_SLOT_VALUES) do
        local oldCollectibleType = activeItemMap:get(activeSlot) or CollectibleType.NULL
        local newCollectibleType = player:GetActiveItem(activeSlot)
        activeItemMap:set(activeSlot, newCollectibleType)
        oldCollectibleTypes[#oldCollectibleTypes + 1] = oldCollectibleType
        newCollectibleTypes[#newCollectibleTypes + 1] = newCollectibleType
    end
    __TS__ArraySort(oldCollectibleTypes, sortNormal)
    __TS__ArraySort(newCollectibleTypes, sortNormal)
    if not arrayEquals(nil, oldCollectibleTypes, newCollectibleTypes) then
        self:updateCollectibleMapAndFire(player, nil)
    end
end
return ____exports
