local ____lualib = require("lualib_bundle")
local __TS__New = ____lualib.__TS__New
local __TS__ArrayEntries = ____lualib.__TS__ArrayEntries
local __TS__Iterator = ____lualib.__TS__Iterator
local __TS__StringTrim = ____lualib.__TS__StringTrim
local __TS__StringSplit = ____lualib.__TS__StringSplit
local ____exports = {}
local getEntityLogLine, getBombVariantName, getEffectVariantName, getFamiliarVariantName, getKnifeVariantName, getLaserVariantName, getEntityTypeName, getPickupVariantName, getPlayerVariantName, getProjectileVariantName, getTearVariantName, getGridEntityLogLine
local ____isaac_2Dtypescript_2Ddefinitions = require("isaac-typescript-definitions")
local BombVariant = ____isaac_2Dtypescript_2Ddefinitions.BombVariant
local EffectVariant = ____isaac_2Dtypescript_2Ddefinitions.EffectVariant
local EntityType = ____isaac_2Dtypescript_2Ddefinitions.EntityType
local FamiliarVariant = ____isaac_2Dtypescript_2Ddefinitions.FamiliarVariant
local GridEntityType = ____isaac_2Dtypescript_2Ddefinitions.GridEntityType
local KnifeVariant = ____isaac_2Dtypescript_2Ddefinitions.KnifeVariant
local LaserVariant = ____isaac_2Dtypescript_2Ddefinitions.LaserVariant
local PickupVariant = ____isaac_2Dtypescript_2Ddefinitions.PickupVariant
local PlayerVariant = ____isaac_2Dtypescript_2Ddefinitions.PlayerVariant
local ProjectileVariant = ____isaac_2Dtypescript_2Ddefinitions.ProjectileVariant
local TearVariant = ____isaac_2Dtypescript_2Ddefinitions.TearVariant
local ____ReadonlySet = require("types.ReadonlySet")
local ReadonlySet = ____ReadonlySet.ReadonlySet
local ____entities = require("functions.entities")
local getEntities = ____entities.getEntities
local getEntityFromPtrHash = ____entities.getEntityFromPtrHash
local getEntityID = ____entities.getEntityID
local ____gridEntities = require("functions.gridEntities")
local getGridEntities = ____gridEntities.getGridEntities
local getGridEntityID = ____gridEntities.getGridEntityID
local ____log = require("functions.log")
local log = ____log.log
--- Helper function to log information about a specific entity.
function ____exports.logEntity(entity)
    local msg = getEntityLogLine(entity)
    log(msg)
