local OFHotBrassPatch = {
    patched = false,
}

local function isPatchToggleEnabled()
    local vars = SandboxVars and SandboxVars.OpinionatedFirearms
    if vars and vars.HBVCEFAmmoMakerPatch ~= nil then
        return vars.HBVCEFAmmoMakerPatch == true
    end

    return true
end

local function isSessionEligible()
    return isPatchToggleEnabled()
end

local function getAmmoMakerFiredCasing(ammoType)
    if type(ammoType) ~= "string" or ammoType == "" then
        return nil
    end

    local function getAmmoTypeData()
        if type(ammoMakerAmmoTypes) ~= "table" then
            return nil
        end

        local data = ammoMakerAmmoTypes[ammoType]
        if type(data) ~= "table" or type(data.ammoTypes) ~= "table" or #data.ammoTypes == 0 then
            return nil
        end

        return data
    end

    local function getActiveAmmoData(typeData)
        if type(typeData) ~= "table" or type(typeData.ammoTypes) ~= "table" or type(ammoMakerAmmoData) ~= "table" then
            return nil
        end

        local activeIndex = 1
        if type(typeData.modIds) == "table" and type(ammoMakerCompatibleMods) == "table" then
            for i = 1, #typeData.modIds do
                local modId = typeData.modIds[i]
                if ammoMakerCompatibleMods[modId] == true then
                    activeIndex = i
                end
            end
        end

        if activeIndex < 1 or activeIndex > #typeData.ammoTypes then
            activeIndex = 1
        end

        local activeAmmoKey = typeData.ammoTypes[activeIndex]
        if type(activeAmmoKey) == "string" then
            local activeAmmoData = ammoMakerAmmoData[activeAmmoKey]
            if type(activeAmmoData) == "table" then
                return activeAmmoData
            end
        end

        for i = 1, #typeData.ammoTypes do
            local ammoKey = typeData.ammoTypes[i]
            if type(ammoKey) == "string" then
                local ammoData = ammoMakerAmmoData[ammoKey]
                if type(ammoData) == "table" then
                    return ammoData
                end
            end
        end

        return nil
    end

    local function partDataToFiredType(partData)
        if type(partData) ~= "table" then
            return nil
        end

        local firedType = partData.partFired or partData.partOld
        if type(firedType) ~= "string" or firedType == "" then
            return nil
        end

        return firedType
    end

    if type(ammoMakerAmmoParts) ~= "table" then
        return nil
    end

    local ammoTypeData = getAmmoTypeData()
    if not ammoTypeData then
        return nil
    end

    local ammoData = getActiveAmmoData(ammoTypeData)
    if type(ammoData) == "table" and type(ammoData.casingType) == "string" then
        local firedType = partDataToFiredType(ammoMakerAmmoParts[ammoData.casingType])
        if firedType then
            return firedType
        end
    end

    return nil
end

local function applyPatch()
    if OFHotBrassPatch.patched then
        return true
    end

    if not isSessionEligible() then
        return false
    end

    if type(SpentCasingPhysics) ~= "table" then
        return false
    end

    if type(SpentCasingPhysics.getItemToEject) ~= "function" then
        return false
    end

    if type(SpentCasingPhysics.doSpawnCasing) ~= "function" then
        return false
    end

    local originalGetItemToEject = SpentCasingPhysics.getItemToEject
    local originalDoSpawnCasing = SpentCasingPhysics.doSpawnCasing

    SpentCasingPhysics.getItemToEject = function(ammoType)
        local mappedType = getAmmoMakerFiredCasing(ammoType)
        if mappedType then
            return mappedType
        end

        return originalGetItemToEject(ammoType)
    end

    SpentCasingPhysics.doSpawnCasing = function(player, weapon, params, racking, optionalItem)
        if not optionalItem and weapon and weapon.getAmmoType then
            local ammoType = weapon:getAmmoType()
            if ammoType then
                local mappedType = getAmmoMakerFiredCasing(tostring(ammoType))
                if mappedType then
                    optionalItem = mappedType
                    if racking then
                        -- Force rack ejects to stay as empties for this patch.
                        racking = false
                    end
                end
            end
        end

        return originalDoSpawnCasing(player, weapon, params, racking, optionalItem)
    end

    OFHotBrassPatch.patched = true
    return true
end

local function tryPatchOnTick()
    if OFHotBrassPatch.patched then
        Events.OnTick.Remove(tryPatchOnTick)
        return
    end

    applyPatch()
end

Events.OnTick.Add(tryPatchOnTick)
