
-- ============================================================
-- FILE: Settings_Keybinds.lua
-- MODULE: MidnightUI_Settings (appends to M = MidnightUI_Settings)
--
-- PURPOSE:
--   Implements the Keybind Mode overlay system. When the player
--   clicks "Keybind Mode" in the Settings UI, this module shows
--   translucent overlays on every action button (bars 1-8 and pet
--   bar) that display the current binding and allow clicking a
--   button while pressing a key to assign a new binding. Bindings
--   are saved immediately via SetBinding() + SaveBindings(2) and
--   persisted in MidnightUISettings.Keybinds for reference.
--
-- HOW IT WORKS:
--   EnterKeybindMode() → shows KeybindHUD + keybind overlays +
--                         KeyCaptureFrame (intercepts key presses)
--   KeyCaptureFrame:OnKeyDown → if hovering a button, binds the key
--                               combo (including modifier detection)
--                               to that button's ACTIONBUTTON command
--   ExitKeybindMode() → hides everything, re-opens settings panel
--
-- DEPENDS ON:
--   Settings.lua (MidnightUI_Settings module, MidnightUISettings SV)
--   Blizzard bindings API: SetBinding, GetBindingKey, SaveBindings
--   _G["ActionButton1"] etc.  — action bar button frame refs
--   _G.MidnightUI_RefreshPetBarHotkeys — optional pet bar refresh
--
-- EXPORTS (globals):
--   MidnightUI_EnterKeybindMode()  — public entry point called from
--                                    Settings_UI.lua
--
-- OWNED SAVEDVARIABLES:
--   MidnightUISettings.Keybinds{}  — maps "bar<N>_<slot>" / "pet_<slot>"
--                                    to the bound key string for display
--                                    reference; actual bindings live in
--                                    Blizzard's SaveBindings system
--
-- FRAMES CREATED:
--   MidnightUI_KeybindHUD (BackdropTemplate, UIParent, DIALOG)
--   MidnightUI_KeyCapture (Frame, UIParent, DIALOG/1000) — key sink
--   keybindOverlays[]  — one overlay per action button (lazily created)
--
-- GOTCHAS:
--   • KeyCaptureFrame uses SetPropagateKeyboardInput(false) during
--     keybind mode to prevent the pressed key from triggering the
--     bound action while assigning it.
--   • Modifier keys (LSHIFT, RSHIFT, LCTRL, RCTRL, LALT, RALT) are
--     filtered out in GetKeybindString — they are detected via
--     IsAltKeyDown/IsControlKeyDown/IsShiftKeyDown instead.
--   • Bindings are stored per character (SaveBindings(2)); per-account
--     bindings (SaveBindings(1)) are not used.
-- ============================================================

-- ============================================================
-- SECTION: Module State + Bar/Button Maps
-- Sets up the BAR_BUTTON_MAP that translates bar numbers (1-8)
-- to Blizzard global frame name prefixes (ActionButton, MultiBarXButton),
-- initializes the Keybinds SavedVar table, and declares all upvalue
-- state for the mode (KeybindMode flag, hovered button tracking,
-- overlay pool).
-- ============================================================
local M = MidnightUI_Settings

local BAR_BUTTON_MAP = {
    [1] = "ActionButton",
    [2] = "MultiBarBottomLeftButton",
    [3] = "MultiBarBottomRightButton",
    [4] = "MultiBarRightButton",
    [5] = "MultiBarLeftButton",
    [6] = "MultiBar5Button",
    [7] = "MultiBar6Button",
    [8] = "MultiBar7Button",
}

if not MidnightUISettings.Keybinds then MidnightUISettings.Keybinds = {} end

local KeybindMode = false
local ExitKeybindMode
local hoveredButton = nil
local hoveredBarNum = nil
local hoveredButtonIndex = nil
local keybindOverlays = {}

local KeybindHUD = CreateFrame("Frame", "MidnightUI_KeybindHUD", UIParent, "BackdropTemplate")
KeybindHUD:SetSize(380, 130); KeybindHUD:SetPoint("TOP", 0, -50); KeybindHUD:SetFrameStrata("DIALOG")
KeybindHUD:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 16, edgeSize = 16, insets = { left = 4, right = 4, top = 4, bottom = 4 } })
KeybindHUD:SetBackdropColor(0.1, 0.1, 0.1, 0.95); KeybindHUD:SetBackdropBorderColor(1, 0.6, 0, 1)
KeybindHUD:Hide()

