local CannibalismUtils = {}

function CannibalismUtils.isCandy(item)
    local items = SandboxVars.Cannibalism.CandyItems or ""
    for candyItem in string.gmatch(items, '([^;]+)') do
        if getScriptManager():getItem(candyItem):getFullName() == item:getFullType() then return true end
    end
    return false
end

function CannibalismUtils.getPlayerInsanityPoints(character)
    local currentInsanityPoints = character:getModData().Cannibalism_InsanityPoints or 0
    return currentInsanityPoints
end

function CannibalismUtils.getPlayerInsanityStage(character)
    local presetVars = CannibalismUtils.getInsanitySettings()

    local stageOnePoints = presetVars.StageOneInsanityPoints
    local stageTwoPoints = presetVars.StageTwoInsanityPoints
    local stageThreePoints = presetVars.StageThreeInsanityPoints
    local currentInsanityPoints = CannibalismUtils.getPlayerInsanityPoints(character)

    -- Check if the system is "Off" (all thresholds are 0)
    if stageOnePoints == 0 and stageTwoPoints == 0 and stageThreePoints == 0 then
        return 0.5 -- Default to no insanity stage when system is "Off"
    end

    -- Determine the insanity stage
    if currentInsanityPoints < stageOnePoints then
        return 0.5
    elseif currentInsanityPoints >= stageOnePoints and currentInsanityPoints < stageTwoPoints then
        return 0.4
    elseif currentInsanityPoints >= stageTwoPoints and currentInsanityPoints < stageThreePoints then
        return 0.3
    elseif currentInsanityPoints >= stageThreePoints then
        return 0.2
    end
end

function CannibalismUtils.getKnife(playerNum)
    local character = getSpecificPlayer(playerNum)
    if not character then return nil end

    local inventory = character:getInventory()

    local itemsToCheck = {
        { type = "MeatCleaver" },
        { type = "Chainsaw" },
        { tag = "ChopTree" },
        { tag = "SharpKnife" },
        { tag = "Saw" }
    }

    for _, item in ipairs(itemsToCheck) do
        if item.type then
            item = inventory:getFirstTypeRecurse(item.type)
            if item then
                if not item:isBroken() then
                    return item
                end
            end
        elseif item.tag then
            item = inventory:getFirstTagRecurse(item.tag)
            if item then
                if not item:isBroken() then
                    return item
                end
            end
        end
    end

    return nil
end

function CannibalismUtils.splitString(str)
    local result = {}
    for match in string.gmatch(str, '([^;]+)') do
        table.insert(result, match)
    end
    return result
end

