--[[
    Commander 3.0 - TUI Input Handler

    Routes keyboard input to TUI apps with action abstraction.
    Converts raw WoW keys to semantic actions.

    Two layers:
    1. Action-based: For menus, dialogs (up/down/select/cancel)
    2. Raw keys: For games that need direct key access

    Usage:
        local action = TuiInput.GetAction(key, modifiers)
        if action == "select" then
            -- Handle selection
        end
]]

local ADDON_NAME, C3 = ...

-------------------------------------------------------------------------------
-- TUI Input Handler
-------------------------------------------------------------------------------

local TuiInput = {}
C3.TUI = C3.TUI or {}
C3.TUI.Input = TuiInput

-------------------------------------------------------------------------------
-- Key Bindings (Key → Action)
-------------------------------------------------------------------------------

-- Standard action bindings
-- Keys should be uppercase, modifiers prefixed (CTRL-X, SHIFT-TAB, ALT-F)
TuiInput.Bindings = {
    -- Navigation
    UP = "up",
    DOWN = "down",
    LEFT = "left",
    RIGHT = "right",
    PAGEUP = "pageUp",
    PAGEDOWN = "pageDown",
    HOME = "home",
    ["END"] = "end_",  -- "end" is Lua keyword

    -- Selection/Confirm
    ENTER = "select",
    SPACE = "toggle",
    NUMPADENTER = "select",

    -- Cancel/Exit
    ESCAPE = "cancel",
    Q = "quit",

    -- Tab Navigation
    TAB = "nextFocus",
    ["SHIFT-TAB"] = "prevFocus",

    -- Search
    ["/"] = "search",
    ["CTRL-F"] = "search",
    F3 = "findNext",
    ["SHIFT-F3"] = "findPrev",

    -- Editing
    BACKSPACE = "backspace",
    DELETE = "delete",
    ["CTRL-A"] = "selectAll",

    -- Clipboard (note: WoW has limitations here)
    ["CTRL-C"] = "copy",
    ["CTRL-V"] = "paste",
    ["CTRL-X"] = "cut",

    -- Undo/Redo
    ["CTRL-Z"] = "undo",
    ["CTRL-Y"] = "redo",
    ["CTRL-SHIFT-Z"] = "redo",

    -- Help
    F1 = "help",
    ["?"] = "help",

    -- vi-style navigation (for yazi/ranger style)
    H = "left",
    J = "down",
    K = "up",
    L = "right",
    G = "goToEnd",
    ["SHIFT-G"] = "goToEnd",

    -- Numeric shortcuts
    ["1"] = "shortcut1",
    ["2"] = "shortcut2",
    ["3"] = "shortcut3",
    ["4"] = "shortcut4",
    ["5"] = "shortcut5",
    ["6"] = "shortcut6",
    ["7"] = "shortcut7",
    ["8"] = "shortcut8",
    ["9"] = "shortcut9",
    ["0"] = "shortcut0",
}

-------------------------------------------------------------------------------
-- Helper Functions
-------------------------------------------------------------------------------

