local M = {}

local EXACT_FOOD_STATS = {
    calories = true,
    carbs = true,
    proteins = true,
    fat = true,
    daysFresh = true,
    daysRotten = true,
    foodPoison = true,
}

local function normalizeTraitName(name)
    if not name then return nil end
    name = tostring(name):lower()
    name = name:gsub("^base:", "")
    name = name:gsub("%s+", "")
    return name
end

local function playerHasKnownTrait(player, wanted)
    if not player or not wanted then return false end

    if player.hasTrait and CharacterTrait then
        for _, traitName in ipairs(wanted) do
            local enumName = string.upper(traitName)
            local trait = CharacterTrait[enumName]
            if trait and player:hasTrait(trait) then return true end
        end
    end

    if player.getCharacterTraits then
        local traits = player:getCharacterTraits()
        local known = traits and traits.getKnownTraits and traits:getKnownTraits()
        if known and known.size and known.get then
            for i = 0, known:size() - 1 do
                local knownName = normalizeTraitName(known:get(i))
                for _, traitName in ipairs(wanted) do
                    if knownName == normalizeTraitName(traitName) then
                        return true
                    end
                end
            end
        end
    end

    return false
end

local function playerKnowsRecipe(player, recipe)
    if not player or not recipe then return false end
    if player.isRecipeActuallyKnown then
        if player:isRecipeActuallyKnown(recipe) then return true end
    end
    if player.getKnownRecipes then
        local recipes = player:getKnownRecipes()
        if recipes and recipes.contains and recipes:contains(recipe) then return true end
    end
    return false
end

function InspectUI_canSeeExactFoodStats()
    local player = getSpecificPlayer and getSpecificPlayer(0) or (getPlayer and getPlayer())
    if not player then return false end
    return playerHasKnownTrait(player, { "nutritionist", "nutritionist2" })
        or playerHasKnownTrait(player, { "herbalist" })
        or playerKnowsRecipe(player, "Herbalist")
end

local function canShowExactStat(statId)
    return (not EXACT_FOOD_STATS[statId]) or InspectUI_canSeeExactFoodStats()
end

local function formatFoodEffect(value)
    if value == nil then return nil end
    local scaled = value * 100
    local decimals = math.abs(scaled - math.floor(scaled)) < 0.0001 and 0 or 1
    return InspectUI_fmtNumber(scaled, decimals)
end

