--[[
    Commander 3.0 - Keybinding Commands

    Commands: binds, bind, unbind

    Manage WoW keybindings from the terminal.
]]

local ADDON_NAME, C3 = ...

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

-------------------------------------------------------------------------------
-- Keybinding Type Registration
-------------------------------------------------------------------------------

C3.Types:Register("Keybinding", {
    description = "Keybinding mapping",
    source = "binds",
    properties = {
        { "action", "Action/command name" },
        { "key1", "Primary key binding" },
        { "key2", "Secondary key binding" },
        { "category", "Binding category" },
    },
    format = function(self)
        local keys = {}
        if self.key1 and self.key1 ~= "" then
            keys[#keys + 1] = Colorize(self.key1, "accent.success")
        end
        if self.key2 and self.key2 ~= "" then
            keys[#keys + 1] = Colorize(self.key2, "accent.success")
        end

        local keyStr = #keys > 0 and table.concat(keys, ", ") or Colorize("(unbound)", "status.dim")
        return string.format("%s %s", Colorize(string.format("%-30s", self.action or "?"), "accent.warning"), keyStr)
    end
})

-------------------------------------------------------------------------------
-- binds - List keybindings
-------------------------------------------------------------------------------

C3.Command:Define({
    name = "binds",
    description = "List current keybindings",
    category = "utility",
    acceptsInput = false,
    args = {
        { name = "filter", required = false, description = "Filter by action name" }
    },
    flags = {
        bound = { short = "b", description = "Show only bound keys" },
    },
    execute = function(ctx)
        local filter = ctx:GetArg(1)
        local filterLower = filter and filter:lower()
        local boundOnly = ctx:HasFlag("bound") or ctx:HasFlag("b")

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

        local numBindings = GetNumBindings()

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

            local action, category, binding1, binding2 = GetBinding(i)

            -- Guard: Invalid binding
            if not action then break end

            -- Guard: Filter
            if filterLower and not action:lower():find(filterLower, 1, true) then break end

            -- Guard: Bound only
            if boundOnly and not binding1 and not binding2 then break end

            -- All guards passed - add result
            results[#results + 1] = C3.Types.Create("Keybinding", {
                action = action,
                key1 = binding1,
                key2 = binding2,
                category = category,
            })
        until true end

        if #results == 0 then
            if filter then
                return ctx:Error("No keybindings matching: " .. filter)
            else
                return ctx:Error("No keybindings found")
            end
        end

        return results
    end
})

-------------------------------------------------------------------------------
-- bind - Set a keybinding
-------------------------------------------------------------------------------

C3.Command:Define({
    name = "bind",
    description = "Set a keybinding",
    category = "utility",
    acceptsInput = false,
    args = {
        { name = "key", required = true, description = "Key to bind (e.g., F1, CTRL-A, ALT-SHIFT-F)" },
        { name = "action", required = true, vararg = true, description = "Action to bind" },
    },
    execute = function(ctx)
        local key = ctx:GetArg(1)
        if not key or key == "" then
            return ctx:Error("Usage: bind <key> <action>")
        end

        local args = ctx:GetArgs()
        if #args < 2 then
            return ctx:Error("Usage: bind <key> <action>")
        end

        -- Join remaining args as action (in case action has spaces)
        local actionParts = {}
        for i = 2, #args do
            actionParts[#actionParts + 1] = args[i]
        end
        local action = table.concat(actionParts, " ")

        if action == "" then
            return ctx:Error("Usage: bind <key> <action>")
        end

        -- Normalize key format
        local normalizedKey = key:upper()

        -- Set the binding
        local ok = SetBinding(normalizedKey, action)
        if ok then
            -- Save bindings
            local bindingSet = GetCurrentBindingSet()
            SaveBindings(bindingSet)
            return ctx:Text(string.format("%s %s to %s", Colorize("Bound", "accent.success"), normalizedKey, Colorize(action, "accent.warning")))
        else
            return ctx:Error("Failed to bind key: " .. normalizedKey)
        end
    end
})

-------------------------------------------------------------------------------
-- unbind - Remove a keybinding
-------------------------------------------------------------------------------

C3.Command:Define({
    name = "unbind",
    description = "Remove a keybinding",
    category = "utility",
    acceptsInput = false,
    args = {
        { name = "key", required = true, description = "Key to unbind" },
    },
    execute = function(ctx)
        local key = ctx:GetArg(1)
        if not key or key == "" then
            return ctx:Error("Usage: unbind <key>")
        end

        -- Normalize key format
        local normalizedKey = key:upper()

        -- Get current binding for this key
        local currentAction = GetBindingAction(normalizedKey)
        if not currentAction or currentAction == "" then
            return ctx:Error("Key not bound: " .. normalizedKey)
        end

        -- Clear the binding
        local ok = SetBinding(normalizedKey, nil)
        if ok then
            -- Save bindings
            local bindingSet = GetCurrentBindingSet()
            SaveBindings(bindingSet)
            return ctx:Text(string.format("%s %s (was: %s)", Colorize("Unbound", "accent.success"), normalizedKey, currentAction))
        else
            return ctx:Error("Failed to unbind key: " .. normalizedKey)
        end
    end
})

-------------------------------------------------------------------------------
-- getbind - Get binding for a key
-------------------------------------------------------------------------------

C3.Command:Define({
    name = "getbind",
    description = "Show what action a key is bound to",
    category = "utility",
    acceptsInput = false,
    args = {
        { name = "key", required = true, description = "Key to check" },
    },
    execute = function(ctx)
        local key = ctx:GetArg(1)
        if not key or key == "" then
            return ctx:Error("Usage: getbind <key>")
        end

        -- Normalize key format
        local normalizedKey = key:upper()

        -- Get current binding for this key
        local action = GetBindingAction(normalizedKey)
        if action and action ~= "" then
            return C3.Types.Create("Keybinding", {
                action = action,
                key1 = normalizedKey,
            })
        else
            return ctx:Text(string.format("%s is %s", normalizedKey, Colorize("not bound", "status.dim")))
        end
    end
})

return true
