----------------------------------------------------------
-- Category_Tools.lua
-- Token-based rules (v3.8)
----------------------------------------------------------

local C = {}
C.parent = "Tool"

-- token tables
local TOKENS = {
    ToolCrafted      = { "crafted", "improvised", "homemade", "makeshift" },

    EquipBackpack    = { "bag", "container", "memento", "backpack", "case", "satchel", "basket", "satchel", "framepack" },
    EquipContainer   = { "container", "storage" },
    EquipToolbox     = { "toolbox", "tool box" },
    EquipCamping     = { "camping" },
    EquipSleepingBag = { "sleeping bag", "sleepingbag", "sleepbag" },
    EquipTent        = { "tent", "canopy" },
    EquipHousehold   = { "house", "household" },
    EquipSecurity    = { "security", "padlock", "lock", "key", "chain", "llave", "candado", "seguridad" },
    EquipToy         = { "raccoon", "spiffo", "teddy", "bear", "plush", "toy", "spider" },
    EquipBackTorso   = { "suspenders", "bandolier", "pack", "rig" },
    EquipWallet      = { "wallet", "billfold" },
    EquipKeyring     = { "keyring", "key ring", "keychain", "key chain" },
    EquipOpener      = { "opener", "bottle opener", "can opener", "corkscrew" },
    EquipPaint       = { "paint", "spray paint", "spraypaint", "spray can", "graffiti" },
    EquipSports      = { "ball", "sport" },
    EquipCooking     = { "cook", "pan", "pot", "tray", "bake", "mold", "muffin", "skillet", "saucepan" },
    EquipFishing     = { "fish", "bobber", "float", "lure", "hook", "rod", "line", "reel" },
    EquipInstrument  = { "instrument", "guitar", "whistle", "flute", "drum", "violin", "trumpet", "sax" },
    EquipBox         = { "box", "crate", "case", "pack", "carton" },
    EquipVehiclePart = { "vehicle", "maintenance", "hood", "door", "trunk", "bumper", "fender", "charger", "battery", "engine", "tire", "wheel" },
    EquipTrapping    = { "trapping", "trap", "snare", "cage", "box trap" },

    GardeningBase    = { "garden", "farming", "seed", "plant", "seedling", "sapling", "fertilizer", "watering", "packet" },
    GardenWeapon     = { "rake", "hoe", "shovel" },
    SeedPacket       = { "seedpacket", "packet seed", "seed packet" },
    Seed             = { "seed" },
    Plants           = { "plant", "seedling", "sapling", "sprout" },
}

-- Universal token matcher for all categories
local function matchTokens(text, tokens)
    for _, token in ipairs(tokens) do
        if text:find(token, 1, true) then
            return true
        end
    end
    return false
end

local function lower(val)
    if not val then return "" end
    return string.lower(tostring(val))
end

local function getDisplayCategory(item)
    return lower(item.getDisplayCategory and item:getDisplayCategory())
end

local function getCategory(item)
    return lower(item.getCategory and item:getCategory())
end

local function getText(item)
    local name = lower(item.getDisplayName and item:getDisplayName())
    local dc   = getDisplayCategory(item)
    return (name or "") .. " " .. (dc or "")
end

local function isTool(item)
    local dc = getDisplayCategory(item)
    local cat = getCategory(item)
    return dc:find("tool", 1, true) ~= nil or cat:find("tool", 1, true) ~= nil
end