M.defs = {
    --------------------------------------------------
    -- FOOD & COOKING
    --------------------------------------------------
    {
        id       = "hunger",
        labelKey = "IGUI_Inspect_Hunger",
        fallback = "Hunger",
        getter   = function(item)
            if not item or not item.getHungerChange then return end
            local v = item:getHungerChange() or 0
            if v == 0 then return end
            return formatFoodEffect(v)
        end,
    },
    {
        id       = "thirst",
        labelKey = "IGUI_Inspect_Thirst",
        fallback = "Thirst",
        getter   = function(item)
            if not item or not item.getThirstChange then return end
            local v = item:getThirstChange() or 0
            if v == 0 then return end
            return formatFoodEffect(v)
        end,
    },
    {
        id       = "freshState",
        labelKey = "IGUI_Inspect_Fresh",
        fallback = "Fresh",
        getter   = function(item)
            local fresh = InspectUI_foodFlags(item)
            if not fresh then return end
            return InspectUI_tr("IGUI_Inspect_Yes", "Yes")
        end,
    },
    {
        id       = "staleState",
        labelKey = "IGUI_Inspect_Stale",
        fallback = "Stale",
        getter   = function(item)
            local _, stale = InspectUI_foodFlags(item)
            if not stale then return end
            return InspectUI_tr("IGUI_Inspect_Yes", "Yes")
        end,
    },
    {
        id       = "rottenState",
        labelKey = "IGUI_Inspect_Rotten",
        fallback = "Rotten",
        getter   = function(item)
            local _, _, rotten = InspectUI_foodFlags(item)
            if not rotten then return end
            return InspectUI_tr("IGUI_Inspect_Yes", "Yes")
        end,
    },
    {
        id       = "burnedState",
        labelKey = "IGUI_Inspect_Burned",
        fallback = "Burned",
        getter   = function(item)
            local _, _, _, burnt = InspectUI_foodFlags(item)
            if not burnt then return end
            return InspectUI_tr("IGUI_Inspect_Yes", "Yes")
        end,
    },
    {
        id       = "burnTime",
        labelKey = "IGUI_Inspect_BurnTime",
        fallback = "Burn time",
        getter   = function(item)
            if not item or not item.getScriptItem then return end
            local script = item:getScriptItem()
            if not script or not script.getBurnTime then return end
            local v = script:getBurnTime()
            if not v or v <= 0 then return end
            -- burn time suele venir en minutos
            return InspectUI_fmtNumber(v, 1) .. " min"
        end,
    },
    {
        id       = "unhappiness",
        labelKey = "IGUI_Inspect_Unhappiness",
        fallback = "Unhappiness",
        getter   = function(item)
            if not item or not instanceof(item, "Food") then return end
            if not item.getUnhappyChange then return end
            local v = item:getUnhappyChange() or 0
            if v == 0 then return end
            return InspectUI_fmtNumber(v, 2)
        end,
    },
    {
        id       = "calories",
        labelKey = "IGUI_Inspect_Calories",
        fallback = "Calories",
        getter   = function(item)
            if not canShowExactStat("calories") then return end
            if not item or not instanceof(item, "Food") then return end
            if not item.getCalories then return end
            local v = item:getCalories() or 0
            if v <= 0 then return end
            return tostring(math.floor(v))
        end,
    },
    {
        id       = "carbs",
        labelKey = "IGUI_Inspect_Stat_Carbs",
        fallback = "Carbohydrates",
        getter   = function(item)
            if not canShowExactStat("carbs") then return end
            if not item or not instanceof(item, "Food") then return end
            if not item.getCarbohydrates then return end
            local v = item:getCarbohydrates()
            if not v or v == 0 then return end
            -- gramos aprox.
            return InspectUI_fmtNumber(v, 1)
        end,
    },
    {
        id       = "proteins",
        labelKey = "IGUI_Inspect_Stat_Proteins",
        fallback = "Proteins",
        getter   = function(item)
            if not canShowExactStat("proteins") then return end
            if not item or not instanceof(item, "Food") then return end
            if not item.getProteins then return end
            local v = item:getProteins()
            if not v or v == 0 then return end
            return InspectUI_fmtNumber(v, 1)
        end,
    },
    {
        id       = "fat",
        labelKey = "IGUI_Inspect_Stat_Fat",
        fallback = "Fat",
        getter   = function(item)
            if not canShowExactStat("fat") then return end
            if not item or not instanceof(item, "Food") then return end
            if not item.getLipids then return end
            local v = item:getLipids()
            if not v or v == 0 then return end
            return InspectUI_fmtNumber(v, 1)
        end,
    },
    {
        id       = "daysFresh",
        labelKey = "IGUI_Inspect_Stat_DaysFresh",
        fallback = "Days fresh",
        getter   = function(item)
            if not canShowExactStat("daysFresh") then return end
            if not item or not instanceof(item, "Food") then return end
            if not item.getScriptItem then return end

            local script = item:getScriptItem()
            if not script or not script.getDaysFresh then return end

            local d = script:getDaysFresh()
            -- 1000000000 = no perecedero / sentinel
            if not d or d <= 0 or d >= 1000000000 then return end

            return tostring(d)
        end,
    },
    {
        id       = "daysRotten",
        labelKey = "IGUI_Inspect_Stat_DaysRotten",
        fallback = "Days until rotten",
        getter   = function(item)
            if not canShowExactStat("daysRotten") then return end
            if not item or not instanceof(item, "Food") then return end
            if not item.getScriptItem then return end

            local script = item:getScriptItem()
            if not script or not script.getDaysTotallyRotten then return end

            local d = script:getDaysTotallyRotten()
            if not d or d <= 0 or d >= 1000000000 then return end

            return tostring(d)
        end,
    },
    {
        id       = "foodPoison",
        labelKey = "IGUI_Inspect_Stat_Poison",
        fallback = "Poison",
        getter   = function(item)
            if not canShowExactStat("foodPoison") then return end
            if not item or not instanceof(item, "Food") then return end
            local v
            if item.getPoisonPower then
                v = item:getPoisonPower()
            end
            if (not v or v == 0) and item.getScriptItem then
                local script = item:getScriptItem()
                if script and script.getPoisonPower then
                    v = script:getPoisonPower()
                end
            end
            if not v or v == 0 then return end
            return InspectUI_fmtNumber(v, 2)
        end,
    },
}

M.order = {
    "hunger",
    "thirst",
    "freshState",
    "staleState",
    "rottenState",
    "burnedState",
    "burnTime",
    "unhappiness",
    "calories",
    "carbs",
    "proteins",
    "fat",
    "daysFresh",
    "daysRotten",
    "foodPoison",
}

return M
