local ____lualib = require("lualib_bundle")
local __TS__Class = ____lualib.__TS__Class
local __TS__Spread = ____lualib.__TS__Spread
local __TS__ObjectEntries = ____lualib.__TS__ObjectEntries
local __TS__ArrayIncludes = ____lualib.__TS__ArrayIncludes
local __TS__ArrayUnshift = ____lualib.__TS__ArrayUnshift
local __TS__ArrayMap = ____lualib.__TS__ArrayMap
local ____exports = {}
local getExportedMethodsFromFeature
local ____isaac_2Dtypescript_2Ddefinitions = require("isaac-typescript-definitions")
local CallbackPriority = ____isaac_2Dtypescript_2Ddefinitions.CallbackPriority
local ModCallback = ____isaac_2Dtypescript_2Ddefinitions.ModCallback
local ____callbacks = require("callbacks")
local getCallbacks = ____callbacks.getCallbacks
local ____decorators = require("decorators")
local EXPORTED_METHOD_NAMES_KEY = ____decorators.EXPORTED_METHOD_NAMES_KEY
local ____ISCFeature = require("enums.ISCFeature")
local ISCFeature = ____ISCFeature.ISCFeature
local ____ModCallbackCustom = require("enums.ModCallbackCustom")
local ModCallbackCustom = ____ModCallbackCustom.ModCallbackCustom
local ____features = require("features")
local getFeatures = ____features.getFeatures
local ____debugFunctions = require("functions.debugFunctions")
local getElapsedTimeSince = ____debugFunctions.getElapsedTimeSince
local getTime = ____debugFunctions.getTime
local ____enums = require("functions.enums")
local isEnumValue = ____enums.isEnumValue
local ____log = require("functions.log")
local getParentFunctionDescription = ____log.getParentFunctionDescription
local log = ____log.log
local ____tstlClass = require("functions.tstlClass")
local getTSTLClassConstructor = ____tstlClass.getTSTLClassConstructor
local getTSTLClassName = ____tstlClass.getTSTLClassName
local ____types = require("functions.types")
local parseIntSafe = ____types.parseIntSafe
local ____utils = require("functions.utils")
local assertDefined = ____utils.assertDefined
function getExportedMethodsFromFeature(self, featureClass)
    local constructor = getTSTLClassConstructor(nil, featureClass)
    local exportedMethodNames = constructor[EXPORTED_METHOD_NAMES_KEY]
    if exportedMethodNames == nil then
        return {}
    end
    return __TS__ArrayMap(
        exportedMethodNames,
        function(____, name)
            local featureClassRecord = featureClass
            if featureClassRecord[name] == nil then
                error("Failed to find a decorated exported method: " .. name)
            end
            local function wrappedMethod(____, ...)
                return featureClassRecord[name](featureClassRecord, ...)
            end
            return {name, wrappedMethod}
        end
    )
end
--- `isaacscript-common` has many custom callbacks that you can use in your mods. Instead of
-- hijacking the vanilla `Mod` object, we provide a `ModUpgraded` object for you to use, which
-- extends the base class and adds a new method of `AddCallbackCustom`.
-- 
-- To upgrade your mod, use the `upgradeMod` helper function.
-- 
-- By specifying one or more optional features when upgrading your mod, you will get a version of
-- `ModUpgraded` that has extra methods corresponding to the features that were specified. (This
-- corresponds to the internal-type `ModUpgradedWithFeatures` type, which extends `ModUpgraded`.)
____exports.ModUpgraded = __TS__Class()
local ModUpgraded = ____exports.ModUpgraded
ModUpgraded.name = "ModUpgraded"
function ModUpgraded.prototype.____constructor(self, mod, ____debug, timeThreshold)
    self.Name = mod.Name
    self.mod = mod
    self.debug = ____debug
    self.timeThreshold = timeThreshold
    self.callbacks = getCallbacks(nil)
    self.features = getFeatures(nil, self, self.callbacks)
end
function ModUpgraded.prototype.AddCallback(self, modCallback, ...)
    self:AddPriorityCallback(modCallback, CallbackPriority.DEFAULT, ...)
