-- @author DoomTero 2026

ZR_Trait = ZR_Trait or {}

local ZR_TRAIT_IDS = {
    Sexaddict      = "zomborut:sexaddict",
    Masochist      = "zomborut:masochist",
    Rapist         = "zomborut:rapist",
    Wimp           = "zomborut:wimp",
    Necrophiliac   = "zomborut:necrophiliac",
    Virgin         = "zomborut:virgin",
    Inexperienced  = "zomborut:inexperienced",
    Experienced    = "zomborut:experienced",
    Nymphomaniac   = "zomborut:nymphomaniac",
    Innocent       = "zomborut:innocent",
    Lewd           = "zomborut:lewd",
    Traumatized    = "zomborut:traumatized",
    succubus       = "zomborut:succubus",
    submissive     = "zomborut:submissive",
    dominate       = "zomborut:dominate",
    youngBuck      = "zomborut:youngbuck",
    AARP           = "zomborut:aarp",
    inPrime        = "zomborut:inprime",
    spunkDefault   = "zomborut:spunkdefault",
    lowEffort      = "zomborut:loweffort",
    smokesAfter    = "zomborut:smokesafter",
    betterAlive    = "zomborut:betteralive",
    itFollows      = "zomborut:itfollows",
    promiscuous    = "zomborut:promiscuous",
    swinger        = "zomborut:swinger",
    unkempt        = "zomborut:unkempt",
    neatTidy       = "zomborut:neattidy",
    lovesClean     = "zomborut:lovesclean",
    viciousZombies = "zomborut:viciouszombies",
    dpress         = "zomborut:dpress",
    proteinDiet    = "zomborut:proteindiet",
    hydration      = "zomborut:hydration",
    drained        = "zomborut:drained",
    fighter        = "zomborut:fighter",
    glassBones     = "zomborut:glassbones",
    cardioJunkie   = "zomborut:cardiojunkie",
    Conspicuous2   = "zomborut:conspicuous2",
    Desensitized2  = "zomborut:desensitized2",
    Conspicuous    = "base:conspicuous",
    Inconspicuous  = "base:inconspicuous",
    Desensitized   = "base:desensitized",
    Brave          = "base:brave",
    Cowardly       = "base:cowardly",
}

local _cache = {}
local NIL_SENTINEL = {}

setmetatable(ZR_Trait, {
    __index = function(_, key)
        local loc = ZR_TRAIT_IDS[key]
        if not loc then return nil end
        local cached = _cache[key]
        if cached == NIL_SENTINEL then return nil end
        if cached ~= nil then return cached end
        local obj = CharacterTrait.get(ResourceLocation.of(loc))
        if obj == nil then
            print("[ZomboRut] WARN: CharacterTrait.get returned nil for " .. loc .. " (cached; won't re-warn)")
            _cache[key] = NIL_SENTINEL
            return nil
        end
        _cache[key] = obj
        return obj
    end,
})

function ZR_Trait.has(character, key)
    if character == nil then return false end
    local trait = ZR_Trait[key]
    if trait == nil then return false end
    local charTraits = character:getCharacterTraits()
    if charTraits == nil then return false end
    local map = charTraits:getTraits()
    if map == nil or not map:containsKey(trait) then return false end
    return character:hasTrait(trait)
end

function ZR_Trait.seedAll(character)
    if character == nil then return end
    local charTraits = character:getCharacterTraits()
    if charTraits == nil then return end
    local map = charTraits:getTraits()
    if map == nil then return end
    for key, _ in pairs(ZR_TRAIT_IDS) do
        local trait = ZR_Trait[key]
        if trait ~= nil and not map:containsKey(trait) then
            charTraits:set(trait, false)
        end
    end
end

local SEED_FLAG = "ZR_TraitMapSeeded_v2"

function ZR_Trait.ensureSeeded(character)
    if character == nil then return end
    local md = character:getModData()
    if md == nil then return end
    if md[SEED_FLAG] == true then return end
    ZR_Trait.seedAll(character)
    md[SEED_FLAG] = true
end

local function seedOnCreatePlayer(_, player) ZR_Trait.ensureSeeded(player) end

local function seedOnGameStart()
    local p = getPlayer()
    if p ~= nil then ZR_Trait.ensureSeeded(p) end
end

local firstTickSeed
firstTickSeed = function(player)
    if player == nil then return end
    ZR_Trait.ensureSeeded(player)
    Events.OnPlayerUpdate.Remove(firstTickSeed)
end

Events.OnCreatePlayer.Add(seedOnCreatePlayer)
Events.OnGameStart.Add(seedOnGameStart)
Events.OnPlayerUpdate.Add(firstTickSeed)
