local addonName, LRH = ...

LRH = LRH or {}
LRH.L = LRH.L or {}
LRH.Utils = LRH.Utils or {}
LRH.UI = LRH.UI or {}

local L = LRH.L
local U = LRH.Utils

-- LibSharedMedia (bundled) - unified media registry
local LSM
if LibStub then
    local ok, lib = pcall(LibStub, "LibSharedMedia-3.0")
    if ok then LSM = lib end
end
LRH.LSM = LSM

local function LRH_RegisterBundledFonts()
    if not LRH.LSM then return end
    local base = "Interface\\AddOns\\Left_Right_Helper\\Fonts\\"

    LRH.LSM:Register("font", "Standard", STANDARD_TEXT_FONT)

    local bundled = {
        { "American Captain", "AmericanCaptain.otf" },
        { "Belion Radego", "BelionRadego.otf" },
        { "Fastelar Demo Regular", "FastelarDemoRegular.ttf" },
        { "Runtime Regular", "RuntimeRegular.otf" },
    }

    for _, f in ipairs(bundled) do
        local name, file = f[1], f[2]
        LRH.LSM:Register("font", name, base .. file)
    end
end

-------------------------------------------------
-- Font registration
-------------------------------------------------
LRH._pendingFonts = LRH._pendingFonts or {}

function LRH:RegisterFont(key, name, path)
    if type(key) ~= "string" or key == "" then return end
    if type(name) ~= "string" or name == "" then name = key end
    if type(path) ~= "string" or path == "" then return end

    self._pendingFonts[key] = { name = name, path = path }
    if self.FONT_PRESETS then
        self.FONT_PRESETS[key] = { name = name, path = path }
    end
end

-------------------------------------------------
-- SavedVariables
-------------------------------------------------
LeftRightDB = LeftRightDB or {}
LeftRightDB.enabled = (LeftRightDB.enabled ~= false)
LeftRightDB.dragEnabled = (LeftRightDB.dragEnabled == true)

LeftRightConfig = LeftRightConfig or {}

LeftRightConfig.fontName    = LeftRightConfig.fontName or "Standard"
LeftRightConfig.sizeMul     = LeftRightConfig.sizeMul or 1.25
LeftRightConfig.alpha       = LeftRightConfig.alpha or 1
LeftRightConfig.arrowGapPx  = LeftRightConfig.arrowGapPx or 150
LeftRightConfig.arrowDesign = LeftRightConfig.arrowDesign or "CLASSIC"
LeftRightConfig.borderStyle = LeftRightConfig.borderStyle or "GOLD"
LeftRightConfig.fontKey     = LeftRightConfig.fontKey or "STANDARD"
LeftRightConfig.fontOutline = LeftRightConfig.fontOutline or "OUTLINE"

LeftRightConfig.leftColor  = U.EnsureColorTable(LeftRightConfig.leftColor,  0.20, 0.60, 1.00)
LeftRightConfig.rightColor = U.EnsureColorTable(LeftRightConfig.rightColor, 1.00, 0.20, 0.20)

-------------------------------------------------
-- Constants
-------------------------------------------------
LRH.ADDON_PATH   = "Interface\\AddOns\\Left_Right_Helper\\"
LRH.TEX_MINIMAP  = LRH.ADDON_PATH .. "Images\\Minimap\\Left Right Helper.blp"

LRH.BASE_W, LRH.BASE_H = 120, 120

LRH.SNAP_PX       = 16
LRH.TOP_MARGIN_PX = 20

LRH.DEFAULT_SIZE_MUL = 1.25
LRH.MIN_MUL, LRH.MAX_MUL = 0.2, 3.0
LRH.MUL_STEP = 0.05

LRH.MIN_GAP, LRH.MAX_GAP = 0, 700
LRH.GAP_STEP = 1

LRH.BOX_CENTER_Y_FACTOR = 0.25

LRH.BASE_FONT = 26
LRH.MIN_FONT  = 12
LRH.MAX_FONT  = 64

