--[[
    Commander 3.0 - Toys Data Source

    Provides access to player toy collection.
    Commands: toys, toy
]]

local ADDON_NAME, C3 = ...

-- Use shared utilities
local Colorize = function(...) return C3.Colors.Colorize(...) end
local fuzzyMatch = function(...) return C3.StringUtils.fuzzyMatch(...) end

-------------------------------------------------------------------------------
-- Toy Type Registration
-------------------------------------------------------------------------------

C3.Types:Register("Toy", {
    description = "Collected toy from toy box",
    source = "toys",
    properties = {
        { "id", "Toy item ID" },
        { "name", "Toy name" },
        { "icon", "Icon texture ID" },
        { "isFavorite", "true if marked favorite" },
        { "isUsable", "true if can be used now" },
        { "hasFanfare", "true if has special effect" },
    },
})

C3.Formatter:Register("Toy", {
    format = function(obj)
        local prefix = ""
        if obj.isFavorite then
            prefix = Colorize("*", "accent.warning") .. " "
        end

        local icon = obj.icon and (C3.Formatter:Icon(obj.icon) .. " ") or ""
        local name = obj.name or "Unknown"
        if not obj.isUsable then
            name = Colorize(name, "status.dim")
        end

        return string.format("%s%s%s", prefix, icon, name)
    end,
    list = function(obj)
        local icon = obj.icon and (C3.Formatter:Icon(obj.icon) .. " ") or ""
        local fav = obj.isFavorite and (Colorize("*", "accent.warning")) or ""
        return fav .. icon .. (obj.name or "?")
    end,
    compact = function(obj)
        return obj.name or "?"
    end
})

-------------------------------------------------------------------------------
-- Toys Intellisense Provider
-------------------------------------------------------------------------------

local MAX_SUGGESTIONS = C3.Constants.MAX_SUGGESTIONS

C3.Intellisense:RegisterProvider("Toys", function(partial, ctx)
    if not C_ToyBox then
        return {}
    end

    -- Set up filters to get collected toys
    C_ToyBox.SetAllSourceTypeFilters(true)
    C_ToyBox.SetCollectedShown(true)
    C_ToyBox.SetUncollectedShown(false)
    C_ToyBox.SetFilterString("")
    C_ToyBox.ForceToyRefilter()

    -- Collect toys
    local toys = {}
    local numToys = C_ToyBox.GetNumFilteredToys()
    for i = 1, numToys do
        local itemID = C_ToyBox.GetToyFromIndex(i)
        if itemID and itemID > 0 then
            local toyID, name, icon, isFavorite = C_ToyBox.GetToyInfo(itemID)
            if toyID and name and fuzzyMatch(partial, name) then
                toys[#toys + 1] = {
                    name = name,
                    icon = icon,
                    isFavorite = isFavorite,
                }
                if #toys >= MAX_SUGGESTIONS then break end
            end
        end
    end

    local results = {}
    for _, toy in ipairs(toys) do
        results[#results + 1] = {
            text = toy.name,
            description = toy.isFavorite and "Favorite" or "Toy",
            icon = toy.icon,
        }
    end
    return results
end)

-------------------------------------------------------------------------------
-- toys - List toy collection
-------------------------------------------------------------------------------

C3.Command:Define({
    name = "toys",
    description = "List collected toys",
    category = "data",
    producesType = "Toy",
    acceptsInput = false,
    flags = {
        all = { short = "a", description = "Show all toys (including uncollected)" },
        usable = { short = "u", description = "Show only usable toys" },
        favorites = { short = "f", description = "Show only favorite toys" },
    },
    execute = function(ctx)
        local showAll = ctx:HasFlag("all") or ctx:HasFlag("a")
        local usableOnly = ctx:HasFlag("usable") or ctx:HasFlag("u")
        local favoritesOnly = ctx:HasFlag("favorites") or ctx:HasFlag("f")

        if not C_ToyBox then
            return ctx:Error("Toy Box not available in this game version")
        end

        -- Build results array with yielding to prevent freezing
        local results = {}
        local YIELD_INTERVAL = C3.Constants.YIELD_INTERVAL
        local numToys = C_ToyBox.GetNumToys()

        for i = 1, numToys do repeat
            -- Yield periodically
            if i % YIELD_INTERVAL == 0 then
                coroutine.yield()
            end

            local itemID = C_ToyBox.GetToyFromIndex(i)

            -- Guard: Invalid item
            if not itemID or itemID <= 0 then break end

            local toyID, name, icon, isFavorite, hasFanfare, itemQuality = C_ToyBox.GetToyInfo(itemID)

            -- Guard: Invalid toy info
            if not toyID then break end

            local isCollected = PlayerHasToy(toyID)
            local isUsable = C_ToyBox.IsToyUsable(toyID)

            -- Guard: Not collected (unless --all)
            if not showAll and not isCollected then break end

            -- Guard: Usable filter
            if usableOnly and not isUsable then break end

            -- Guard: Favorites filter
            if favoritesOnly and not isFavorite then break end

            -- All guards passed - add result
            table.insert(results, C3.Types.Create("Toy", {
                id = toyID,
                itemID = itemID,
                name = name,
                icon = icon,
                isFavorite = isFavorite,
                hasFanfare = hasFanfare,
                quality = itemQuality,
                isCollected = isCollected,
                isUsable = isUsable,
            }))
        until true end

        return results
    end
})

-------------------------------------------------------------------------------
-- toy - Use a toy
-------------------------------------------------------------------------------

C3.Command:Define({
    name = "toy",
    description = "Use a toy by name",
    category = "action",
    acceptsInput = false,
    args = {
        { name = "name", required = true, description = "Toy name (partial match)",
          provider = "Toys" }
    },
    execute = function(ctx)
        local query = ctx:GetArg(1)

        if not query then
            return ctx:Error("Usage: toy <name>")
        end

        if not C_ToyBox then
            return ctx:Error("Toy Box not available")
        end

        -- Search for toy by exact name (case-insensitive)
        local queryLower = query:lower()
        local matchedToy = nil

        -- Set up filters to search collected toys
        C_ToyBox.SetAllSourceTypeFilters(true)
        C_ToyBox.SetCollectedShown(true)
        C_ToyBox.SetUncollectedShown(false)
        C_ToyBox.SetFilterString("")
        C_ToyBox.ForceToyRefilter()

        local numToys = C_ToyBox.GetNumFilteredToys()

        for i = 1, numToys do repeat
            local itemID = C_ToyBox.GetToyFromIndex(i)

            -- Guard: Invalid item
            if not itemID or itemID <= 0 then break end

            local toyID, name = C_ToyBox.GetToyInfo(itemID)

            -- Guard: Invalid toy info
            if not toyID or not name then break end

            -- Strict: exact match only (case-insensitive)
            if name:lower() == queryLower then
                matchedToy = { id = toyID, itemID = itemID, name = name }
                break
            end
        until true end

        if not matchedToy then
            return ctx:Error("Toy not found: " .. query)
        end

        -- If we're called, secure action wasn't pre-armed
        -- Give instructions like other secure commands
        return ctx:Text("Type 'toy " .. matchedToy.name .. "' and press Enter to use")
    end
})

-------------------------------------------------------------------------------
-- Intellisense Provider for Toys
-------------------------------------------------------------------------------

-- Provider is added to C3.Intellisense.Providers in core/intellisense.lua
-- We define it here after the toys API functions are available

return true
