--[[
    Commander 3.0 - Macros Data Source

    Provides access to player macros.
    Commands: macros

    Shows macro name, body, icon, and scope (global vs character).
    Macros 1-120 are global, 121-138 are character-specific.
]]

local ADDON_NAME, C3 = ...

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

-------------------------------------------------------------------------------
-- Constants
-------------------------------------------------------------------------------

local MAX_GLOBAL_MACROS = 120
local MAX_CHARACTER_MACROS = 18
local FIRST_CHARACTER_MACRO = MAX_GLOBAL_MACROS + 1
local MAX_TOTAL_MACROS = MAX_GLOBAL_MACROS + MAX_CHARACTER_MACROS

-------------------------------------------------------------------------------
-- Macro Type Registration
-------------------------------------------------------------------------------

C3.Types:Register("Macro", {
    description = "Player macro",
    source = "macros",
    properties = {
        { "id", "Macro slot index" },
        { "name", "Macro name" },
        { "icon", "Icon texture ID" },
        { "body", "Macro body text" },
        { "isCharacter", "true if character-specific macro" },
        { "lineCount", "Number of lines in body" },
    },
    format = function(self)
        local scope = self.isCharacter and Colorize("[Char]", "accent.success") or Colorize("[Global]", "accent.warning")
        local icon = self.icon and (C3.Formatter:Icon(self.icon) .. " ") or ""
        local name = self.name or "Unnamed"

        -- Truncate body for preview
        local preview = ""
        if self.body and self.body ~= "" then
            local firstLine = self.body:match("^([^\n]+)")
            if firstLine then
                if #firstLine > 40 then
                    firstLine = firstLine:sub(1, 37) .. "..."
                end
                preview = " " .. Colorize("- " .. firstLine, "status.dim")
            end
        end

        return string.format("%s %s%s%s", scope, icon, name, preview)
    end
})

-- Register formatter
C3.Formatter:Register("Macro", {
    format = function(obj)
        local scope = obj.isCharacter and "[Char]" or "[Global]"
        local name = obj.name or "Unnamed"
        local preview = ""
        if obj.body and obj.body ~= "" then
            local firstLine = obj.body:match("^([^\n]+)")
            if firstLine then
                if #firstLine > 40 then
                    firstLine = firstLine:sub(1, 37) .. "..."
                end
                preview = " - " .. firstLine
            end
        end
        return string.format("%s %s%s", scope, name, preview)
    end,
    list = function(obj)
        local scope = obj.isCharacter and "C" or "G"
        return string.format("[%s] %s", scope, obj.name or "?")
    end,
    compact = function(obj)
        return obj.name or "?"
    end
})

-------------------------------------------------------------------------------
-- macros - List all macros
-------------------------------------------------------------------------------

C3.Command:Define({
    name = "macros",
    description = "List player macros",
    category = "data",
    acceptsInput = false,
    flags = {
        global = { short = "g", description = "Show only global macros" },
        character = { short = "c", description = "Show only character macros" },
        body = { short = "b", description = "Show full macro body" },
    },
    execute = function(ctx)
        local globalOnly = ctx:HasFlag("global") or ctx:HasFlag("g")
        local characterOnly = ctx:HasFlag("character") or ctx:HasFlag("c")
        local showBody = ctx:HasFlag("body") or ctx:HasFlag("b")

        local results = {}
        local processed = 0
        local YIELD_INTERVAL = C3.Constants.YIELD_INTERVAL

        -- Get macro counts
        local numGlobal, numCharacter = GetNumMacros()

        -- Iterate through all macro slots
        for i = 1, MAX_TOTAL_MACROS do repeat
            -- Yield periodically
            processed = processed + 1
            if processed % YIELD_INTERVAL == 0 then
                coroutine.yield()
            end

            local isCharacter = i >= FIRST_CHARACTER_MACRO

            -- Guard: Global filter
            if globalOnly and isCharacter then break end

            -- Guard: Character filter
            if characterOnly and not isCharacter then break end

            -- Get macro info
            local name, iconTexture, body = GetMacroInfo(i)

            -- Guard: Empty slot
            if not name or name == "" then break end

            -- Count lines in body
            local lineCount = 0
            if body and body ~= "" then
                for _ in body:gmatch("[^\n]+") do
                    lineCount = lineCount + 1
                end
            end

            -- All guards passed - add result
            table.insert(results, C3.Types.Create("Macro", {
                id = i,
                name = name,
                icon = iconTexture,
                body = body or "",
                isCharacter = isCharacter,
                lineCount = lineCount,
            }))
        until true end

        return results
    end
})

-------------------------------------------------------------------------------
-- macro <name> - Show specific macro details
-------------------------------------------------------------------------------

C3.Command:Define({
    name = "showmacro",
    description = "Show macro details",
    category = "data",
    acceptsInput = false,
    args = {
        {
            name = "name",
            required = true,
            description = "Macro name or slot number",
        }
    },
    execute = function(ctx)
        local query = ctx:GetArg(1)
        if not query then
            return ctx:Error("Usage: showmacro <name|slot>")
        end

        -- Try as slot number first
        local slot = tonumber(query)
        if slot then
            local name, iconTexture, body = GetMacroInfo(slot)
            if name then
                local isCharacter = slot >= FIRST_CHARACTER_MACRO
                return C3.Types.Create("Macro", {
                    id = slot,
                    name = name,
                    icon = iconTexture,
                    body = body or "",
                    isCharacter = isCharacter,
                })
            else
                return ctx:Error("No macro in slot " .. slot)
            end
        end

        -- Search by exact name (case-insensitive)
        local queryLower = query:lower()
        for i = 1, MAX_TOTAL_MACROS do
            local name, iconTexture, body = GetMacroInfo(i)
            if name and name:lower() == queryLower then
                local isCharacter = i >= FIRST_CHARACTER_MACRO
                return C3.Types.Create("Macro", {
                    id = i,
                    name = name,
                    icon = iconTexture,
                    body = body or "",
                    isCharacter = isCharacter,
                })
            end
        end

        return ctx:Error("Macro not found: " .. query)
    end
})

return true
