--[[
    Commander 3.0 - Currency Data Source

    Provides access to player currencies.
    Commands: currency, currencies

    Supports both Retail and Classic
]]

local ADDON_NAME, C3 = ...

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

-------------------------------------------------------------------------------
-- Currency Type Registration
-------------------------------------------------------------------------------

C3.Types:Register("Currency", {
    description = "Currency from currency tab",
    source = "currencies",
    properties = {
        { "id", "Currency ID number" },
        { "name", "Currency name" },
        { "icon", "Icon texture ID" },
        { "quantity", "Current amount owned" },
        { "maxQuantity", "Maximum cap (0 if no cap)" },
        { "weeklyQuantity", "Amount earned this week" },
        { "maxWeeklyQuantity", "Weekly cap (0 if no cap)" },
        { "isDiscovered", "true if discovered" },
        { "quality", "Quality: 1=Common, 2=Uncommon, etc." },
        { "isHeader", "true if category header" },
        { "isExpanded", "true if header expanded" },
    },
    format = function(self)
        local icon = self.icon and (C3.Formatter:Icon(self.icon) .. " ") or ""
        local name = self.name or "Unknown Currency"
        local qty = self.quantity or 0

        -- Color by quality
        local qualityColors = {
            [0] = "9d9d9d", -- Poor
            [1] = "ffffff", -- Common
            [2] = "1eff00", -- Uncommon
            [3] = "0070dd", -- Rare
            [4] = "a335ee", -- Epic
            [5] = "ff8000", -- Legendary
        }
        local color = qualityColors[self.quality or 1] or "ffffff"

        local display = string.format("%s|cff%s%s|r: %s",
            icon, color, name, Colorize(C3.Formatter:FormatNumber(qty), "status.gold"))

        if self.maxQuantity and self.maxQuantity > 0 then
            display = display .. string.format(" / %s", C3.Formatter:FormatNumber(self.maxQuantity))
        end

        return display
    end
})

-- Register formatter
C3.Formatter:Register("Currency", {
    format = function(obj)
        local icon = obj.icon and (C3.Formatter:Icon(obj.icon) .. " ") or ""
        local name = obj.name or "Unknown Currency"
        local qty = obj.quantity or 0

        local qualityColors = {
            [0] = "9d9d9d",
            [1] = "ffffff",
            [2] = "1eff00",
            [3] = "0070dd",
            [4] = "a335ee",
            [5] = "ff8000",
        }
        local color = qualityColors[obj.quality or 1] or "ffffff"

        local display = string.format("%s|cff%s%s|r: %s",
            icon, color, name, Colorize(tostring(qty), "status.gold"))

        if obj.maxQuantity and obj.maxQuantity > 0 then
            display = display .. string.format(" / %s", tostring(obj.maxQuantity))
        end

        return display
    end,
    list = function(obj)
        local icon = obj.icon and (C3.Formatter:Icon(obj.icon) .. " ") or ""
        return string.format("%s%s: %d", icon, obj.name or "?", obj.quantity or 0)
    end,
    compact = function(obj)
        return string.format("%s: %d", obj.name or "?", obj.quantity or 0)
    end
})

-------------------------------------------------------------------------------
-- API Compatibility
-------------------------------------------------------------------------------

local function isRetailCurrency()
    return C_CurrencyInfo and C_CurrencyInfo.GetCurrencyListSize
end

-------------------------------------------------------------------------------
-- currencies - List all currencies
-------------------------------------------------------------------------------

