---@diagnostic disable: undefined-global

rSemiTruck = rSemiTruck or {}
rSemiTruck.DoubleTireRecipePatch = rSemiTruck.DoubleTireRecipePatch or {}

local DoubleTireRecipePatch = rSemiTruck.DoubleTireRecipePatch

if not Recipe then Recipe = {} end
if not Recipe.OnCreate then Recipe.OnCreate = {} end

local CONVERT_RECIPE_NAMES = {
    "Convert_KI5Tire_To_Vanilla",
    "Base_Convert_KI5Tire_To_Vanilla",
    "Convert_Damn_Tire_To_Vanilla",
    "Base_Convert_Damn_Tire_To_Vanilla",
}

local EXCLUDED_TIRE_BASENAMES = {
    ClassicTire2 = true,
    OldTire2 = true,
    NormalTire2 = true,
    ModernTire2 = true,
    DoubleOldTire2 = true,
    DoubleNormalTire2 = true,
    DoubleModernTire2 = true,
    AxleOldTire2 = true,
    AxleNormalTire2 = true,
    AxleModernTire2 = true,
}

local didPatchConvertRecipe = false

local function safeAddItem(container, item)
    if not container or not item then
        return false
    end

    container:AddItem(item)

    if sendAddItemToContainer then
        sendAddItemToContainer(container, item)
    end
    if sendItemStats then
        sendItemStats(item)
    end
    if container.setDrawDirty then
        container:setDrawDirty(true)
    end

    return true
end

local function safeRemoveItem(container, item)
    if not container or not item then
        return false
    end

    if container.DoRemoveItem then
        container:DoRemoveItem(item)
    else
        container:Remove(item)
    end

    if sendRemoveItemFromContainer then
        sendRemoveItemFromContainer(container, item)
    end
    if container.setDrawDirty then
        container:setDrawDirty(true)
    end

    return true
end

local function safeCall(object, methodName)
    if not object or not object[methodName] then
        return nil
    end

    local ok, result = pcall(object[methodName], object)
    if ok then
        return result
    end

    return nil
end