LRH.LABEL_GAP_PX = 6
LRH.LABEL_AREA_BASE = 28
LRH.LABEL_VISUAL_YOFFSET = 20

LRH.BORDER_COLORS = {
    GOLD   = { r = 1.00, g = 0.82, b = 0.20 },
    SILVER = { r = 0.80, g = 0.80, b = 0.85 },
    BROWN  = { r = 0.55, g = 0.40, b = 0.25 },
}

-- Shared backdrop for MainFrame + QuickOptions
LRH.SHARED_BACKDROP = {
    bgFile   = "Interface\\DialogFrame\\UI-DialogBox-Background",
    edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
    edgeSize = 16,
    insets   = { left = 3, right = 3, top = 3, bottom = 3 },
}
LRH.SHARED_BACKDROP_COLOR = { 0.06, 0.07, 0.10, 0.78 }
LRH.SHARED_BORDER_COLOR   = { 0.00, 0.44, 0.87, 1.00 }

LRH.FONT_PRESETS = {}

LRH.OUTLINE_PRESETS = {
    NONE         = { name = L.OUTLINE_NONE or "None",          flag = "" },
    OUTLINE      = { name = L.OUTLINE_NORMAL or "Outline",     flag = "OUTLINE" },
    THICKOUTLINE = { name = L.OUTLINE_THICK or "Thick outline", flag = "THICKOUTLINE" },
}

LRH.DESIGNS = {
    CLASSIC = {
        name = "Classic",
        leftFill    = LRH.ADDON_PATH .. "Images\\Styles\\Classic\\ArrowLeftClassicFill.blp",
        leftBorder  = LRH.ADDON_PATH .. "Images\\Styles\\Classic\\ArrowLeftClassicBorder.blp",
        rightFill   = LRH.ADDON_PATH .. "Images\\Styles\\Classic\\ArrowRightClassicFill.blp",
        rightBorder = LRH.ADDON_PATH .. "Images\\Styles\\Classic\\ArrowRightClassicBorder.blp",
    },
    MODERN = {
        name = "Modern",
        leftFill    = LRH.ADDON_PATH .. "Images\\Styles\\Modern\\ArrowLeftModernFill.blp",
        leftBorder  = LRH.ADDON_PATH .. "Images\\Styles\\Modern\\ArrowLeftModernBorder.blp",
        rightFill   = LRH.ADDON_PATH .. "Images\\Styles\\Modern\\ArrowRightModernFill.blp",
        rightBorder = LRH.ADDON_PATH .. "Images\\Styles\\Modern\\ArrowRightModernBorder.blp",
    },
    SIMPLE = {
        name = "Simple",
        leftFill    = LRH.ADDON_PATH .. "Images\\Styles\\Simple\\ArrowLeftSimple.blp",
        rightFill   = LRH.ADDON_PATH .. "Images\\Styles\\Simple\\ArrowRightSimple.blp",
        leftBorder  = nil,
        rightBorder = nil,
        noBorder    = true,
    },
}

LRH.AVAILABLE_DESIGNS = LRH.AVAILABLE_DESIGNS or {}

-------------------------------------------------
-- Helpers
-------------------------------------------------
local function EnsureProbeTexture()
    if LRH.__probeTex and LRH.__probeTex.SetTexture then
        return LRH.__probeTex
    end
    local f = CreateFrame("Frame")
    f:Hide()
    LRH.__probeTex = f:CreateTexture()
    return LRH.__probeTex
end

local function ApplySharedBackdrop(frame)
    if not frame then return end

    frame:SetBackdrop(LRH.SHARED_BACKDROP)

    local c = LRH.SHARED_BACKDROP_COLOR
    frame:SetBackdropColor(c[1], c[2], c[3], c[4])

    local b = LRH.SHARED_BORDER_COLOR
    frame:SetBackdropBorderColor(b[1], b[2], b[3], b[4])
end