local kbTitle = KeybindHUD:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
kbTitle:SetPoint("TOP", 0, -15); kbTitle:SetText("Keybind Mode"); kbTitle:SetTextColor(1, 0.6, 0)

local kbInstr = KeybindHUD:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
kbInstr:SetPoint("TOP", kbTitle, "BOTTOM", 0, -8)
kbInstr:SetText("Hover an action button and press a key, mouse button, or scroll the wheel to bind it.\nHold Shift, Ctrl, or Alt for combos (e.g. Shift+Right-Click, Shift+Wheel Up).")
kbInstr:SetTextColor(0.9, 0.9, 0.9)
kbInstr:SetJustifyH("CENTER")

local kbStatus = KeybindHUD:CreateFontString(nil, "OVERLAY", "GameFontNormal")
kbStatus:SetPoint("TOP", kbInstr, "BOTTOM", 0, -12)
kbStatus:SetText("Hovering: None"); kbStatus:SetTextColor(0.6, 0.6, 0.6)

local kbDone = CreateFrame("Button", nil, KeybindHUD, "GameMenuButtonTemplate")
kbDone:SetPoint("BOTTOM", 0, 15); kbDone:SetSize(140, 26); kbDone:SetText("Done")

-- ============================================================
-- SECTION: Keybind Mode Core — Overlays, Key Capture + Mode Control
-- The main implementation of the keybind workflow. Overlay frames
-- are created lazily per action button and pooled in keybindOverlays[].
-- The KeyCaptureFrame intercepts all keyboard input during mode and
-- calls SetBinding() on hover + keypress combinations.
--
-- READS:
--   hoveredBarNum, hoveredButtonIndex — set by overlay OnEnter
--   IsAltKeyDown, IsControlKeyDown, IsShiftKeyDown — modifier state
--   GetBindingKey(command), GetBindingAction(keyStr) — current bindings
--   MidnightUISettings.Keybinds — for dedup before writing new binding
--
-- WRITES:
--   MidnightUISettings.Keybinds[key] — updated on successful bind
--   Blizzard binding table via SetBinding + SaveBindings(2)
--   overlay.label text/color — reflects current binding state
--
-- FUNCTIONS:
--   GetKeybindString(key)              — builds "MOD-key" combo string;
--                                         returns nil for bare modifiers
--   GetBindingCommand(barNum, idx)     — maps barNum+idx to ACTIONBUTTON
--                                         / MULTIACTIONBARxBUTTON command
--   CreateKeybindOverlay(btn, barNum, idx)
--                                      — creates TOOLTIP-strata overlay
--                                         with Enter/Leave handlers that
--                                         update hovered* state and kbStatus
--   GetBindingDisplay(command, fallback) — returns current key for command
--   CommandToOverlayKey(command)       — maps ACTIONBUTTON string back to
--                                         "barN_idx" / "pet_idx" overlay key
--   FlashOverlayLabel(overlay, r, g, b) — plays the alpha fade-in animation
--                                          to visually confirm a bind change
--   RefreshKeybindOverlayText()        — updates all overlay labels to
--                                         reflect current bindings
--   ShowKeybindOverlays()              — creates/shows overlays for all bars
--   HideKeybindOverlays()              — hides all active overlays
--   EnterKeybindMode()                 — activates mode: shows HUD + overlays
--                                         + KeyCaptureFrame
--   ExitKeybindMode()                  — deactivates mode; re-opens settings
--   MidnightUI_EnterKeybindMode()      — public alias exported to _G
-- ============================================================
local function GetModifierPrefix()
    local modifiers = ""
    if IsAltKeyDown() then modifiers = modifiers .. "ALT-" end
    if IsControlKeyDown() then modifiers = modifiers .. "CTRL-" end
    if IsShiftKeyDown() then modifiers = modifiers .. "SHIFT-" end
    return modifiers
end

local function GetKeybindString(key)
    if key == "LSHIFT" or key == "RSHIFT" or key == "LCTRL" or key == "RCTRL" or key == "LALT" or key == "RALT" then
        return nil
    end
    return GetModifierPrefix() .. key
end