end
function getEntityLogLine(entity, num)
    local msg = num == nil and "" or tostring(num) .. ") "
    msg = msg .. getEntityID(nil, entity)
    local bomb = entity:ToBomb()
    if bomb ~= nil then
        msg = msg .. (" (bomb - " .. getBombVariantName(nil, bomb)) .. ")"
    end
    local effect = entity:ToEffect()
    if effect ~= nil then
        msg = msg .. (((" (effect - " .. getEffectVariantName(nil, effect)) .. ") (State: ") .. tostring(effect.State)) .. ")"
    end
    local familiar = entity:ToFamiliar()
    if familiar ~= nil then
        msg = msg .. (((" (familiar - " .. getFamiliarVariantName(nil, familiar)) .. ") (State: ") .. tostring(familiar.State)) .. ")"
    end
    local knife = entity:ToKnife()
    if knife ~= nil then
        msg = msg .. (" (knife - " .. getKnifeVariantName(nil, knife)) .. ")"
    end
    local laser = entity:ToLaser()
    if laser ~= nil then
        msg = msg .. (" (laser - " .. getLaserVariantName(nil, laser)) .. ")"
    end
    local npc = entity:ToNPC()
    if npc ~= nil then
        msg = msg .. (((" (NPC - " .. getEntityTypeName(nil, npc)) .. ") (State: ") .. tostring(npc.State)) .. ")"
    end
    local pickup = entity:ToPickup()
    if pickup ~= nil then
        msg = msg .. (((" (pickup - " .. getPickupVariantName(nil, pickup)) .. ") (State: ") .. tostring(pickup.State)) .. ")"
    end
    local player = entity:ToPlayer()
    if player ~= nil then
        msg = msg .. (" (player - " .. getPlayerVariantName(nil, player)) .. ")"
    end
    local projectile = entity:ToProjectile()
    if projectile ~= nil then
        msg = msg .. (" (projectile - " .. getProjectileVariantName(nil, projectile)) .. ")"
    end
    local tear = entity:ToTear()
    if tear ~= nil then
        msg = msg .. (" (tear - " .. getTearVariantName(nil, tear)) .. ")"
    end
    msg = msg .. "\n"
    msg = msg .. ("  - Index: " .. tostring(entity.Index)) .. "\n"
    msg = msg .. ("  - InitSeed: " .. tostring(entity.InitSeed)) .. "\n"
    msg = msg .. ("  - DropSeed: " .. tostring(entity.DropSeed)) .. "\n"
    msg = msg .. ((("  - Position: (" .. tostring(entity.Position.X)) .. ", ") .. tostring(entity.Position.Y)) .. ")\n"
    msg = msg .. ((("  - Velocity: (" .. tostring(entity.Velocity.X)) .. ", ") .. tostring(entity.Velocity.Y)) .. ")\n"
    msg = msg .. ((("  - HP: " .. tostring(entity.HitPoints)) .. " / ") .. tostring(entity.MaxHitPoints)) .. "\n"
    msg = msg .. ("  - Parent: " .. tostring(entity.Parent)) .. "\n"
    msg = msg .. ("  - Child: " .. tostring(entity.Child)) .. "\n"
    msg = msg .. ("  - SpawnerEntity: " .. tostring(entity.SpawnerEntity)) .. "\n"
    msg = msg .. ((("  - SpawnerType / SpawnerVariant: " .. tostring(entity.SpawnerType)) .. ".") .. tostring(entity.SpawnerVariant)) .. "\n"
    msg = msg .. ("  - FrameCount: " .. tostring(entity.FrameCount)) .. "\n"
    if npc ~= nil then
        msg = msg .. ("  - CanShutDoors: " .. tostring(npc.CanShutDoors)) .. "\n"
    end
    return msg
end
function getBombVariantName(self, bomb)
    local enumName = BombVariant[bomb.Variant]
    return enumName == nil and "unknown" or "BombVariant." .. enumName
end
function getEffectVariantName(self, effect)
    local enumName = EffectVariant[effect.Variant]
    return enumName == nil and "unknown" or "EffectVariant." .. enumName
end
function getFamiliarVariantName(self, familiar)
    local enumName = FamiliarVariant[familiar.Variant]
    return enumName == nil and "unknown" or "FamiliarVariant." .. enumName
end
function getKnifeVariantName(self, knife)
    local enumName = KnifeVariant[knife.Variant]
    return enumName == nil and "unknown" or "KnifeVariant." .. enumName
end
function getLaserVariantName(self, laser)
    local enumName = LaserVariant[laser.Variant]
    return enumName == nil and "unknown" or "LaserVariant." .. enumName
end
function getEntityTypeName(self, npc)
    local enumName = EntityType[npc.Type]
    return enumName == nil and "unknown" or "EntityType." .. enumName
end
function getPickupVariantName(self, pickup)
    local enumName = PickupVariant[pickup.Variant]
    return enumName == nil and "unknown" or "PickupVariant." .. enumName
end
function getPlayerVariantName(self, player)
    local enumName = PlayerVariant[player.Variant]
    return enumName == nil and "unknown" or "PlayerVariant." .. enumName
end
function getProjectileVariantName(self, projectile)
    local enumName = ProjectileVariant[projectile.Variant]
    return enumName == nil and "unknown" or "ProjectileVariant." .. enumName