local function endsWith(value, suffix)
    return type(value) == "string"
        and type(suffix) == "string"
        and suffix ~= ""
        and value:sub(-#suffix) == suffix
end

local function getAllScriptItems()
    if getAllItems then
        return getAllItems()
    end

    local manager = ScriptManager and ScriptManager.instance or nil
    if manager and manager.getAllItems then
        return manager:getAllItems()
    end

    return nil
end

local function getScriptItem(fullType)
    local manager = ScriptManager and ScriptManager.instance or nil
    if not manager or type(fullType) ~= "string" or fullType == "" then
        return nil
    end

    return manager:getItem(fullType)
end

local function findCraftRecipe(recipeNames)
    local manager = ScriptManager and ScriptManager.instance or nil
    if not manager then
        return nil
    end

    for _, recipeName in ipairs(recipeNames) do
        local recipe = manager:getCraftRecipe(recipeName)
        if recipe then
            return recipe
        end
    end

    return nil
end

local function isConvertibleTire2(scriptItem)
    local baseName = safeCall(scriptItem, "getType") or safeCall(scriptItem, "getName")
    if type(baseName) ~= "string" or EXCLUDED_TIRE_BASENAMES[baseName] then
        return false
    end

    return endsWith(baseName, "Tire2") or endsWith(baseName, "Offroad2")
end

local function discoverConvertibleTireInputs()
    local itemTypes = {}
    local seen = {}
    local items = getAllScriptItems()
    if not items then
        return itemTypes
    end

    for index = 0, items:size() - 1 do
        local scriptItem = items:get(index)
        if isConvertibleTire2(scriptItem) then
            local fullType = safeCall(scriptItem, "getFullName")
            if type(fullType) == "string" and fullType ~= "" and not seen[fullType] then
                seen[fullType] = true
                itemTypes[#itemTypes + 1] = fullType
            end
        end
    end

    table.sort(itemTypes)
    return itemTypes
end

local function buildConvertRecipePatchScript(itemTypes)
    local inputLine = nil
    if #itemTypes > 0 then
        inputLine = "        item 1 [" .. table.concat(itemTypes, ";") .. "],"
    else
        inputLine = "        item 999 tags[LugWrench],"
    end

    return table.concat({
        "{",
        "    Time = 15,",
        "    NeedToBeLearn = false,",
        "    OnCreate = rSemiTruck.DoubleTireRecipePatch.OnCreateConvertDamnTire,",
        "    Tags = InHandCraft;CanBeDoneFromFloor,",
        "    category = W900,",
        "    inputs",
        "    {",
        inputLine,
        "    }",
        "    outputs",
        "    {",
        "        item 1 Base.OldTire2,",
        "    }",
        "}",
    }, "\n")
end

function DoubleTireRecipePatch.applyConvertRecipeInputs()
    if didPatchConvertRecipe then
        return
    end

    local recipe = findCraftRecipe(CONVERT_RECIPE_NAMES)
    if not recipe then
        return
    end

    local itemTypes = discoverConvertibleTireInputs()
    local ok, err = pcall(function()
        recipe:Load(recipe:getName(), buildConvertRecipePatchScript(itemTypes))
    end)
    if not ok then
        print("[rSemiTruck] Failed to patch KI5 tire conversion recipe inputs: " .. tostring(err))
        return
    end

    didPatchConvertRecipe = true
end

local function getVehicleTypeFromItem(item)
    if not item or not item.getFullType then
        return 2
    end

    local scriptItem = getScriptItem(item:getFullType())
    local vehicleType = scriptItem and safeCall(scriptItem, "getVehicleType") or nil
    vehicleType = tonumber(vehicleType)
    if vehicleType == 1 or vehicleType == 2 or vehicleType == 3 then
        return vehicleType
    end

    return 2
end

local function rollTireTier()
    local roll = ZombRand(100)
    if roll < 50 then
        return "Old"
    end

    if roll < 85 then
        return "Normal"
    end

    return "Modern"
end

local function buildVanillaTireFullType(item)
    local vehicleType = getVehicleTypeFromItem(item)
    return "Base." .. rollTireTier() .. "Tire" .. tostring(vehicleType)
end

function DoubleTireRecipePatch.OnCreateConvertDamnTire(craftRecipeData, character)
    if not craftRecipeData or not character then
        return
    end

    local consumedItems = craftRecipeData:getAllConsumedItems()
    local createdItems = craftRecipeData:getAllCreatedItems()
    local sourceItem = nil
    if consumedItems and consumedItems.size and consumedItems:size() > 0 then
        sourceItem = consumedItems:get(0)
    end
    local placeholderItem = nil
    if createdItems and createdItems.size and createdItems:size() > 0 then
        placeholderItem = createdItems:get(0)
    end
    if not sourceItem then
        return
    end

    local inventory = character:getInventory()
    if not inventory then
        return
    end

    if placeholderItem then
        safeRemoveItem(inventory, placeholderItem)
    end

    local targetItem = instanceItem(buildVanillaTireFullType(sourceItem))
    if not targetItem then
        return
    end

    if sourceItem.getCondition and targetItem.setCondition then
        targetItem:setCondition(sourceItem:getCondition())
    end

    safeAddItem(inventory, targetItem)
end

Recipe.OnCreate.rSemiTruckConvertDamnTire = DoubleTireRecipePatch.OnCreateConvertDamnTire

Events.OnInitGlobalModData.Add(DoubleTireRecipePatch.applyConvertRecipeInputs)
Events.OnGameBoot.Add(DoubleTireRecipePatch.applyConvertRecipeInputs)
Events.OnGameStart.Add(DoubleTireRecipePatch.applyConvertRecipeInputs)