local MOUSE_BUTTON_TOKEN = {
    RightButton  = "BUTTON2",
    MiddleButton = "BUTTON3",
    Button4      = "BUTTON4",
    Button5      = "BUTTON5",
}

local ApplyBindingToHovered

local function GetBindingCommand(barNum, buttonIndex)
    if barNum == 1 then
        return "ACTIONBUTTON" .. buttonIndex
    elseif barNum == 2 then
        return "MULTIACTIONBAR1BUTTON" .. buttonIndex
    elseif barNum == 3 then
        return "MULTIACTIONBAR2BUTTON" .. buttonIndex
    elseif barNum == 4 then
        return "MULTIACTIONBAR3BUTTON" .. buttonIndex
    elseif barNum == 5 then
        return "MULTIACTIONBAR4BUTTON" .. buttonIndex
    elseif barNum == 6 then
        return "MULTIACTIONBAR5BUTTON" .. buttonIndex
    elseif barNum == 7 then
        return "MULTIACTIONBAR6BUTTON" .. buttonIndex
    elseif barNum == 8 then
        return "MULTIACTIONBAR7BUTTON" .. buttonIndex
    elseif barNum == "PET" then
        return "BONUSACTIONBUTTON" .. buttonIndex
    end
    return nil
end

local function CreateKeybindOverlay(button, barNum, buttonIndex)
    if not button then return nil end
    
    local overlay = CreateFrame("Frame", nil, button, "BackdropTemplate")
    overlay:SetAllPoints()
    overlay:SetFrameStrata("TOOLTIP")
    overlay:EnableMouse(true)
    overlay:EnableMouseWheel(true)
    overlay:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", edgeSize = 8 })
    overlay:SetBackdropColor(0, 0, 0, 0.7)
    overlay:SetBackdropBorderColor(0.5, 0.5, 0.5, 0.8)
    
    local label = overlay:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    label:SetPoint("CENTER", 0, 0)
    label:SetText(barNum .. "-" .. buttonIndex)
    label:SetTextColor(0.7, 0.7, 0.7)
    overlay.label = label
    overlay.label:SetAlpha(1)
    overlay.label._muiFlash = overlay.label:CreateAnimationGroup()
    local fadeIn = overlay.label._muiFlash:CreateAnimation("Alpha")
    fadeIn:SetFromAlpha(0.2)
    fadeIn:SetToAlpha(1)
    fadeIn:SetDuration(0.25)
    fadeIn:SetSmoothing("IN")
    
    overlay.barNum = barNum
    overlay.buttonIndex = buttonIndex
    
    overlay:SetScript("OnEnter", function(self)
        if KeybindMode then
            hoveredButton = button
            hoveredBarNum = self.barNum
            hoveredButtonIndex = self.buttonIndex
            self:SetBackdropBorderColor(1, 0.6, 0, 1)
            self:SetBackdropColor(0.2, 0.1, 0, 0.8)
            if self.barNum == "PET" then
                kbStatus:SetText("Hovering: Pet Button " .. self.buttonIndex)
            else
                kbStatus:SetText("Hovering: Bar " .. self.barNum .. " Button " .. self.buttonIndex)
            end
            kbStatus:SetTextColor(1, 0.6, 0)
        end
    end)
    
    overlay:SetScript("OnLeave", function(self)
        if KeybindMode then
            hoveredButton = nil
            hoveredBarNum = nil
            hoveredButtonIndex = nil
            self:SetBackdropBorderColor(0.5, 0.5, 0.5, 0.8)
            self:SetBackdropColor(0, 0, 0, 0.7)
            kbStatus:SetText("Hovering: None")
            kbStatus:SetTextColor(0.6, 0.6, 0.6)
        end
    end)

    overlay:SetScript("OnMouseDown", function(self, mouseButton)
        if not KeybindMode then return end
        local token = MOUSE_BUTTON_TOKEN[mouseButton]
        if not token then return end
        ApplyBindingToHovered(GetModifierPrefix() .. token, self.barNum, self.buttonIndex)
    end)

    overlay:SetScript("OnMouseWheel", function(self, delta)
        if not KeybindMode then return end
        local token = (delta > 0) and "MOUSEWHEELUP" or "MOUSEWHEELDOWN"
        ApplyBindingToHovered(GetModifierPrefix() .. token, self.barNum, self.buttonIndex)
    end)

    overlay:Hide()
    return overlay
end