-------------------------------------------------
-- Design availability
-------------------------------------------------
function LRH:IsDesignAvailable(key)
    local d = self.DESIGNS and self.DESIGNS[key]
    if not d then return false end

    local probe = EnsureProbeTexture()
    if not (probe and probe.SetTexture) then return true end

    local ok1 = (not d.leftFill)    or (probe:SetTexture(d.leftFill)    ~= false)
    local ok2 = (not d.leftBorder)  or (probe:SetTexture(d.leftBorder)  ~= false)
    local ok3 = (not d.rightFill)   or (probe:SetTexture(d.rightFill)   ~= false)
    local ok4 = (not d.rightBorder) or (probe:SetTexture(d.rightBorder) ~= false)

    return ok1 and ok2 and ok3 and ok4
end

function LRH:RefreshAvailableDesigns()
    local list = {}
    for key, d in pairs(self.DESIGNS or {}) do
        if d and d.name and self:IsDesignAvailable(key) then
            list[#list + 1] = key
        end
    end

    table.sort(list, function(a, b)
        local da = self.DESIGNS[a]
        local db = self.DESIGNS[b]
        return (da and da.name or a) < (db and db.name or b)
    end)

    self.AVAILABLE_DESIGNS = list
end

function LRH:GetAvailableDesignKeys()
    if not self.AVAILABLE_DESIGNS or #self.AVAILABLE_DESIGNS == 0 then
        self:RefreshAvailableDesigns()
    end
    return self.AVAILABLE_DESIGNS or {}
end

function LRH:GetFirstAvailableDesignKey()
    local keys = self:GetAvailableDesignKeys()
    if keys and keys[1] then return keys[1] end
    return "CLASSIC"
end

function LRH:GetDesignKey()
    local k = LeftRightConfig.arrowDesign
    if k and self.DESIGNS and self.DESIGNS[k] and self:IsDesignAvailable(k) then
        return k
    end
    return self:GetFirstAvailableDesignKey()
end

-------------------------------------------------
-- Size %
-------------------------------------------------
function LRH:GetSizePercent()
    local defaultMul = self.DEFAULT_SIZE_MUL or 1.25
    local currentMul = U.Clamp(LeftRightConfig.sizeMul or defaultMul, self.MIN_MUL, self.MAX_MUL)
    return math.floor(((currentMul / defaultMul) * 100) + 0.5)
end

function LRH:UpdateSizeLabel()
    if not self.SizeLabel then return end
    self.SizeLabel:SetText(string.format("%d%%", self:GetSizePercent()))
end

-------------------------------------------------
-- Apply functions
-------------------------------------------------
function LRH:ApplyDesign()
    local key = self:GetDesignKey()
    local d = self.DESIGNS[key] or self.DESIGNS.CLASSIC

    if self.LeftFill and d.leftFill then
        self.LeftFill:SetTexture(d.leftFill)
        self.LeftFill:Show()
    end
    if self.RightFill and d.rightFill then
        self.RightFill:SetTexture(d.rightFill)
        self.RightFill:Show()
    end

    if d.noBorder then
        if self.LeftBorder then
            self.LeftBorder:SetTexture(nil)
            self.LeftBorder:Hide()
        end
        if self.RightBorder then
            self.RightBorder:SetTexture(nil)
            self.RightBorder:Hide()
        end
    else
        if self.LeftBorder and d.leftBorder then
            self.LeftBorder:SetTexture(d.leftBorder)
            self.LeftBorder:Show()
        end
        if self.RightBorder and d.rightBorder then
            self.RightBorder:SetTexture(d.rightBorder)
            self.RightBorder:Show()
        end
    end

    LeftRightConfig.arrowDesign = key
end

function LRH:ApplyFillTint()
    LeftRightConfig.leftColor  = U.EnsureColorTable(LeftRightConfig.leftColor,  0.20, 0.60, 1.00)
    LeftRightConfig.rightColor = U.EnsureColorTable(LeftRightConfig.rightColor, 1.00, 0.20, 0.20)

    if self.LeftFill then
        local c = LeftRightConfig.leftColor
        self.LeftFill:SetVertexColor(c.r, c.g, c.b, 1)
    end

    if self.RightFill then
        local c = LeftRightConfig.rightColor
        self.RightFill:SetVertexColor(c.r, c.g, c.b, 1)
    end
end

function LRH:ApplyBorderTint()
    local designKey = self:GetDesignKey()
    local d = self.DESIGNS[designKey] or self.DESIGNS.CLASSIC

    if d.noBorder then
        if self.LeftBorder then
            self.LeftBorder:SetAlpha(0)
            self.LeftBorder:Hide()
        end
        if self.RightBorder then
            self.RightBorder:SetAlpha(0)
            self.RightBorder:Hide()
        end
        return
    end

    local style = LeftRightConfig.borderStyle
    if not self.BORDER_COLORS[style] then
        style = "SILVER"
    end
    LeftRightConfig.borderStyle = style

    local c = self.BORDER_COLORS[style]

    if self.LeftBorder then
        self.LeftBorder:SetVertexColor(c.r, c.g, c.b, 1)
        self.LeftBorder:Show()
    end
    if self.RightBorder then
        self.RightBorder:SetVertexColor(c.r, c.g, c.b, 1)
        self.RightBorder:Show()
    end
end

function LRH:GetScaledSize()
    local mul = U.Clamp(LeftRightConfig.sizeMul or self.DEFAULT_SIZE_MUL, self.MIN_MUL, self.MAX_MUL)
    LeftRightConfig.sizeMul = mul
    return self.BASE_W * mul, self.BASE_H * mul
end

function LRH:ApplySizeAndLayout()
    if not self.MainFrame then return end

    local w, h = self:GetScaledSize()
    local gap = U.Clamp(LeftRightConfig.arrowGapPx or 150, self.MIN_GAP, self.MAX_GAP)
    LeftRightConfig.arrowGapPx = gap

    local mul = U.Clamp(LeftRightConfig.sizeMul or self.DEFAULT_SIZE_MUL, self.MIN_MUL, self.MAX_MUL)
    local fontSize = math.floor(self.BASE_FONT * mul + 0.5)
    fontSize = U.Clamp(fontSize, self.MIN_FONT, self.MAX_FONT)

    local labelGap = self.LABEL_GAP_PX or 6
    local labelArea = math.max(self.LABEL_AREA_BASE or 28, fontSize + 8)
    local visualOffset = self.LABEL_VISUAL_YOFFSET or 0

    self.MainFrame:SetSize((2 * w) + gap, h + labelGap + labelArea)

    if self.LeftFill then
        self.LeftFill:ClearAllPoints()
        self.LeftFill:SetPoint("TOPLEFT", self.MainFrame, "TOPLEFT", 0, 0)
        self.LeftFill:SetSize(w, h)
    end
    if self.LeftBorder and self.LeftFill then
        self.LeftBorder:ClearAllPoints()
        self.LeftBorder:SetAllPoints(self.LeftFill)
    end

    if self.RightFill then
        self.RightFill:ClearAllPoints()
        self.RightFill:SetPoint("TOPRIGHT", self.MainFrame, "TOPRIGHT", 0, 0)
        self.RightFill:SetSize(w, h)
    end
    if self.RightBorder and self.RightFill then
        self.RightBorder:ClearAllPoints()
        self.RightBorder:SetAllPoints(self.RightFill)
    end

    if self.LeftLabel and self.LeftFill then
        self.LeftLabel:ClearAllPoints()
        self.LeftLabel:SetPoint("TOP", self.LeftFill, "BOTTOM", 0, -labelGap + visualOffset)
        self.LeftLabel:SetSize(w, labelArea)
    end

    if self.RightLabel and self.RightFill then
        self.RightLabel:ClearAllPoints()
        self.RightLabel:SetPoint("TOP", self.RightFill, "BOTTOM", 0, -labelGap + visualOffset)
        self.RightLabel:SetSize(w, labelArea)
    end

    if self.SizeLabel then
        self.SizeLabel:ClearAllPoints()
        self.SizeLabel:SetPoint("BOTTOM", self.MainFrame, "BOTTOM", 0, 12)
        self.SizeLabel:SetWidth((2 * w) + gap)
        self.SizeLabel:SetHeight(32)
    end

    self:UpdateSizeLabel()
end

function LRH:ApplyFont()
    if not self.LeftLabel or not self.RightLabel then return end

    local fontName = LeftRightConfig.fontName or LeftRightConfig.fontKey or "Standard"
    local fontPath = (self.LSM and self.LSM:Fetch("font", fontName, true)) or STANDARD_TEXT_FONT
    local mul = U.Clamp(LeftRightConfig.sizeMul or self.DEFAULT_SIZE_MUL, self.MIN_MUL, self.MAX_MUL)

    local size = math.floor(self.BASE_FONT * mul + 0.5)
    size = U.Clamp(size, self.MIN_FONT, self.MAX_FONT)

    local o = self.OUTLINE_PRESETS[LeftRightConfig.fontOutline] or self.OUTLINE_PRESETS.OUTLINE
    local flag = o.flag or ""

    self.LeftLabel:SetFont(fontPath, size, flag)
    self.RightLabel:SetFont(fontPath, size, flag)

    self.LeftLabel:SetShadowOffset(1, -1)
    self.RightLabel:SetShadowOffset(1, -1)
    self.LeftLabel:SetShadowColor(0, 0, 0, 0.6)
    self.RightLabel:SetShadowColor(0, 0, 0, 0.6)

    self.LeftLabel:SetTextColor(1, 1, 1)
    self.RightLabel:SetTextColor(1, 1, 1)

    self.LeftLabel:SetText(L.LEFT_SHORT or "L")
    self.RightLabel:SetText(L.RIGHT_SHORT or "R")

    if self.SizeLabel then
        self.SizeLabel:SetFont(STANDARD_TEXT_FONT, 28, "OUTLINE")
        self:UpdateSizeLabel()
    end

    self:ApplyAlpha()
end

function LRH:ApplyAlpha()
    local a = LeftRightConfig.alpha or 1
    local d = self.DESIGNS[self:GetDesignKey()] or self.DESIGNS.CLASSIC

    if self.MainFrame then
        self.MainFrame:SetAlpha(1)
    end

    if self.LeftFill then self.LeftFill:SetAlpha(a) end
    if self.RightFill then self.RightFill:SetAlpha(a) end

    if self.LeftBorder then
        if d.noBorder then
            self.LeftBorder:SetAlpha(0)
        else
            self.LeftBorder:SetAlpha(a)
        end
    end

    if self.RightBorder then
        if d.noBorder then
            self.RightBorder:SetAlpha(0)
        else
            self.RightBorder:SetAlpha(a)
        end
    end

    if self.LeftLabel then self.LeftLabel:SetAlpha(a) end
    if self.RightLabel then self.RightLabel:SetAlpha(a) end

    if self.SizeLabel then
        self.SizeLabel:SetAlpha(1)
        if LeftRightDB.dragEnabled then
            self.SizeLabel:Show()
        else
            self.SizeLabel:Hide()
        end
    end
end

-------------------------------------------------
-- Position helpers
-------------------------------------------------
local function GetUIParentCenterPx()
    local l, b, w, h = UIParent:GetRect()
    if not l then return end
    local s = UIParent:GetEffectiveScale() or 1
    return (l + w / 2) * s, (b + h / 2) * s, w * s, h * s
end

local function GetFrameCenterPx(frame)
    local l, b = frame:GetLeft(), frame:GetBottom()
    if not l then return end
    local s = frame:GetEffectiveScale() or 1
    local w, h = frame:GetWidth() * s, frame:GetHeight() * s
    return (l * s) + w / 2, (b * s) + h / 2, w, h
end

local function ClampOffsetPx(frame, xPx, yPx)
    local _, _, pw, ph = GetUIParentCenterPx()
    local _, _, fw, fh = GetFrameCenterPx(frame)
    if not pw or not fw then return xPx, yPx end

    local minX = -pw / 2 + fw / 2
    local maxX =  pw / 2 - fw / 2
    local minY = -ph / 2 + fh / 2
    local maxY =  ph / 2 - fh / 2

    return U.Clamp(xPx, minX, maxX), U.Clamp(yPx, minY, maxY)
end

local function EnsureDefaultPosition(frame)
    if LeftRightConfig.xOffsetPx ~= nil and LeftRightConfig.yOffsetPx ~= nil then
        return
    end

    local _, _, _, ph = GetUIParentCenterPx()
    local _, _, _, fh = GetFrameCenterPx(frame)

    if not ph or not fh then
        LeftRightConfig.xOffsetPx = 0
        LeftRightConfig.yOffsetPx = 0
        return
    end

    LeftRightConfig.xOffsetPx = 0
    LeftRightConfig.yOffsetPx = ph / 2 - fh / 2 - LRH.TOP_MARGIN_PX
end

-------------------------------------------------
-- Position / visibility
-------------------------------------------------
function LRH:ApplyPosition()
    if not self.MainFrame then return end
    EnsureDefaultPosition(self.MainFrame)

    local x = LeftRightConfig.xOffsetPx or 0
    local y = LeftRightConfig.yOffsetPx or 0
    x, y = ClampOffsetPx(self.MainFrame, x, y)

    self.MainFrame:ClearAllPoints()
    self.MainFrame:SetPoint("CENTER", UIParent, "CENTER", U.PxToUI(x), U.PxToUI(y))
end

function LRH:UpdateVisibility()
    if self.MainFrame then
        self.MainFrame:SetShown(LeftRightDB.enabled)
    end
end

-------------------------------------------------
-- Drag visuals
-------------------------------------------------
local grid

local function ClearGridTextures()
    if not grid then return end
    for _, r in ipairs({ grid:GetRegions() }) do
        if r and r:GetObjectType() == "Texture" then
            r:Hide()
            r:SetTexture(nil)
        end
    end
end

local function DrawGrid()
    if not grid then return end
    grid:SetAllPoints(UIParent)

    local sw, sh = UIParent:GetWidth(), UIParent:GetHeight()
    ClearGridTextures()

    for x = 0, sw, LRH.SNAP_PX do
        local t = grid:CreateTexture(nil, "ARTWORK")
        t:SetColorTexture(0, 0.44, 0.87, 0.25)
        t:SetSize(1, sh)
        t:SetPoint("TOPLEFT", grid, "TOPLEFT", x, 0)
    end

    for y = 0, sh, LRH.SNAP_PX do
        local t = grid:CreateTexture(nil, "ARTWORK")
        t:SetColorTexture(0, 0.44, 0.87, 0.25)
        t:SetSize(sw, 1)
        t:SetPoint("TOPLEFT", grid, "TOPLEFT", 0, -y)
    end

    local midH = grid:CreateTexture(nil, "OVERLAY")
    midH:SetColorTexture(1, 0, 0, 0.8)
    midH:SetSize(sw, 2)
    midH:SetPoint("TOPLEFT", grid, "TOPLEFT", 0, -sh / 2)

    local midV = grid:CreateTexture(nil, "OVERLAY")
    midV:SetColorTexture(1, 0, 0, 0.8)
    midV:SetSize(2, sh)
    midV:SetPoint("TOPLEFT", grid, "TOPLEFT", sw / 2, 0)
end

function LRH:UpdateDragVisuals()
    if not self.MainFrame then return end

    if not grid then
        grid = CreateFrame("Frame", "LeftRightGrid", UIParent)
        grid:SetFrameStrata("BACKGROUND")
        grid:Hide()
    end

    if LeftRightDB.dragEnabled then
        if self.Highlight then self.Highlight:Show() end
        if self.SizeLabel then
            self:UpdateSizeLabel()
            self.SizeLabel:Show()
        end

        ApplySharedBackdrop(self.MainFrame)

        DrawGrid()
        grid:Show()
    else
        if self.Highlight then self.Highlight:Hide() end
        if self.SizeLabel then self.SizeLabel:Hide() end
        grid:Hide()

        self.MainFrame:SetBackdrop(nil)
    end
end

-------------------------------------------------
-- Reset + confirmation
-------------------------------------------------
local function ResetToDefaults()
    LeftRightConfig.xOffsetPx   = nil
    LeftRightConfig.yOffsetPx   = nil

    LeftRightConfig.sizeMul     = LRH.DEFAULT_SIZE_MUL
    LeftRightConfig.alpha       = 1

    LeftRightConfig.arrowGapPx  = 150
    LeftRightConfig.arrowDesign = "CLASSIC"

    LeftRightConfig.leftColor   = { r = 0.20, g = 0.60, b = 1.00 }
    LeftRightConfig.rightColor  = { r = 1.00, g = 0.20, b = 0.20 }

    LeftRightConfig.borderStyle = "GOLD"
    LeftRightConfig.fontName    = "Standard"
    LeftRightConfig.fontKey     = "STANDARD"
    LeftRightConfig.fontOutline = "OUTLINE"

    LeftRightDB.enabled = true
    LeftRightDB.dragEnabled = false

    LRH:FullApply()

    if LRH.UI and LRH.UI.Quick and LRH.UI.Quick.Refresh then
        LRH.UI.Quick.Refresh()
    end

    print("|cFF00FF00" .. (L.ADDON_NAME or "Left Right Helper") .. ": " .. (L.RESET_DONE or "Defaults restored") .. "|r")
end

function LRH:ConfirmReset(onAccept)
    StaticPopupDialogs = StaticPopupDialogs or {}
    StaticPopupDialogs["LRH_RESET_CONFIRM"] = StaticPopupDialogs["LRH_RESET_CONFIRM"] or {
        text = L.RESET_CONFIRM_TEXT or "Reset to defaults?",
        button1 = L.RESET_CONFIRM_YES or "Reset",
        button2 = L.RESET_CONFIRM_NO or "Cancel",
        timeout = 0,
        whileDead = 1,
        hideOnEscape = 1,
        preferredIndex = 3,
        OnAccept = function()
            if onAccept then onAccept() end
        end,
    }
    StaticPopup_Show("LRH_RESET_CONFIRM")
end

function LRH:ResetRequested()
    self:ConfirmReset(function()
        ResetToDefaults()
        if LeftRightDB.dragEnabled then
            self:SetDragMode(false)
        end
    end)
end

-------------------------------------------------
-- Drag mode
-------------------------------------------------
local escCatcher = CreateFrame("Frame", "LeftRightEscCatcher", UIParent)
escCatcher:Hide()

UISpecialFrames = UISpecialFrames or {}
do
    local exists = false
    for _, n in ipairs(UISpecialFrames) do
        if n == "LeftRightEscCatcher" then
            exists = true
            break
        end
    end
    if not exists then
        table.insert(UISpecialFrames, "LeftRightEscCatcher")
    end
end

function LRH:SetDragMode(state)
    LeftRightDB.dragEnabled = state and true or false

    if not self.MainFrame then return end

    if state then
        self.MainFrame:EnableMouse(true)
        self.MainFrame:EnableMouseWheel(true)
        self.MainFrame:RegisterForDrag("LeftButton")
        escCatcher:Show()

        self:UpdateDragVisuals()
        if LRH.UI and LRH.UI.ShowQuickOptions then
            LRH.UI.ShowQuickOptions()
        end

        print("|cFF00FF00" .. (L.ADDON_NAME or "Left Right Helper") .. ": " .. (L.DRAG_ON or "Drag mode enabled") .. "|r")
    else
        self.MainFrame:EnableMouse(false)
        self.MainFrame:EnableMouseWheel(false)
        self.MainFrame:RegisterForDrag()
        escCatcher:Hide()

        self:UpdateDragVisuals()
        if LRH.UI and LRH.UI.HideQuickOptions then
            LRH.UI.HideQuickOptions()
        end

        print("|cFFFF0000" .. (L.ADDON_NAME or "Left Right Helper") .. ": " .. (L.DRAG_OFF or "Drag mode disabled") .. "|r")
    end
end

escCatcher:SetScript("OnHide", function()
    if LeftRightDB.dragEnabled then
        LRH:SetDragMode(false)
    end
end)

-------------------------------------------------
-- Frame drag + wheel handlers
-------------------------------------------------
function LRH:AttachFrameScripts()
    if not self.MainFrame then return end

    self.MainFrame:SetScript("OnDragStart", function()
        if not LeftRightDB.dragEnabled then return end
        LRH:ApplyPosition()
        LRH.MainFrame:StartMoving()
    end)

    self.MainFrame:SetScript("OnDragStop", function()
        if not LeftRightDB.dragEnabled then return end
        LRH.MainFrame:StopMovingOrSizing()

        local pcx, pcy = GetUIParentCenterPx()
        local fcx, fcy = GetFrameCenterPx(LRH.MainFrame)
        if not pcx or not fcx then return end

        local x = U.SnapPx(fcx - pcx, LRH.SNAP_PX)
        local y = U.SnapPx(fcy - pcy, LRH.SNAP_PX)
        x, y = ClampOffsetPx(LRH.MainFrame, x, y)

        LeftRightConfig.xOffsetPx = x
        LeftRightConfig.yOffsetPx = y
        LRH:ApplyPosition()

        if LRH.UI and LRH.UI.Quick and LRH.UI.Quick.Refresh then
            LRH.UI.Quick.Refresh()
        end
    end)

    self.MainFrame:SetScript("OnMouseWheel", function(_, delta)
        if not LeftRightDB.dragEnabled then return end

        local mul = (LeftRightConfig.sizeMul or LRH.DEFAULT_SIZE_MUL) + (delta > 0 and LRH.MUL_STEP or -LRH.MUL_STEP)
        LeftRightConfig.sizeMul = U.Clamp(mul, LRH.MIN_MUL, LRH.MAX_MUL)

        LRH:ApplySizeAndLayout()
        LRH:ApplyFont()
        LRH:ApplyPosition()
        LRH:ApplyAlpha()

        if LRH.UI and LRH.UI.Quick and LRH.UI.Quick.Refresh then
            LRH.UI.Quick.Refresh()
        end
    end)
end

-------------------------------------------------
-- Full apply
-------------------------------------------------
function LRH:FullApply()
    self:ApplyDesign()
    self:ApplyFillTint()
    self:ApplyBorderTint()
    self:ApplySizeAndLayout()
    self:ApplyFont()
    self:ApplyPosition()
    self:UpdateVisibility()
    self:UpdateDragVisuals()
    self:ApplyAlpha()
end

-------------------------------------------------
-- Init
-------------------------------------------------
local ev = CreateFrame("Frame")
ev:RegisterEvent("PLAYER_LOGIN")
ev:SetScript("OnEvent", function()
    LRH_RegisterBundledFonts()

    if LRH.UI and LRH.UI.CreateMainFrame then
        LRH.UI.CreateMainFrame()
    end

    LRH:RefreshAvailableDesigns()
    LeftRightConfig.arrowDesign = LRH:GetDesignKey()

    LRH:FullApply()
    LRH:SetDragMode(LeftRightDB.dragEnabled)
end)

C_Timer.After(0, function()
    if LRH and LRH.GetDesignKey then
        LeftRightConfig.arrowDesign = LRH:GetDesignKey()
    end
end)