local ____lualib = require("lualib_bundle")
local __TS__ArrayFilter = ____lualib.__TS__ArrayFilter
local __TS__ArrayMap = ____lualib.__TS__ArrayMap
local ____exports = {}
local getTotalWeightOfJSONObject, getJSONObjectWithChosenWeight
local ____isaac_2Dtypescript_2Ddefinitions = require("isaac-typescript-definitions")
local DoorSlotFlagZero = ____isaac_2Dtypescript_2Ddefinitions.DoorSlotFlagZero
local RoomShape = ____isaac_2Dtypescript_2Ddefinitions.RoomShape
local ____array = require("functions.array")
local sumArray = ____array.sumArray
local ____doors = require("functions.doors")
local doorSlotToDoorSlotFlag = ____doors.doorSlotToDoorSlotFlag
local getRoomShapeDoorSlot = ____doors.getRoomShapeDoorSlot
local ____enums = require("functions.enums")
local isEnumValue = ____enums.isEnumValue
local ____flag = require("functions.flag")
local addFlag = ____flag.addFlag
local ____log = require("functions.log")
local log = ____log.log
local ____random = require("functions.random")
local getRandomFloat = ____random.getRandomFloat
local ____types = require("functions.types")
local parseIntSafe = ____types.parseIntSafe
local ____utils = require("functions.utils")
local assertDefined = ____utils.assertDefined
function getTotalWeightOfJSONObject(self, jsonOjectArray)
    local weights = __TS__ArrayMap(
        jsonOjectArray,
        function(____, jsonObject)
            local weightString = jsonObject["$"].weight
            local weight = tonumber(weightString)
            assertDefined(
                nil,
                weight,
                ("Failed to parse the weight of a JSON object: " .. tostring(weightString)) .. "."
            )
            return weight
        end
    )
    return sumArray(nil, weights)
end
function getJSONObjectWithChosenWeight(self, jsonOjectArray, chosenWeight)
    local weightAccumulator = 0
    for ____, jsonObject in ipairs(jsonOjectArray) do
        local weightString = jsonObject["$"].weight
        local weight = tonumber(weightString)
        assertDefined(
            nil,
            weight,
            "Failed to parse the weight of a JSON object: " .. tostring(weightString)
        )
        weightAccumulator = weightAccumulator + weight
        if weightAccumulator >= chosenWeight then
            return jsonObject
        end
    end
    return nil
end
--- Helper function to calculate what the resulting `BitFlags<DoorSlotFlag>` value would be for a
-- given JSON room.
-- 
-- (A JSON room is an XML file converted to JSON so that it can be directly imported into your mod.)
function ____exports.getJSONRoomDoorSlotFlags(self, jsonRoom)
    local roomShapeString = jsonRoom["$"].shape
    local roomShape = parseIntSafe(nil, roomShapeString)
    assertDefined(nil, roomShape, "Failed to parse the \"shape\" field of a JSON room: " .. roomShapeString)
    if not isEnumValue(nil, roomShape, RoomShape) then
        error("Failed to parse the \"shape\" field of a JSON room since it was an invalid number: " .. tostring(roomShape))
    end
    local doorSlotFlags = DoorSlotFlagZero
    for ____, door in ipairs(jsonRoom.door) do
        do
            local existsString = door["$"].exists
            if existsString ~= "True" and existsString ~= "False" then
                error("Failed to parse the \"exists\" field of a JSON room door: " .. existsString)
            end
            if existsString == "False" then
                goto __continue4
            end
            local xString = door["$"].x
            local x = parseIntSafe(nil, xString)
            assertDefined(nil, x, "Failed to parse the \"x\" field of a JSON room door: " .. xString)
            local yString = door["$"].y
            local y = parseIntSafe(nil, yString)
            assertDefined(nil, y, "Failed to parse the \"y\" field of a JSON room door: " .. yString)
            local doorSlot = getRoomShapeDoorSlot(nil, roomShape, x, y)
            assertDefined(
                nil,
                doorSlot,
                ((("Failed to retrieve the door slot for a JSON room door at coordinates: [" .. tostring(x)) .. ", ") .. tostring(y)) .. "]"
            )
            local doorSlotFlag = doorSlotToDoorSlotFlag(nil, doorSlot)
            doorSlotFlags = addFlag(nil, doorSlotFlags, doorSlotFlag)
        end
        ::__continue4::
    end
    return doorSlotFlags