end
function ModUpgraded.prototype.AddPriorityCallback(self, modCallback, priority, ...)
    local args = {...}
    if self.debug then
        local callback = args[1]
        local optionalArg = args[2]
        local parentFunctionDescription = getParentFunctionDescription()
        local customCallback = type(modCallback) == "string"
        local callbackName = customCallback and tostring(modCallback) .. " (custom callback)" or "ModCallback." .. ModCallback[modCallback]
        local signature = parentFunctionDescription == nil and callbackName or (parentFunctionDescription .. " - ") .. callbackName
        --- We don't use the "log" helper function here since it will always show the same "unknown"
        -- prefix.
        local function callbackWithLogger(____, ...)
            local startTime = getTime(nil)
            Isaac.DebugString(signature .. " - START")
            local returnValue = callback(nil, ...)
            local elapsedTime = getElapsedTimeSince(nil, startTime)
            if self.timeThreshold == nil or self.timeThreshold <= elapsedTime then
                Isaac.DebugString((signature .. " - END - time: ") .. tostring(elapsedTime))
            else
                Isaac.DebugString(signature .. " - END")
            end
            return returnValue
        end
        local newArgs = {callbackWithLogger, optionalArg}
        self.mod:AddPriorityCallback(
            modCallback,
            priority,
            table.unpack(newArgs)
        )
    else
        self.mod:AddPriorityCallback(
            modCallback,
            priority,
            __TS__Spread(args)
        )
    end
end
function ModUpgraded.prototype.HasData(self)
    return self.mod:HasData()
end
function ModUpgraded.prototype.LoadData(self)
    return self.mod:LoadData()
end
function ModUpgraded.prototype.RemoveCallback(self, modCallback, callback)
    self.mod:RemoveCallback(modCallback, callback)
end
function ModUpgraded.prototype.RemoveData(self)
    self.mod:RemoveData()
end
function ModUpgraded.prototype.SaveData(self, data)
    self.mod:SaveData(data)
end
function ModUpgraded.prototype.AddCallbackCustom(self, modCallbackCustom, ...)
    self:AddPriorityCallbackCustom(modCallbackCustom, CallbackPriority.DEFAULT, ...)
end
function ModUpgraded.prototype.AddPriorityCallbackCustom(self, modCallbackCustom, priority, ...)
    local callbackClass = self.callbacks[modCallbackCustom]
    callbackClass:addSubscriber(priority, ...)
    self:initFeature(callbackClass)
end
function ModUpgraded.prototype.RemoveCallbackCustom(self, modCallbackCustom, callback)
    local callbackClass = self.callbacks[modCallbackCustom]
    callbackClass:removeSubscriber(callback)
    self:uninitFeature(callbackClass)
end
function ModUpgraded.prototype.logUsedFeatures(self)
    for ____, ____value in ipairs(__TS__ObjectEntries(self.callbacks)) do
        local modCallbackCustomString = ____value[1]
        local callbackClass = ____value[2]
        do
            if callbackClass.numConsumers == 0 then
                goto __continue19
            end
            local modCallbackCustom = parseIntSafe(nil, modCallbackCustomString)
            assertDefined(nil, modCallbackCustom, ("Failed to convert the string \"" .. modCallbackCustomString) .. "\" representing a \"ModCallbackCustom\" value to a number.")
            if not isEnumValue(nil, modCallbackCustom, ModCallbackCustom) then
                error(("Failed to convert the number " .. tostring(modCallbackCustom)) .. " to a \"ModCallbackCustom\" value.")
            end
            log(((("- ModCallbackCustom." .. ModCallbackCustom[modCallbackCustom]) .. " (") .. tostring(modCallbackCustom)) .. ")")
        end
        ::__continue19::
    end
    for ____, ____value in ipairs(__TS__ObjectEntries(self.features)) do
        local iscFeatureString = ____value[1]
        local featureClass = ____value[2]
        do
            if featureClass.numConsumers == 0 then
                goto __continue23
            end
            local iscFeature = parseIntSafe(nil, iscFeatureString)
            assertDefined(nil, iscFeature, ("Failed to convert the string \"" .. iscFeatureString) .. "\" representing a \"ISCFeature\" value to a number.")
            if not isEnumValue(nil, iscFeature, ISCFeature) then
                error(("Failed to convert the number " .. tostring(iscFeature)) .. " to a \"ISCFeature\" value.")
            end
            log(((("- ISCFeature." .. ISCFeature[iscFeature]) .. " (") .. tostring(iscFeature)) .. ")")
        end
        ::__continue23::
    end