end
function getTearVariantName(self, tear)
    local enumName = TearVariant[tear.Variant]
    return enumName == nil and "unknown" or "TearVariant." .. enumName
end
--- Helper function for log information about a specific grid entity.
function ____exports.logGridEntity(gridEntity)
    local msg = getGridEntityLogLine(gridEntity)
    log(msg)
end
function getGridEntityLogLine(gridEntity, num)
    local gridEntityDesc = gridEntity:GetSaveState()
    local msg = num == nil and "" or tostring(num) .. ") "
    msg = msg .. getGridEntityID(nil, gridEntity)
    local door = gridEntity:ToDoor()
    if door ~= nil then
        msg = msg .. " (door)"
    end
    local pit = gridEntity:ToPit()
    if pit ~= nil then
        msg = msg .. " (pit)"
    end
    local poop = gridEntity:ToPoop()
    if poop ~= nil then
        msg = msg .. " (poop)"
    end
    local pressurePlate = gridEntity:ToPressurePlate()
    if pressurePlate ~= nil then
        msg = msg .. " (pressurePlate)"
    end
    local rock = gridEntity:ToRock()
    if rock ~= nil then
        msg = msg .. " (rock)"
    end
    local spikes = gridEntity:ToSpikes()
    if spikes ~= nil then
        msg = msg .. " (spikes)"
    end
    local tnt = gridEntity:ToTNT()
    if tnt ~= nil then
        msg = msg .. " (TNT)"
    end
    msg = msg .. ("  - State: " .. tostring(gridEntity.State)) .. "\n"
    msg = msg .. ("  - VarData: " .. tostring(gridEntity.VarData)) .. "\n"
    msg = msg .. ((("  - Position: (" .. tostring(gridEntity.Position.X)) .. ", ") .. tostring(gridEntity.Position.Y)) .. ")\n"
    msg = msg .. ("  - SpawnSeed: " .. tostring(gridEntityDesc.SpawnSeed)) .. "\n"
    msg = msg .. ("  - VariableSeed: " .. tostring(gridEntityDesc.VariableSeed)) .. ")\n"
    if door ~= nil then
        msg = msg .. ("  - Slot: " .. tostring(door.Slot)) .. "\n"
        msg = msg .. ("  - Direction: " .. tostring(door.Direction)) .. "\n"
        msg = msg .. ("  - TargetRoomIndex: " .. tostring(door.TargetRoomIndex)) .. "\n"
        msg = msg .. ("  - TargetRoomType: " .. tostring(door.TargetRoomType)) .. "\n"
    end
    return msg
end
local IGNORE_EFFECT_VARIANTS = __TS__New(ReadonlySet, {
    EffectVariant.BLOOD_EXPLOSION,
    EffectVariant.BLOOD_PARTICLE,
    EffectVariant.TINY_BUG,
    EffectVariant.TINY_FLY,
    EffectVariant.WATER_DROPLET,
    EffectVariant.WORM,
    EffectVariant.WALL_BUG,
    EffectVariant.FALLING_EMBER,
    EffectVariant.LIGHT,
    EffectVariant.MIST,
    EffectVariant.BACKDROP_DECORATION,
    EffectVariant.TADPOLE
})
--- Helper function for printing out every entity (or filtered entity) in the current room.
function ____exports.logAllEntities(includeBackgroundEffects, entityTypeFilter)
    local msg = "Entities in the room"
    if entityTypeFilter ~= nil then
        msg = msg .. (" (filtered to entity type " .. tostring(entityTypeFilter)) .. ")"
    elseif not includeBackgroundEffects then
        msg = msg .. " (not including background effects)"
    end
    msg = msg .. ":\n"
    local entities = getEntities(nil)
    local numMatchedEntities = 0
    for ____, ____value in __TS__Iterator(__TS__ArrayEntries(entities)) do
        local i = ____value[1]
        local entity = ____value[2]
        do
            if entityTypeFilter ~= nil and entity.Type ~= entityTypeFilter then
                goto __continue5
            end
            local effect = entity:ToEffect()
            if not includeBackgroundEffects and effect ~= nil and IGNORE_EFFECT_VARIANTS:has(effect.Variant) then
                goto __continue5
            end
            msg = msg .. getEntityLogLine(entity, i + 1)
            numMatchedEntities = numMatchedEntities + 1
        end
        ::__continue5::
    end
    local zeroText = "(no entities matched)"
    local oneOrMoreText = ((("(" .. tostring(numMatchedEntities)) .. " total ") .. (numMatchedEntities == 1 and "entity" or "entities")) .. ")"
    local text = numMatchedEntities == 0 and zeroText or oneOrMoreText
    msg = msg .. text .. "\n"
    for ____, line in ipairs(__TS__StringSplit(
        __TS__StringTrim(msg),
        "\n"
    )) do
        log(line)
    end