end
--- Helper function to find a specific room from an array of JSON rooms.
-- 
-- (A JSON room is an XML file converted to JSON so that it can be directly imported into your mod.)
-- 
-- @param jsonRooms The array of rooms to search through.
-- @param variant The room variant to select. (The room variant can be thought of as the ID of the
-- room.)
function ____exports.getJSONRoomOfVariant(self, jsonRooms, variant)
    local jsonRoomsOfVariant = __TS__ArrayFilter(
        jsonRooms,
        function(____, jsonRoom)
            local roomVariantString = jsonRoom["$"].variant
            local roomVariant = parseIntSafe(nil, roomVariantString)
            if roomVariant == nil then
                error("Failed to convert a JSON room variant to an integer: " .. roomVariantString)
            end
            return roomVariant == variant
        end
    )
    if #jsonRoomsOfVariant == 0 then
        return nil
    end
    if #jsonRoomsOfVariant == 1 then
        return jsonRoomsOfVariant[1]
    end
    error(((("Found " .. tostring(#jsonRoomsOfVariant)) .. " JSON rooms with a variant of ") .. tostring(variant)) .. ", when there should only be 1.")
end
--- Helper function to find all of the JSON rooms that match the sub-type provided.
-- 
-- (A JSON room is an XML file converted to JSON so that it can be directly imported into your mod.)
-- 
-- @param jsonRooms The array of rooms to search through.
-- @param subType The sub-type to match.
function ____exports.getJSONRoomsOfSubType(self, jsonRooms, subType)
    return __TS__ArrayFilter(
        jsonRooms,
        function(____, jsonRoom)
            local roomSubTypeString = jsonRoom["$"].subtype
            local roomSubType = parseIntSafe(nil, roomSubTypeString)
            if roomSubType == nil then
                error("Failed to convert a JSON room sub-type to an integer: " .. roomSubTypeString)
            end
            return roomSubType == subType
        end
    )
end
--- Helper function to get a random JSON entity from an array of JSON entities.
-- 
-- (A JSON entity is an entity inside of a JSON room. A JSON room is an XML file converted to JSON
-- so that it can be directly imported into your mod.)
-- 
-- Note that this function does not simply choose a random element in the provided array; it will
-- properly account for each room weight using the algorithm from:
-- https://stackoverflow.com/questions/1761626/weighted-random-numbers
-- 
-- If you want an unseeded entity, you must explicitly pass `undefined` to the `seedOrRNG`
-- parameter.
-- 
-- @param jsonEntities The array of entities to randomly choose between.
-- @param seedOrRNG The `Seed` or `RNG` object to use. If an `RNG` object is provided, the
-- `RNG.Next` method will be called. If `undefined` is provided, it will default to
-- a random seed.
-- @param verbose Optional. If specified, will write entries to the "log.txt" file that describe
-- what the function is doing. Default is false.
function ____exports.getRandomJSONEntity(self, jsonEntities, seedOrRNG, verbose)
    if verbose == nil then
        verbose = false
    end
    local totalWeight = getTotalWeightOfJSONObject(nil, jsonEntities)
    if verbose then
        log("Total weight of the JSON entities provided: " .. tostring(totalWeight))
    end
    local chosenWeight = getRandomFloat(nil, 0, totalWeight, seedOrRNG)
    if verbose then
        log("Randomly chose weight for JSON entity: " .. tostring(chosenWeight))
    end
    local randomJSONEntity = getJSONObjectWithChosenWeight(nil, jsonEntities, chosenWeight)
    assertDefined(
        nil,
        randomJSONEntity,
        "Failed to get a JSON entity with chosen weight: " .. tostring(chosenWeight)
    )
    return randomJSONEntity
end
--- Helper function to get a random JSON room from an array of JSON rooms.
-- 
-- (A JSON room is an XML file converted to JSON so that it can be directly imported into your mod.)
-- 
-- Note that this function does not simply choose a random element in the provided array; it will
-- properly account for each room weight using the algorithm from:
-- https://stackoverflow.com/questions/1761626/weighted-random-numbers
-- 
-- If you want an unseeded room, you must explicitly pass `undefined` to the `seedOrRNG` parameter.
-- 
-- @param jsonRooms The array of rooms to randomly choose between.
-- @param seedOrRNG The `Seed` or `RNG` object to use. If an `RNG` object is provided, the
-- `RNG.Next` method will be called. If `undefined` is provided, it will default to
-- a random seed.
-- @param verbose Optional. If specified, will write entries to the "log.txt" file that describe
-- what the function is doing. Default is false.
function ____exports.getRandomJSONRoom(self, jsonRooms, seedOrRNG, verbose)
    if verbose == nil then
        verbose = false
    end
    local totalWeight = getTotalWeightOfJSONObject(nil, jsonRooms)
    if verbose then
        log("Total weight of the JSON rooms provided: " .. tostring(totalWeight))
    end
    local chosenWeight = getRandomFloat(nil, 0, totalWeight, seedOrRNG)
    if verbose then
        log("Randomly chose weight for JSON room: " .. tostring(chosenWeight))
    end
    local randomJSONRoom = getJSONObjectWithChosenWeight(nil, jsonRooms, chosenWeight)
    assertDefined(
        nil,
        randomJSONRoom,
        "Failed to get a JSON room with chosen weight: " .. tostring(chosenWeight)
    )
    return randomJSONRoom
end
return ____exports
