local Helpers = {}

Helpers.MODULE_ID = "EURY_COOKINGUI"
-- GLOBAL seasoning suffix shared by all modules
Helpers.SPICE_SUFFIX = getText("ContextMenu_EvolvedRecipe_Spice") or " as Seasoning"

---------------------------------------------------------------------------
-- Helpers
---------------------------------------------------------------------------

function Helpers.log(message)
    if isDebugEnabled() then
        DebugLog.log(DebugType.General, "[BC] " .. message)
    end
end

---Return a "time until spoilage" value for sorting.
---Non-perishables get a large value so they sink to the bottom.
---@param evoItem InventoryItem
---@return number
function Helpers.getTimeLeft(evoItem) -- getSeasoningTimeLeft
    local HUGE = 1e9

    if not evoItem or not instanceof(evoItem, "Food") then
        return HUGE
    end

    local offAge = evoItem:getOffAge()
    local age    = evoItem:getAge()
    if not offAge or not age then
        return HUGE
    end

    local timeLeft = offAge - age
    if timeLeft < 0 then
        timeLeft = 0
    end
    return timeLeft
end

function Helpers.isSeasoning(evoItem)
    if not evoItem then
        return false
    end

    -- 42.13: For Food instances, the per-item Food:isSpice() is the authoritative spice flag.
    if instanceof(evoItem, "Food") then
        return evoItem.isSpice and evoItem:isSpice() or false
    end

    -- Fallback: non-Food spice carriers can still be flagged at the script-item level.
    local script = evoItem.getScriptItem and evoItem:getScriptItem() or nil
    if script and script.isSpice and script:isSpice() then
        return true
    end

    return false
end

---Return "uses left" for sorting drainable seasonings.
---Lower usesLeft = should be used up sooner.
---@param evoItem InventoryItem
---@return number
function Helpers.getUsesLeft(evoItem) -- getSeasoningUsesLeft
    local HUGE = 1e9

    if not evoItem then
        return HUGE
    end

    -- Drainable condiments (ketchup, mustard, etc.)
    if evoItem.isDrainable and evoItem:isDrainable() then
        -- getDrainableUsesInt() returns whole uses left for drainables.
        local usesInt = evoItem.getDrainableUsesInt and evoItem:getDrainableUsesInt()
        if usesInt ~= nil then
            -- 0 or low values = almost empty → we want them first
            return usesInt
        end
    end

    -- Non-drainables / unknowns get a big value so they come after
    -- real "almost empty" condiments when spoilage is equal.
    return HUGE
end

---Heuristic: is this option an "Add Random ..." style entry?
---We keep these at the very top of the main evo submenu.
---@param name string
---@return boolean
function Helpers.isRandomEvoOptionName(name)
    if not name then return false end
    local lowerName = string.lower(name)
    if string.find(lowerName, "random", 1, true) then
        return true
    end
    -- If there is ever a dedicated translation key for "Random" we can add it here.
    return false
end

-- Is this item one of the butcher-quality meats we care about?
function Helpers.isButcheredMeat(item)
    if not item then return false end
    if not instanceof(item, "Food") then return false end
    if not item.isCustomName or not item:isCustomName() then return false end

    if not AnimalPartsDefinitions or not AnimalPartsDefinitions.meat then return false end
    local ft = item.getFullType and item:getFullType() or nil
    if not ft then return false end

    local def = AnimalPartsDefinitions.meat[ft]
    if not def then return false end

    local md = item.getModData and item:getModData() or nil
    if md and md.BC_ButcherQuality ~= nil then
        return false
    end

    return true
end

-- To infer quality by diffing item name
-- Returns: "prime" | "medium" | "poor" | nil
function Helpers.getQualityToken(item)
    if not item then return nil end
    if not AnimalPartsDefinitions or not AnimalPartsDefinitions.meat then return nil end

    local ft = item.getFullType and item:getFullType() or nil
    if not ft then return nil end

    local def = AnimalPartsDefinitions.meat[ft]
    local variants = def and def.variants or nil
    if not variants then return nil end

    local name = item.getName and item:getName() or nil
    if not name or name == "" then return nil end

    -- Match the localized "extraName" string that vanilla used when it set the custom name.
    -- We then convert the translation key into a stable internal token.
    for _, v in ipairs(variants) do
        local extraKey = v and v.extraName or nil
        if extraKey and getText then
            local extraText = getText(extraKey)
            if extraText and extraText ~= "" then
                if string.find(name, extraText, 1, true) then
                    -- Convert the translation key into a stable token.
                    -- Vanilla keys are typically like:
                    --   IGUI_AnimalMeat_PrimeCut / MediumCut / PoorCut
                    local k = tostring(extraKey)

                    if string.find(k, "PrimeCut", 1, true) then return "prime" end
                    if string.find(k, "MediumCut", 1, true) then return "medium" end
                    if string.find(k, "PoorCut", 1, true) then return "poor" end

                    -- Unknown variant naming scheme, but we did match the extraText.
                    -- Return a stable fallback token derived from the key.
                    return k
                end
            end
        end
    end

    return nil
end

return Helpers