end
--- Helper function for printing out every grid entity (or filtered grid entity) in the current room.
-- 
-- @param includeWalls Optional. Whether oto log the walls. Default is false.
-- @param gridEntityTypeFilter Optional. If specified, will only log the given `GridEntityType`.
-- Default is undefined.
function ____exports.logAllGridEntities(includeWalls, gridEntityTypeFilter)
    if includeWalls == nil then
        includeWalls = false
    end
    local msg = "Grid entities in the room"
    if gridEntityTypeFilter ~= nil then
        msg = msg .. (" (filtered to grid entity type " .. tostring(gridEntityTypeFilter)) .. ")"
    elseif not includeWalls then
        msg = msg .. " (not including walls)"
    end
    msg = msg .. ":\n"
    local gridEntities = getGridEntities(nil)
    local numMatchedEntities = 0
    for ____, gridEntity in ipairs(gridEntities) do
        do
            local gridEntityIndex = gridEntity:GetGridIndex()
            local gridEntityType = gridEntity:GetType()
            if gridEntityTypeFilter ~= nil and gridEntityType ~= gridEntityTypeFilter then
                goto __continue14
            end
            if not includeWalls and gridEntityType == GridEntityType.WALL and gridEntityTypeFilter ~= GridEntityType.WALL then
                goto __continue14
            end
            msg = msg .. getGridEntityLogLine(gridEntity, gridEntityIndex)
            numMatchedEntities = numMatchedEntities + 1
        end
        ::__continue14::
    end
    msg = msg .. (numMatchedEntities == 0 and "(no grid entities matched)\n" or ((("(" .. tostring(numMatchedEntities)) .. " total grid ") .. (numMatchedEntities == 1 and "entity" or "entities")) .. ")\n")
    for ____, line in ipairs(__TS__StringSplit(
        __TS__StringTrim(msg),
        "\n"
    )) do
        log(line)
    end
end
--- Helper function for logging an array of specific entities.
function ____exports.logEntities(entities)
    for ____, entity in ipairs(entities) do
        ____exports.logEntity(entity)
    end
end
--- Helper function for logging an array of specific grid entities.
function ____exports.logGridEntities(gridEntities)
    for ____, gridEntity in ipairs(gridEntities) do
        ____exports.logGridEntity(gridEntity)
    end
end
--- Helper function to log information about the entity that corresponding to a pointer hash. (Only
-- use this when debugging, since retrieving the corresponding entity is expensive.)
function ____exports.logPtrHash(ptrHash)
    log("PtrHash: " .. tostring(ptrHash))
    local entity = getEntityFromPtrHash(nil, ptrHash)
    if entity == nil then
        log("No corresponding entity found.")
    else
        ____exports.logEntity(entity)
    end
end
--- Helper function to log information about the entity that corresponding to one or more pointer
-- hashes. (Only use this when debugging, since retrieving the corresponding entity is expensive.)
function ____exports.logPtrHashes(ptrHashes)
    for ____, ptrHash in ipairs(ptrHashes) do
        ____exports.logPtrHash(ptrHash)
    end
end
return ____exports