end
function ModUpgraded.prototype.initFeature(self, feature)
    feature.numConsumers = feature.numConsumers + 1
    if feature.initialized then
        return
    end
    feature.initialized = true
    if feature.v ~= nil then
        if feature.featuresUsed == nil then
            feature.featuresUsed = {}
        end
        if not __TS__ArrayIncludes(feature.featuresUsed, ISCFeature.SAVE_DATA_MANAGER) then
            __TS__ArrayUnshift(feature.featuresUsed, ISCFeature.SAVE_DATA_MANAGER)
        end
    end
    if feature.featuresUsed ~= nil then
        for ____, featureUsed in ipairs(feature.featuresUsed) do
            local featureClass = self.features[featureUsed]
            self:initFeature(featureClass)
        end
    end
    if feature.callbacksUsed ~= nil then
        for ____, callbackTuple in ipairs(feature.callbacksUsed) do
            local modCallback, callbackFunc, optionalArgs = table.unpack(callbackTuple)
            self:AddPriorityCallback(
                modCallback,
                CallbackPriority.IMPORTANT,
                callbackFunc,
                table.unpack(optionalArgs or ({}))
            )
        end
    end
    if feature.customCallbacksUsed ~= nil then
        for ____, callbackTuple in ipairs(feature.customCallbacksUsed) do
            local modCallback, callbackFunc, optionalArgs = table.unpack(callbackTuple)
            self:AddPriorityCallbackCustom(
                modCallback,
                CallbackPriority.IMPORTANT,
                callbackFunc,
                table.unpack(optionalArgs or ({}))
            )
        end
    end
    if feature.v ~= nil then
        local className = getTSTLClassName(nil, feature)
        assertDefined(nil, className, "Failed to get the name of a feature.")
        local saveDataManagerClass = self.features[ISCFeature.SAVE_DATA_MANAGER]
        saveDataManagerClass:saveDataManager(className, feature.v, feature.vConditionalFunc)
    end
end
function ModUpgraded.prototype.uninitFeature(self, feature)
    if feature.numConsumers <= 0 then
        local className = getTSTLClassName(nil, feature) or "unknown"
        error(((("Failed to uninit feature \"" .. className) .. "\" since it has ") .. tostring(feature.numConsumers)) .. " consumers, which should never happen.")
    end
    if not feature.initialized then
        local className = getTSTLClassName(nil, feature) or "unknown"
        error(("Failed to uninit feature \"" .. className) .. "\" since it was not initialized, which should never happen.")
    end
    feature.numConsumers = feature.numConsumers - 1
    if feature.numConsumers > 0 then
        return
    end
    feature.initialized = false
    if feature.featuresUsed ~= nil then
        for ____, featureUsed in ipairs(feature.featuresUsed) do
            local featureClass = self.features[featureUsed]
            self:uninitFeature(featureClass)
        end
    end
    if feature.callbacksUsed ~= nil then
        for ____, callbackTuple in ipairs(feature.callbacksUsed) do
            local modCallback, callbackFunc = table.unpack(callbackTuple)
            self:RemoveCallback(modCallback, callbackFunc)
        end
    end
    if feature.customCallbacksUsed ~= nil then
        for ____, callbackTuple in ipairs(feature.customCallbacksUsed) do
            local modCallback, callbackFunc = table.unpack(callbackTuple)
            self:RemoveCallbackCustom(modCallback, callbackFunc)
        end
    end
    if feature.v ~= nil then
        local className = getTSTLClassName(nil, feature)
        assertDefined(nil, className, "Failed to get the name of a feature.")
        local saveDataManagerClass = self.features[ISCFeature.SAVE_DATA_MANAGER]
        saveDataManagerClass:saveDataManagerRemove(className)
    end
end
function ModUpgraded.prototype.initOptionalFeature(self, feature)
    local featureClass = self.features[feature]
    self:initFeature(featureClass)
    return getExportedMethodsFromFeature(nil, featureClass)
end
return ____exports