function CannibalismUtils.getRandomSound(soundString)
    -- Split the string into a list of sounds
    local sounds = CannibalismUtils.splitString(soundString)

    -- Check if the list is not empty
    if #sounds == 0 then
        return nil
    end

    -- Generate a random index
    local randomIndex = ZombRand(#sounds + 1)

    -- Return the randomly selected sound
    return sounds[randomIndex]
end

function CannibalismUtils.getCandyItems()
    local items = SandboxVars.Cannibalism.CandyItems or ""
    local itemsToEdit = {}
    for item in string.gmatch(items, '([^;]+)') do
        table.insert(itemsToEdit, item)
    end
    return itemsToEdit
end

function CannibalismUtils.getInsanitySettings()
    local sandboxSettings = SandboxVars.Cannibalism
    local settings = {}

    -- Define preset values in a table
    local presets = {
        Off = {
            PointsGain = { 0, 0, 0, 0 },  -- The amount of points the player gains when consuming certain types of meats
            InsanityPoints = { 0, 0, 0 }, -- The amount of points needed to trigger each stage of insanity
            SoundFrequency = { 0, 0, 0 }, -- After how many real life minutes should a player hear the insanity sounds at each stage of insanity
            SoundChance = { 0, 0, 0 }     -- The chance for a sound to trigger after each "Frequency" interval for each insanity stage
        },
        Low = {
            PointsGain = { 1, 1, 1, 1 },
            InsanityPoints = { 30, 60, 100 },
            SoundFrequency = { 50, 30, 20 },
            SoundChance = { 5, 7, 10 }
        },
        Med = {
            PointsGain = { 2, 1, 2, 1 },
            InsanityPoints = { 20, 40, 80 },
            SoundFrequency = { 40, 20, 10 },
            SoundChance = { 10, 15, 20 }
        },
        High = {
            PointsGain = { 3, 2, 3, 2 },
            InsanityPoints = { 10, 20, 40 },
            SoundFrequency = { 20, 10, 5 },
            SoundChance = { 15, 25, 35 }
        }
    }

    -- Determine preset
    local presetKey = sandboxSettings.SoundPresetOff and "Off"
        or sandboxSettings.SoundPresetLow and "Low"
        or sandboxSettings.SoundPresetMed and "Med"
        or sandboxSettings.SoundPresetHigh and "High"

    if presetKey then
        local preset = presets[presetKey]
        settings.RawZombieMeatInsanityPointsGain, settings.CookedZombieMeatInsanityPointsGain,
        settings.RawHumanMeatInsanityPointsGain, settings.CookedHumanMeatInsanityPointsGain = unpack(preset.PointsGain)

        settings.StageOneInsanityPoints, settings.StageTwoInsanityPoints, settings.StageThreeInsanityPoints = unpack(
            preset.InsanityPoints)
        settings.StageOneSoundFrequency, settings.StageTwoSoundFrequency, settings.StageThreeSoundFrequency = unpack(
            preset.SoundFrequency)
        settings.StageOneSoundChance, settings.StageTwoSoundChance, settings.StageThreeSoundChance = unpack(preset
            .SoundChance)
    else
        -- Custom settings
        settings.RawZombieMeatInsanityPointsGain = sandboxSettings.RawZombieMeatInsanityPointsGain
        settings.CookedZombieMeatInsanityPointsGain = sandboxSettings.CookedZombieMeatInsanityPointsGain
        settings.RawHumanMeatInsanityPointsGain = sandboxSettings.RawHumanMeatInsanityPointsGain
        settings.CookedHumanMeatInsanityPointsGain = sandboxSettings.CookedHumanMeatInsanityPointsGain

        settings.StageOneInsanityPoints = sandboxSettings.StageOneInsanityPoints
        settings.StageTwoInsanityPoints = sandboxSettings.StageTwoInsanityPoints
        settings.StageThreeInsanityPoints = sandboxSettings.StageThreeInsanityPoints

        settings.StageOneSoundFrequency = sandboxSettings.StageOneSoundFrequency
        settings.StageTwoSoundFrequency = sandboxSettings.StageTwoSoundFrequency
        settings.StageThreeSoundFrequency = sandboxSettings.StageThreeSoundFrequency

        settings.StageOneSoundChance = sandboxSettings.StageOneSoundChance
        settings.StageTwoSoundChance = sandboxSettings.StageTwoSoundChance
        settings.StageThreeSoundChance = sandboxSettings.StageThreeSoundChance
    end

    return settings
end

local humanTextures =
{
    ["MaleBody01"] = true,
    ["MaleBody01a"] = true,
    ["MaleBody02"] = true,
    ["MaleBody02a"] = true,
    ["MaleBody03"] = true,
    ["MaleBody03a"] = true,
    ["MaleBody04"] = true,
    ["MaleBody04a"] = true,
    ["MaleBody05"] = true,
    ["MaleBody05a"] = true,
    ["FemaleBody01"] = true,
    ["FemaleBody02"] = true,
    ["FemaleBody03"] = true,
    ["FemaleBody04"] = true,
    ["FemaleBody05"] = true,
}
---Checks if a dead body is human
---@param body IsoDeadBody
---@return boolean
function CannibalismUtils.isBodyHuman(body)
    if not body then return false end
    local humanVisual = body:getHumanVisual()
    if not humanVisual then return false end

    local skinTexture = humanVisual:getSkinTexture()
    if not skinTexture then return false end

    if humanTextures[skinTexture] then return true else return false end
end

return CannibalismUtils