local function isEquipment(item, statMap)
    local dc = getDisplayCategory(item)
    local cat = getCategory(item)

    -- Seguridad/llaves cuentan como equipo
    if dc:find("security", 1, true) or cat:find("security", 1, true) or dc:find("key", 1, true) or cat:find("key", 1, true) then
        return true
    end

    local isFluid = (statMap and statMap["fluidCapacity"] ~= nil)
        or (InspectUI_isFluidContainer and InspectUI_isFluidContainer(item))
        or dc:find("water", 1, true) ~= nil
        or dc:find("watercontainer", 1, true) ~= nil
        or dc:find("fuel", 1, true) ~= nil
    if isFluid then
        return false
    end

    return dc:find("container") ~= nil
        or dc:find("camping") ~= nil
        or dc:find("tool") ~= nil
        or dc:find("bag") ~= nil
        or dc:find("luggage") ~= nil
        or dc:find("storage") ~= nil
        or dc:find("memento") ~= nil
        or dc:find("cook", 1, true) ~= nil
        or dc:find("fish", 1, true) ~= nil
        or dc:find("trapping") ~= nil
        or dc:find("trap") ~= nil
        or dc:find("box") ~= nil
        or dc:find("crate") ~= nil
        or dc:find("vehicle", 1, true) ~= nil
        or dc:find("maintenance", 1, true) ~= nil
        or dc:find("security", 1, true) ~= nil
        or cat:find("cook", 1, true) ~= nil
        or cat:find("fish", 1, true) ~= nil
        or cat:find("key", 1, true) ~= nil
        or (item.isContainer and item:isContainer())
        or (item.getDisplayName and getText(item):find("box", 1, true))
end

local function isGardening(item)
    local text = getText(item)
    return matchTokens(text, TOKENS.GardeningBase)
end