---Build a key string with modifiers
---@param key string The base key
---@param ctrl boolean
---@param shift boolean
---@param alt boolean
---@return string
local function buildKeyString(key, ctrl, shift, alt)
    local parts = {}
    if ctrl then parts[#parts + 1] = "CTRL" end
    if shift then parts[#parts + 1] = "SHIFT" end
    if alt then parts[#parts + 1] = "ALT" end
    parts[#parts + 1] = key:upper()
    return table.concat(parts, "-")
end

-------------------------------------------------------------------------------
-- Public API
-------------------------------------------------------------------------------

---Get action for a key combination
---@param key string The key pressed
---@param modifiers? table { ctrl, shift, alt } booleans
---@return string|nil action
function TuiInput.GetAction(key, modifiers)
    if not key then return nil end

    modifiers = modifiers or {}
    local ctrl = modifiers.ctrl or false
    local shift = modifiers.shift or false
    local alt = modifiers.alt or false

    -- Try full key with modifiers first
    local fullKey = buildKeyString(key, ctrl, shift, alt)
    local action = TuiInput.Bindings[fullKey]
    if action then return action end

    -- Try without modifiers (for simple keys)
    if not ctrl and not shift and not alt then
        action = TuiInput.Bindings[key:upper()]
        if action then return action end
    end

    -- Try just with CTRL if ctrl is pressed
    if ctrl and not shift and not alt then
        action = TuiInput.Bindings["CTRL-" .. key:upper()]
        if action then return action end
    end

    -- Try just with SHIFT if shift is pressed
    if shift and not ctrl and not alt then
        action = TuiInput.Bindings["SHIFT-" .. key:upper()]
        if action then return action end
    end

    return nil
end

---Check if a key triggers a specific action
---@param key string
---@param action string
---@param modifiers? table
---@return boolean
function TuiInput.IsAction(key, action, modifiers)
    return TuiInput.GetAction(key, modifiers) == action
end

---Register a custom binding
---@param key string Key combo (e.g., "CTRL-S", "F2")
---@param action string Action name
function TuiInput.Bind(key, action)
    TuiInput.Bindings[key:upper()] = action
end

---Remove a binding
---@param key string
function TuiInput.Unbind(key)
    TuiInput.Bindings[key:upper()] = nil
end

---Get all bindings for an action
---@param action string
---@return table Array of key strings
function TuiInput.GetBindingsFor(action)
    local result = {}
    for key, boundAction in pairs(TuiInput.Bindings) do
        if boundAction == action then
            result[#result + 1] = key
        end
    end
    return result
end

---Create a binding context (scoped bindings for an app)
---@param bindings? table Initial bindings
---@return table Context
function TuiInput.CreateContext(bindings)
    local context = {
        bindings = bindings or {},
    }

    function context:GetAction(key, modifiers)
        modifiers = modifiers or {}
        local fullKey = buildKeyString(key, modifiers.ctrl, modifiers.shift, modifiers.alt)

        -- Check context-specific binding first
        local action = self.bindings[fullKey] or self.bindings[key:upper()]
        if action then return action end

        -- Fall back to global bindings
        return TuiInput.GetAction(key, modifiers)
    end

    function context:Bind(key, action)
        self.bindings[key:upper()] = action
    end

    function context:Unbind(key)
        self.bindings[key:upper()] = nil
    end

    return context
end

-------------------------------------------------------------------------------
-- WoW Key Utilities
-------------------------------------------------------------------------------

---Convert WoW key name to display string
---@param key string WoW key name
---@return string Display string
function TuiInput.KeyToDisplay(key)
    local displayMap = {
        ESCAPE = "Esc",
        ENTER = "Enter",
        SPACE = "Space",
        BACKSPACE = "Backspace",
        DELETE = "Del",
        TAB = "Tab",
        UP = "↑",
        DOWN = "↓",
        LEFT = "←",
        RIGHT = "→",
        PAGEUP = "PgUp",
        PAGEDOWN = "PgDn",
        HOME = "Home",
        ["END"] = "End",
        NUMPADENTER = "NumEnter",
    }
    return displayMap[key:upper()] or key
end

---Format action binding for display (e.g., "Ctrl+S")
---@param key string Key binding string
---@return string Display string
function TuiInput.FormatBinding(key)
    local result = key
    result = result:gsub("CTRL%-", "Ctrl+")
    result = result:gsub("SHIFT%-", "Shift+")
    result = result:gsub("ALT%-", "Alt+")

    -- Replace key names with display versions
    for full, display in pairs({
        ESCAPE = "Esc",
        ENTER = "Enter",
        SPACE = "Space",
        TAB = "Tab",
    }) do
        result = result:gsub(full, display)
    end

    return result
end

return TuiInput