local function GetBindingDisplay(command, fallback)
    if not command or not GetBindingKey then return fallback end
    local key = GetBindingKey(command)
    if key and key ~= "" then return key end
    return fallback
end

local function CommandToOverlayKey(command)
    if not command or command == "" then return nil end
    local idx = command:match("^ACTIONBUTTON(%d+)$")
    if idx then return "bar1_" .. idx end
    idx = command:match("^MULTIACTIONBAR1BUTTON(%d+)$")
    if idx then return "bar2_" .. idx end
    idx = command:match("^MULTIACTIONBAR2BUTTON(%d+)$")
    if idx then return "bar3_" .. idx end
    idx = command:match("^MULTIACTIONBAR3BUTTON(%d+)$")
    if idx then return "bar4_" .. idx end
    idx = command:match("^MULTIACTIONBAR4BUTTON(%d+)$")
    if idx then return "bar5_" .. idx end
    idx = command:match("^MULTIACTIONBAR5BUTTON(%d+)$")
    if idx then return "bar6_" .. idx end
    idx = command:match("^MULTIACTIONBAR6BUTTON(%d+)$")
    if idx then return "bar7_" .. idx end
    idx = command:match("^MULTIACTIONBAR7BUTTON(%d+)$")
    if idx then return "bar8_" .. idx end
    idx = command:match("^BONUSACTIONBUTTON(%d+)$")
    if idx then return "pet_" .. idx end
    return nil
end

local function FlashOverlayLabel(overlay, r, g, b)
    if not overlay or not overlay.label then return end
    overlay.label:SetTextColor(r, g, b)
    if overlay.label._muiFlash then
        overlay.label._muiFlash:Stop()
        overlay.label._muiFlash:Play()
    end
end

local function RefreshKeybindOverlayText()
    for barNum = 1, 8 do
        for i = 1, 12 do
            local key = "bar" .. barNum .. "_" .. i
            local overlay = keybindOverlays[key]
            if overlay then
                local cmd = GetBindingCommand(barNum, i)
                local display = GetBindingDisplay(cmd, barNum .. "-" .. i)
                overlay.label:SetText(display)
                overlay.label:SetTextColor(display == (barNum .. "-" .. i) and 0.7 or 0, display == (barNum .. "-" .. i) and 0.7 or 0.8, display == (barNum .. "-" .. i) and 0.7 or 1)
            end
        end
    end
    for i = 1, 10 do
        local key = "pet_" .. i
        local overlay = keybindOverlays[key]
        if overlay then
            local cmd = "BONUSACTIONBUTTON" .. i
            local display = GetBindingDisplay(cmd, "P-" .. i)
            overlay.label:SetText(display)
            overlay.label:SetTextColor(display == ("P-" .. i) and 0.7 or 0, display == ("P-" .. i) and 0.7 or 0.8, display == ("P-" .. i) and 0.7 or 1)
        end
    end
end

local function ShowKeybindOverlays()
    if not MidnightUISettings.Keybinds then MidnightUISettings.Keybinds = {} end
    
    for barNum = 1, 8 do
        local prefix = BAR_BUTTON_MAP[barNum]
        if prefix then
            for i = 1, 12 do
                local button = _G[prefix .. i]
                if button then
                    local key = "bar" .. barNum .. "_" .. i
                    if not keybindOverlays[key] then
                        keybindOverlays[key] = CreateKeybindOverlay(button, barNum, i)
                    end
                    if keybindOverlays[key] then
                        local cmd = GetBindingCommand(barNum, i)
                        local display = GetBindingDisplay(cmd, barNum .. "-" .. i)
                        keybindOverlays[key].label:SetText(display)
                        if display == (barNum .. "-" .. i) then
                            keybindOverlays[key].label:SetTextColor(0.7, 0.7, 0.7)
                        else
                            keybindOverlays[key].label:SetTextColor(0, 0.8, 1)
                        end
                        keybindOverlays[key]:Show()
                    end
                end
            end
        end
    end

    for i = 1, 10 do
        local button = _G["PetActionButton"..i]
        if button then
            local key = "pet_" .. i
            if not keybindOverlays[key] then
                keybindOverlays[key] = CreateKeybindOverlay(button, "PET", i)
            end
            if keybindOverlays[key] then
                local cmd = "BONUSACTIONBUTTON" .. i
                local display = GetBindingDisplay(cmd, "P-" .. i)
                keybindOverlays[key].label:SetText(display)
                if display == ("P-" .. i) then
                    keybindOverlays[key].label:SetTextColor(0.7, 0.7, 0.7)
                else
                    keybindOverlays[key].label:SetTextColor(0, 0.8, 1)
                end
                keybindOverlays[key]:Show()
            end
        end
    end