C.rules = {
    -- Tool base
    {
        id = "Tool.BaseCheck",
        priority = 50,
        match = function(item, statMap)
            return isTool(item)
        end,
        category = "Tool",
    },

    {
        id = "Tool.Crafted",
        priority = 100,
        match = function(item, statMap)
            if not isTool(item) then return false end
            return matchTokens(getText(item), TOKENS.ToolCrafted)
        end,
        category = "Tool/Crafted",
    },

    -- Equipment base
    {
        id = "Equipment.BaseCheck",
        priority = 50,
        match = function(item, statMap)
            return isEquipment(item, statMap)
        end,
        category = "Equipment",
    },

    {
        id = "Equipment.Backpack",
        priority = 100,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            local text = getText(item)
            if text:find("box", 1, true) or text:find("crate", 1, true) or text:find("carton", 1, true) then
                return false
            end
            return matchTokens(text, TOKENS.EquipBackpack)
        end,
        category = "Equipment/Backpack",
    },

    {
        id = "Equipment.Container",
        priority = 95,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            local text = getText(item)
            if matchTokens(text, TOKENS.EquipContainer) then return true end
            return item.isContainer and item:isContainer()
        end,
        category = "Equipment/Container",
    },

    {
        id = "Equipment.Toolbox",
        priority = 95,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            return matchTokens(getText(item), TOKENS.EquipToolbox)
        end,
        category = "Equipment/Toolbox",
    },

    {
        id = "Equipment.Camping",
        priority = 95,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            return matchTokens(getText(item), TOKENS.EquipCamping)
        end,
        category = "Equipment/Camping",
    },

    {
        id = "Equipment.SleepingBag",
        priority = 98,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            return matchTokens(getText(item), TOKENS.EquipSleepingBag)
        end,
        category = "Equipment/SleepingBag",
    },

    {
        id = "Equipment.BackTorso",
        priority = 97,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            return matchTokens(getText(item), TOKENS.EquipBackTorso)
        end,
        category = "Equipment/BackTorso",
    },

    {
        id = "Equipment.Wallet",
        priority = 96,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            return matchTokens(getText(item), TOKENS.EquipWallet)
        end,
        category = "Equipment/Wallet",
    },

    {
        id = "Equipment.Keyring",
        priority = 101,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            return matchTokens(getText(item), TOKENS.EquipKeyring)
        end,
        category = "Equipment/Keyring",
    },

    {
        id = "Equipment.Tent",
        priority = 98,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            return matchTokens(getText(item), TOKENS.EquipTent)
        end,
        category = "Equipment/Tent",
    },

    {
        id = "Equipment.Household",
        priority = 95,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            return matchTokens(getText(item), TOKENS.EquipHousehold)
        end,
        category = "Equipment/Household",
    },

    {
        id = "Equipment.Security",
        priority = 120,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            local cat = getCategory(item)
            if cat:find("key", 1, true) then return true end
            return matchTokens(getText(item), TOKENS.EquipSecurity)
        end,
        category = "Equipment/Security",
    },

    {
        id = "Equipment.Toy",
        priority = 95,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            return matchTokens(getText(item), TOKENS.EquipToy)
        end,
        category = "Equipment/Toy",
    },

    {
        id = "Equipment.Paint",
        priority = 110,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            return matchTokens(getText(item), TOKENS.EquipPaint)
        end,
        category = "Equipment/Paint",
    },

    {
        id = "Equipment.Sports",
        priority = 95,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            return matchTokens(getText(item), TOKENS.EquipSports)
        end,
        category = "Equipment/Sports",
    },

    {
        id = "Equipment.Opener",
        priority = 96,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            return matchTokens(getText(item), TOKENS.EquipOpener)
        end,
        category = "Equipment/Opener",
    },

    {
        id = "Equipment.Cooking",
        priority = 95,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            return matchTokens(getText(item), TOKENS.EquipCooking)
        end,
        category = "Equipment/Cooking",
    },

    {
        id = "Equipment.Fishing",
        priority = 95,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            return matchTokens(getText(item), TOKENS.EquipFishing)
        end,
        category = "Equipment/Fishing",
    },

    {
        id = "Equipment.Instrument",
        priority = 95,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            return matchTokens(getText(item), TOKENS.EquipInstrument)
        end,
        category = "Equipment/Instrument",
    },

    {
        id = "Equipment.Box",
        priority = 95,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            local text = getText(item)
            if matchTokens(text, TOKENS.EquipBox) then return true end
            local dc = getDisplayCategory(item)
            return dc:find("box") ~= nil or dc:find("crate") ~= nil
        end,
        category = "Equipment/Box",
    },

    {
        id = "Equipment.VehiclePart",
        priority = 100,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            return matchTokens(getText(item), TOKENS.EquipVehiclePart)
        end,
        category = "Equipment/VehiclePart",
    },

    {
        id = "Equipment.Trapping",
        priority = 95,
        match = function(item, statMap)
            if not isEquipment(item, statMap) then return false end
            return matchTokens(getText(item), TOKENS.EquipTrapping)
        end,
        category = "Equipment/Trapping",
    },

    -- Gardening (shared within this file)
    {
        id = "Gardening.BaseCheck",
        priority = 50,
        match = function(item, statMap)
            return isGardening(item)
        end,
        category = "Gardening",
    },

    {
        id = "Gardening.GardenWeapon",
        priority = 110,
        match = function(item, statMap)
            if not isGardening(item) then return false end
            local text = getText(item)
            local cat = getCategory(item)
            local isWeapon = cat:find("weapon", 1, true) ~= nil or (instanceof and instanceof(item, "HandWeapon"))
            return isWeapon and matchTokens(text, TOKENS.GardenWeapon)
        end,
        category = "Gardening/GardenWeapon",
    },

    {
        id = "Gardening.SeedPacket",
        priority = 100,
        match = function(item, statMap)
            if not isGardening(item) then return false end
            local text = getText(item)
            return matchTokens(text, TOKENS.SeedPacket)
        end,
        category = "Gardening/SeedPacket",
    },

    {
        id = "Gardening.Seed",
        priority = 95,
        match = function(item, statMap)
            if not isGardening(item) then return false end
            local text = getText(item)
            if matchTokens(text, TOKENS.SeedPacket) then return false end
            return matchTokens(text, TOKENS.Seed)
        end,
        category = "Gardening/Seed",
    },

    {
        id = "Gardening.Plants",
        priority = 90,
        match = function(item, statMap)
            if not isGardening(item) then return false end
            return matchTokens(getText(item), TOKENS.Plants)
        end,
        category = "Gardening/Plants",
    },

    {
        id = "Tools.Base",
        priority = 50,
        match = function(item, statMap)
            local dc = item.getDisplayCategory and item:getDisplayCategory() or ""
            dc = string.lower(dc)
            return dc:find("tool", 1, true) ~= nil
        end,
        category = "Tools",
    },
}

return C