C3.Command:Define({
    name = "currencies",
    description = "List player currencies",
    category = "data",
    producesType = "Currency",
    acceptsInput = false,
    flags = {
        all = { short = "a", description = "Include header categories" },
        discovered = { short = "d", description = "Show only discovered currencies" },
        capped = { short = "c", description = "Show only capped currencies" },
    },
    execute = function(ctx)
        local showAll = ctx:HasFlag("all") or ctx:HasFlag("a")
        local discoveredOnly = ctx:HasFlag("discovered") or ctx:HasFlag("d")
        local cappedOnly = ctx:HasFlag("capped") or ctx:HasFlag("c")

        -- Build results array with yielding to prevent freezing
        -- We can't use ctx:Produce() because coroutine.wrap() creates a C-call
        -- boundary that prevents yielding during iteration
        local results = {}
        local processed = 0
        local YIELD_INTERVAL = C3.Constants.YIELD_INTERVAL

        if isRetailCurrency() then
            -- Retail: First expand all headers to see all currencies
            local function expandAllHeaders()
                local changed = true
                local iterations = 0
                local MAX_ITERATIONS = 100  -- Safety limit to prevent infinite loop
                while changed and iterations < MAX_ITERATIONS do
                    iterations = iterations + 1
                    changed = false
                    local size = C_CurrencyInfo.GetCurrencyListSize()
                    for i = 1, size do
                        local info = C_CurrencyInfo.GetCurrencyListInfo(i)
                        if info and info.isHeader and not info.isHeaderExpanded then
                            C_CurrencyInfo.ExpandCurrencyList(i, true)
                            changed = true
                            break -- List indices change after expand, restart
                        end
                    end
                end
            end

            expandAllHeaders()

            -- Now iterate through all currencies
            local numCurrencies = C_CurrencyInfo.GetCurrencyListSize()

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

                local info = C_CurrencyInfo.GetCurrencyListInfo(i)

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

                -- Handle headers
                if info.isHeader then
                    if showAll then
                        table.insert(results, C3.Types.Create("Currency", {
                            id = 0,
                            name = info.name,
                            icon = info.iconFileID,
                            quantity = 0,
                            maxQuantity = 0,
                            isHeader = true,
                            isExpanded = info.isHeaderExpanded,
                        }))
                    end
                    break
                end

                -- Guard: Discovered filter
                if discoveredOnly and not info.discovered then break end

                -- Guard: Capped filter
                if cappedOnly then
                    if not info.maxQuantity or info.maxQuantity == 0 then break end
                    if info.quantity < info.maxQuantity then break end
                end

                -- All guards passed - add result
                table.insert(results, C3.Types.Create("Currency", {
                    id = info.currencyID,
                    name = info.name,
                    icon = info.iconFileID,
                    quantity = info.quantity,
                    maxQuantity = info.maxQuantity,
                    weeklyQuantity = info.quantityEarnedThisWeek,
                    maxWeeklyQuantity = info.maxWeeklyQuantity,
                    isDiscovered = info.discovered,
                    quality = info.quality,
                    isHeader = false,
                }))
            until true end
        else
            -- Classic fallback: limited currency support
            -- Try common currency IDs
            local commonCurrencies = {
                1, -- Currency Token Test Token 1
                -- Add Classic-specific currency IDs as needed
            }

            for _, currencyID in ipairs(commonCurrencies) do
                local info = C_CurrencyInfo and C_CurrencyInfo.GetCurrencyInfo(currencyID)
                if info and info.name then
                    table.insert(results, C3.Types.Create("Currency", {
                        id = currencyID,
                        name = info.name,
                        icon = info.iconFileID,
                        quantity = info.quantity,
                        maxQuantity = info.maxQuantity,
                        isDiscovered = info.discovered,
                        quality = info.quality or 1,
                    }))
                end
            end
        end

        return results
    end
})

-------------------------------------------------------------------------------
-- gold - Show player gold
-------------------------------------------------------------------------------

C3.Command:Define({
    name = "gold",
    description = "Show player gold",
    category = "data",
    acceptsInput = false,
    execute = function(ctx)
        local copper = GetMoney()
        local gold = math.floor(copper / 10000)
        local silver = math.floor((copper % 10000) / 100)
        local copperRem = copper % 100

        local display = string.format("|cffffd700%d|rg |cffc0c0c0%d|rs |cffb87333%d|rc",
            gold, silver, copperRem)

        return C3.Types.Create("Currency", {
            id = 0,
            name = "Gold",
            icon = 133784, -- Gold coin icon
            quantity = gold,
            maxQuantity = 0,
            quality = 5, -- Legendary color for gold
            display = display,
        })
    end
})

return true