end

local function HideKeybindOverlays()
    for key, overlay in pairs(keybindOverlays) do
        if overlay then overlay:Hide() end
    end
end

local KeyCaptureFrame = CreateFrame("Frame", "MidnightUI_KeyCapture", UIParent)
KeyCaptureFrame:SetAllPoints(UIParent)
KeyCaptureFrame:SetFrameStrata("DIALOG")
KeyCaptureFrame:SetFrameLevel(1000)
KeyCaptureFrame:EnableKeyboard(true)
KeyCaptureFrame:SetPropagateKeyboardInput(true)
KeyCaptureFrame:Hide()

ApplyBindingToHovered = function(keybindStr, barNum, buttonIndex)
    if not keybindStr or not barNum or not buttonIndex then return end

    local command = GetBindingCommand(barNum, buttonIndex)
    if not command then return end

    local oldBinding1, oldBinding2 = GetBindingKey(command)
    if oldBinding1 then SetBinding(oldBinding1) end
    if oldBinding2 then SetBinding(oldBinding2) end

    local prevCommand = GetBindingAction and GetBindingAction(keybindStr) or nil
    SetBinding(keybindStr)

    if MidnightUISettings.Keybinds then
        for savedKey, savedBind in pairs(MidnightUISettings.Keybinds) do
            if savedBind == keybindStr then
                MidnightUISettings.Keybinds[savedKey] = nil
            end
        end
    end

    local success = SetBinding(keybindStr, command)

    if success then
        if not MidnightUISettings.Keybinds then MidnightUISettings.Keybinds = {} end

        local storeKey
        if barNum == "PET" then
            storeKey = "pet_" .. buttonIndex
        else
            storeKey = "bar" .. barNum .. "_" .. buttonIndex
        end
        MidnightUISettings.Keybinds[storeKey] = keybindStr

        RefreshKeybindOverlayText()
        if prevCommand then
            local prevKey = CommandToOverlayKey(prevCommand)
            local prevOverlay = prevKey and keybindOverlays[prevKey] or nil
            if prevOverlay then
                FlashOverlayLabel(prevOverlay, 1, 0.2, 0.2)
            end
        end
        local newOverlay = keybindOverlays[storeKey]
        if newOverlay then
            FlashOverlayLabel(newOverlay, 0.2, 1, 0.2)
        end

        if barNum == "PET" then
            kbStatus:SetText("Set: " .. keybindStr .. " -> Pet Btn " .. buttonIndex)
        else
            kbStatus:SetText("Set: " .. keybindStr .. " -> Bar " .. barNum .. " Btn " .. buttonIndex)
        end
        kbStatus:SetTextColor(0, 1, 0)

        SaveBindings(2)
        if _G.MidnightUI_RefreshPetBarHotkeys then
            _G.MidnightUI_RefreshPetBarHotkeys()
        end

        if barNum == "PET" then
            print("|cff00ccffMidnight UI:|r Bound |cffFFFF00" .. keybindStr .. "|r to Pet Button " .. buttonIndex)
        else
            print("|cff00ccffMidnight UI:|r Bound |cffFFFF00" .. keybindStr .. "|r to Action Bar " .. barNum .. " Button " .. buttonIndex)
        end
    else
        kbStatus:SetText("Failed to bind: " .. keybindStr)
        kbStatus:SetTextColor(1, 0, 0)
    end
end

KeyCaptureFrame:SetScript("OnKeyDown", function(self, key)
    if not KeybindMode then return end

    if key == "ESCAPE" then
        ExitKeybindMode()
        return
    end

    if not hoveredButton or not hoveredBarNum or not hoveredButtonIndex then return end

    local keybindStr = GetKeybindString(key)
    if not keybindStr then return end

    ApplyBindingToHovered(keybindStr, hoveredBarNum, hoveredButtonIndex)

    self:SetPropagateKeyboardInput(false)
end)

local function EnterKeybindMode()
    KeybindMode = true
    ShowKeybindOverlays()
    KeybindHUD:Show()
    KeyCaptureFrame:Show()
    KeyCaptureFrame:SetPropagateKeyboardInput(false)
    
    if SettingsPanel then SettingsPanel:Hide() 
    elseif InterfaceOptionsFrame then InterfaceOptionsFrame:Hide() end
end

ExitKeybindMode = function()
    KeybindMode = false
    HideKeybindOverlays()
    KeybindHUD:Hide()
    KeyCaptureFrame:SetPropagateKeyboardInput(true)
    KeyCaptureFrame:Hide()
    hoveredButton = nil
    hoveredBarNum = nil
    hoveredButtonIndex = nil
    
    local cat = M and M.SettingsCategory or nil
    if cat and Settings and Settings.OpenToCategory then 
        Settings.OpenToCategory(cat.ID)
    elseif SettingsPanel then SettingsPanel:Show() 
    elseif InterfaceOptionsFrame then InterfaceOptionsFrame:Show() end
end

kbDone:SetScript("OnClick", ExitKeybindMode)

function MidnightUI_EnterKeybindMode()
    EnterKeybindMode()
end

local applyStoredKeybindsPending = false
local applyStoredKeybindsFrame

local function ApplyStoredKeybinds()
    if InCombatLockdown() then
        if not applyStoredKeybindsFrame then
            applyStoredKeybindsFrame = CreateFrame("Frame")
            applyStoredKeybindsFrame:SetScript("OnEvent", function(self, event)
                if event == "PLAYER_REGEN_ENABLED" and applyStoredKeybindsPending then
                    applyStoredKeybindsPending = false
                    self:UnregisterEvent("PLAYER_REGEN_ENABLED")
                    ApplyStoredKeybinds()
                end
            end)
        end
        applyStoredKeybindsPending = true
        applyStoredKeybindsFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
        return
    end

    if type(MidnightUISettings) ~= "table" or type(MidnightUISettings.Keybinds) ~= "table" then
        return
    end

    local applied = 0
    for storedKey, keybindStr in pairs(MidnightUISettings.Keybinds) do
        if type(storedKey) == "string" and type(keybindStr) == "string" and keybindStr ~= "" then
            local barNum, buttonIndex
            local barStr, idxStr = storedKey:match("^bar(%d+)_(%d+)$")
            if barStr and idxStr then
                barNum = tonumber(barStr)
                buttonIndex = tonumber(idxStr)
            else
                local petIdx = storedKey:match("^pet_(%d+)$")
                if petIdx then
                    barNum = "PET"
                    buttonIndex = tonumber(petIdx)
                end
            end

            local command = barNum and buttonIndex and GetBindingCommand(barNum, buttonIndex) or nil
            if command then
                if GetBindingAction then
                    local existing = GetBindingAction(keybindStr)
                    if existing and existing ~= "" and existing ~= command then
                        SetBinding(keybindStr)
                    end
                end
                if SetBinding(keybindStr, command) then
                    applied = applied + 1
                end
            end
        end
    end

    if applied > 0 then
        SaveBindings(2)
        if _G.MidnightUI_RefreshPetBarHotkeys then
            _G.MidnightUI_RefreshPetBarHotkeys()
        end
    end
end

local function SyncKeybindsFromBlizzard()
    if type(MidnightUISettings) ~= "table" then return end
    MidnightUISettings.Keybinds = MidnightUISettings.Keybinds or {}
    local k = MidnightUISettings.Keybinds
    for slot in pairs(k) do k[slot] = nil end

    local function capture(barNum, idx, storedKey)
        local cmd = GetBindingCommand(barNum, idx)
        if not cmd then return end
        local key1, key2 = GetBindingKey(cmd)
        local picked = (key1 and key1 ~= "" and key1) or (key2 and key2 ~= "" and key2) or nil
        if picked then
            k[storedKey] = picked
        end
    end

    for barNum = 1, 8 do
        for idx = 1, 12 do
            capture(barNum, idx, "bar" .. barNum .. "_" .. idx)
        end
    end
    for idx = 1, 12 do
        capture("PET", idx, "pet_" .. idx)
    end
end

M.SyncKeybindsFromBlizzard = SyncKeybindsFromBlizzard

M.ApplyStoredKeybinds = ApplyStoredKeybinds

