--[[
    Options.lua - TGXG Interrupt
    -----------------------------------------------------------------------
    Custom settings window (dark theme, green accent), opened via /tgxg.

    Two view modes (toggle at the top, persisted):
      NORMAL — essentials only, everything else stays preconfigured
      EXPERT — every option visible (the full set)
    Toggling rebuilds the window content in place.

    Layout: fixed header (logo banner + "Created by ColdwaterGODX") and a
    scrollable two-column body (UIPanelScrollFrameTemplate mouse wheel).
    -----------------------------------------------------------------------
]]

TGX = TGX or {}
TGX.Options = TGX.Options or {}
local OPT = TGX.Options

local _win, _scroll, _content
local ACCENT = { 0.2, 1.0, 0.6 }

local WINDOW_W   = 720
local WINDOW_H   = 690
local BANNER_ASPECT = 3168 / 1344
local COL_WIDTH  = 330
local COL1_X     = 14
local COL2_X     = 376

local CREDIT = "Created by ColdwaterGODX"

local function db() return TGX.db end
local de = GetLocale() == "deDE"

local S = {
    EXPERT         = de and "Expertenmodus (alle Einstellungen zeigen)"
                          or "Expert mode (show all settings)",
    SEC_TRACKER    = de and "Interrupt-Tracker"        or "Interrupt tracker",
    SEC_CASTBAR    = de and "Blizzard-Castbars (Ziel/Fokus)" or "Blizzard cast bars (target/focus)",
    SEC_ALERTS     = de and "Hinweise & Einteilung"    or "Alerts & assignment",
    SEC_ASSIGNPERM = de and "Einteilungs-Rechte"       or "Assignment permissions",
    ENABLE_TRACKER = de and "Tracker aktivieren"       or "Enable tracker",
    LOCKED         = de and "Fenster sperren"          or "Lock frames",
    SHOW_OWN       = de and "Eigenen Balken zeigen"    or "Show own bar",
    SHOW_TITLE     = de and "Titel anzeigen"           or "Show title",
    GROW_UP        = de and "Nach oben wachsen"        or "Grow upward",
    CLASS_COLORS   = de and "Klassenfarben"            or "Class colors",
    HIDE_SOLO      = de and "Solo ausblenden"          or "Hide while solo",
    SCALE          = de and "Skalierung (%)"           or "Scale (%)",
    BAR_WIDTH      = de and "Balkenbreite"             or "Bar width",
    BAR_HEIGHT     = de and "Balkenhöhe"               or "Bar height",
    FONT_SIZE      = de and "Schriftgröße"             or "Font size",
    CB_ENABLE      = de and "Blizzard-Castbars verwalten" or "Manage Blizzard cast bars",
    CB_FOCUS       = de and "Auch Fokus-Castbar"       or "Also focus cast bar",
    CB_LOCK        = de and "Castbars sperren"         or "Lock cast bars",
    CB_SCALE       = de and "Ziel: Skalierung (%)"     or "Target: scale (%)",
    CB_F_SCALE     = de and "Fokus: Skalierung (%)"    or "Focus: scale (%)",
    CB_WIDTH       = de and "Ziel: Breite (0 = Standard)"  or "Target: width (0 = default)",
    CB_HEIGHT      = de and "Ziel: Höhe (0 = Standard)"    or "Target: height (0 = default)",
    CB_F_WIDTH     = de and "Fokus: Breite (0 = Standard)" or "Focus: width (0 = default)",
    CB_F_HEIGHT    = de and "Fokus: Höhe (0 = Standard)"   or "Focus: height (0 = default)",
    CB_RESET_T     = de and "Ziel zurücksetzen"        or "Reset target",
    CB_RESET_F     = de and "Fokus zurücksetzen"       or "Reset focus",
    CB_HINT        = de and "Entsperren zeigt grüne Greifflächen auf den Original-Castbars — ziehen, fertig."
                          or "Unlocking shows green drag handles on the original cast bars — drag, done.",
    AL_ENABLE      = de and "Kick-Hinweis (Ziel)"      or "Kick alert (target)",
    AL_FOCUS       = de and "Auch für Fokusziel"       or "Also for focus target",
    AL_SOUND       = de and "Hinweiston abspielen"     or "Play alert sound",
    AL_UNKNOWN     = de and "Auch bei unbekanntem Status (M+)" or "Also on unknown status (M+)",
    AL_SPELLDB     = de and "Zauber-Datenbank nutzen (lernend)" or "Use spell database (learning)",
    AS_ENABLE      = de and "Automatische Einteilung"  or "Automatic assignment",
    AS_ANNOUNCE    = de and "Einteilung im Chat posten" or "Post assignment to chat",
    AS_SOUND       = de and "Ton bei Marker-Hinweis"   or "Sound on marker alert",
    ROT_ENABLE     = de and "Kick-Rotation aktivieren"  or "Enable kick rotation",
    ROT_NOTE       = de and "Reihenfolge aller Kicker (du zuerst, dann Gruppe). Kickt der Aktuelle, ist der Nächste dran und bekommt beim nächsten kickbaren Cast \"DU BIST DRAN\". Andere sehen den Hinweis nur als Backup, wenn der Diensthabende im Cooldown ist. Goldener » im Tracker zeigt, wer dran ist."
                          or "Order of all kickers (you first, then party). When the current one kicks, the next is up and gets \"YOUR TURN\" on the next kickable cast. Others only see a backup alert while the assignee is on cooldown. A golden » in the tracker marks whose turn it is.",
    CCF_ENABLE     = de and "CC-Vorschlag bei Kick im CD" or "Suggest CC while kick on CD",
    HIST_ENABLE    = de and "Interrupt-Verlauf unter dem Tracker" or "Interrupt history below tracker",
    FF_ENABLE      = de and "Fail-Kick-Feedback (roter Balken)" or "Fail-kick feedback (red bar)",
    FF_SOUND       = de and "Fail-Kick-Ton"             or "Fail-kick sound",
    MM_ENABLE      = de and "Minimap-Button anzeigen"   or "Show minimap button",
    MM_TIP1        = de and "Linksklick: Einstellungen" or "Left click: settings",
    MM_TIP2        = de and "Rechtsklick: Alles sperren/entsperren" or "Right click: lock/unlock all",
    MM_TIP3        = de and "Shift-Klick: Testmodus"    or "Shift-click: test mode",
    AP_ASSIST      = de and "Assistenten dürfen einteilen" or "Assistants may assign",
    AP_ALL         = de and "Jeder darf einteilen"     or "Everyone may assign",
    AP_NOTE        = de and "Assistenten: Auch Raid-Assistenten dürfen die Marker-Einteilung an die Gruppe senden. Jeder: Alle TGXG-Nutzer dürfen einteilen — die letzte Änderung gewinnt, gleichzeitige Klicks können sich gegenseitig überschreiben! Empfehlung: beide AUS (nur der Gruppenleiter verteilt — eine Quelle der Wahrheit)."
                          or "Assistants: raid assistants may also broadcast the marker assignment. Everyone: any TGXG user may assign — last change wins, simultaneous clicks can overwrite each other! Recommended: both OFF (leader only — one source of truth).",
    SEC_KICKICON   = de and "Eigener Kick (Symbol)"    or "Own kick (icon)",
    KI_ENABLE      = de and "Kick-Symbol anzeigen"     or "Show kick icon",
    KI_LOCK        = de and "Kick-Symbol sperren"      or "Lock kick icon",
    KI_COMBAT      = de and "Nur im Kampf anzeigen (aus = immer anzeigen)"
                          or "Only show in combat (off = always show)",
    KI_SIZE        = de and "Symbolgröße"              or "Icon size",
    BTN_TEST       = de and "Testmodus"                or "Test mode",
    BTN_ASSIGN     = de and "Jetzt einteilen"          or "Assign now",
    BTN_CLEAR      = de and "Einteilung löschen"       or "Clear assignment",
    HINT_MOVE      = de and "Zum Verschieben: Sperre lösen und Fenster ziehen."
                          or "To move: unlock and drag the frames.",
    HINT_NORMAL    = de and "Normalmodus: nur die wichtigsten Optionen. Expertenmodus einschalten für alle Detail-Einstellungen."
                          or "Normal mode: essentials only. Enable expert mode for every detail setting.",
}

------------------------------------------------------------
-- Widget factory — constructors take a column context {x, y}
------------------------------------------------------------
local function Section(col, text)
    local fs = _content:CreateFontString(nil, "OVERLAY")
    fs:SetFont(STANDARD_TEXT_FONT, 14, "OUTLINE")
    fs:SetTextColor(ACCENT[1], ACCENT[2], ACCENT[3])
    fs:SetPoint("TOPLEFT", _content, "TOPLEFT", col.x, col.y)
    fs:SetText(text)
    local line = _content:CreateTexture(nil, "ARTWORK")
    line:SetColorTexture(ACCENT[1], ACCENT[2], ACCENT[3], 0.3)
    line:SetPoint("TOPLEFT", fs, "BOTTOMLEFT", 0, -3)
    line:SetSize(COL_WIDTH - 20, 1)
    col.y = col.y - 29
end

local function Checkbox(col, label, key, onChange)
    local cb = CreateFrame("CheckButton", nil, _content, "UICheckButtonTemplate")
    cb:SetPoint("TOPLEFT", _content, "TOPLEFT", col.x, col.y)
    cb:SetSize(24, 24)
    cb.text = cb:CreateFontString(nil, "OVERLAY")
    cb.text:SetFont(STANDARD_TEXT_FONT, 12, "")
    cb.text:SetPoint("LEFT", cb, "RIGHT", 4, 0)
    cb.text:SetText(label)
    cb:SetChecked(db()[key])
    cb:SetScript("OnClick", function(self)
        db()[key] = self:GetChecked() and true or false
        if onChange then onChange(db()[key]) end
    end)
    col.y = col.y - 24
    return cb
end

local function Slider(col, label, key, minV, maxV, step, onChange)
    local fs = _content:CreateFontString(nil, "OVERLAY")
    fs:SetFont(STANDARD_TEXT_FONT, 12, "")
    fs:SetPoint("TOPLEFT", _content, "TOPLEFT", col.x + 4, col.y)
    fs:SetText(label .. ": |cffffd700" .. tostring(db()[key]) .. "|r")

    local sl = CreateFrame("Slider", nil, _content, "MinimalSliderTemplate")
    sl:SetPoint("TOPLEFT", _content, "TOPLEFT", col.x + 4, col.y - 16)
    sl:SetSize(COL_WIDTH - 40, 16)
    sl:SetMinMaxValues(minV, maxV)
    sl:SetValueStep(step)
    sl:SetObeyStepOnDrag(true)
    sl:SetValue(db()[key])
    sl:SetScript("OnValueChanged", function(_, value)
        value = math.floor(value / step + 0.5) * step
        if db()[key] == value then return end
        db()[key] = value
        fs:SetText(label .. ": |cffffd700" .. tostring(value) .. "|r")
        if onChange then onChange(value) end
    end)
    col.y = col.y - 40
    return sl
end

-- Multi-line explanatory note inside a column
local function Note(col, text)
    local fs = _content:CreateFontString(nil, "OVERLAY")
    fs:SetFont(STANDARD_TEXT_FONT, 10, "")
    fs:SetTextColor(0.62, 0.62, 0.62)
    fs:SetPoint("TOPLEFT", _content, "TOPLEFT", col.x + 4, col.y)
    fs:SetWidth(COL_WIDTH - 24)
    fs:SetJustifyH("LEFT")
    fs:SetText(text)
    col.y = col.y - (fs:GetStringHeight() + 10)
end

local function Button(label, width, onClick)
    local b = CreateFrame("Button", nil, _content, "UIPanelButtonTemplate")
    b:SetSize(width or 120, 24)
    b:SetText(label)
    b:SetScript("OnClick", onClick)
    return b
end

------------------------------------------------------------
-- Minimap button
-- Left: settings · Right: lock/unlock ALL frames · Shift-left: test mode
------------------------------------------------------------
local function ToggleAllLocks()
    local d = db()
    -- If anything is unlocked → lock everything; otherwise unlock all.
    local anyUnlocked = (not d.locked) or (not d.castbarLocked) or (not d.kickIconLocked)
    local lockState = anyUnlocked
    d.locked, d.castbarLocked, d.kickIconLocked = lockState, lockState, lockState
    if TGX.Tracker  then TGX.Tracker:ApplyLock()  end
    if TGX.Castbar  then TGX.Castbar:ApplyLock()  end
    if TGX.KickIcon then TGX.KickIcon:ApplyLock() TGX.KickIcon:UpdateVisibility() end
end

local function PositionMinimapButton(btn)
    local angle = math.rad(db().minimapPos or 220)
    btn:ClearAllPoints()
    btn:SetPoint("CENTER", Minimap, "CENTER",
        80 * math.cos(angle), 80 * math.sin(angle))
end

function OPT:CreateMinimapButton()
    if self._mmBtn then return end
    local btn = CreateFrame("Button", "TGXGMinimapButton", Minimap)
    self._mmBtn = btn
    btn:SetSize(31, 31)
    btn:SetFrameStrata("MEDIUM")
    btn:SetFrameLevel(8)
    btn:RegisterForClicks("LeftButtonUp", "RightButtonUp")
    btn:RegisterForDrag("LeftButton")

    btn.icon = btn:CreateTexture(nil, "BACKGROUND")
    btn.icon:SetSize(20, 20)
    btn.icon:SetPoint("CENTER", -1, 1)
    btn.icon:SetTexture("Interface\\AddOns\\TGXG_Interrupt\\Media\\icon.png")
    pcall(btn.icon.SetMask, btn.icon, "Interface\\CharacterFrame\\TempPortraitAlphaMask")

    btn.border = btn:CreateTexture(nil, "OVERLAY")
    btn.border:SetSize(53, 53)
    btn.border:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")
    btn.border:SetPoint("TOPLEFT")

    btn:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight")

    btn:SetScript("OnClick", function(_, mouseButton)
        if mouseButton == "RightButton" then
            ToggleAllLocks()
        elseif IsShiftKeyDown() then
            TGX:StartTestMode()
        else
            OPT:Toggle()
        end
    end)

    -- Drag around the minimap rim: track the cursor angle while held.
    btn:SetScript("OnDragStart", function(self)
        self:SetScript("OnUpdate", function(self)
            local mx, my = Minimap:GetCenter()
            local cx, cy = GetCursorPosition()
            local s = UIParent:GetEffectiveScale()
            db().minimapPos = math.deg(math.atan2(cy / s - my, cx / s - mx)) % 360
            PositionMinimapButton(self)
        end)
    end)
    btn:SetScript("OnDragStop", function(self)
        self:SetScript("OnUpdate", nil)
    end)

    btn:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_LEFT")
        GameTooltip:SetText("|cff33ff99TGXG|r Interrupt", 1, 1, 1)
        GameTooltip:AddLine(S.MM_TIP1, 0.8, 0.8, 0.8)
        GameTooltip:AddLine(S.MM_TIP2, 0.8, 0.8, 0.8)
        GameTooltip:AddLine(S.MM_TIP3, 0.8, 0.8, 0.8)
        GameTooltip:Show()
    end)
    btn:SetScript("OnLeave", function() GameTooltip:Hide() end)

    PositionMinimapButton(btn)
    self:UpdateMinimapButton()
end

function OPT:UpdateMinimapButton()
    if not self._mmBtn then return end
    self._mmBtn:SetShown(db().minimapButton ~= false)
end

------------------------------------------------------------
-- Window
------------------------------------------------------------
function OPT:Init()
    self:CreateMinimapButton()
end

local function RefreshAll()
    if TGX.Tracker then TGX.Tracker:Rebuild(); TGX.Tracker:ApplyLock() end
    if TGX.Castbar then TGX.Castbar:ApplySettings() end
end

local Build   -- forward declaration (Rebuild calls it)

-- Rebuild the whole window (used by the expert-mode toggle). The old
-- frame is orphaned (WoW can't destroy frames) — cheap and rare.
local function RebuildWindow()
    local wasShown = _win and _win:IsShown()
    if _win then _win:Hide() end
    _win, _scroll, _content = nil, nil, nil
    Build()
    if wasShown then _win:Show() end
end

Build = function()
    local EXPERT = db().expertMode == true

    _win = CreateFrame("Frame", "TGXGOptionsWindow", UIParent, "BackdropTemplate")
    _win:SetSize(WINDOW_W, WINDOW_H)
    _win:SetPoint("CENTER")
    _win:SetFrameStrata("DIALOG")
    _win:SetMovable(true)
    _win:EnableMouse(true)
    _win:RegisterForDrag("LeftButton")
    _win:SetScript("OnDragStart", _win.StartMoving)
    _win:SetScript("OnDragStop", _win.StopMovingOrSizing)
    _win:SetClampedToScreen(true)
    _win:SetBackdrop({
        bgFile   = "Interface\\BUTTONS\\WHITE8X8",
        edgeFile = "Interface\\BUTTONS\\WHITE8X8",
        edgeSize = 1,
    })
    _win:SetBackdropColor(0.07, 0.07, 0.08, 0.97)
    _win:SetBackdropBorderColor(ACCENT[1], ACCENT[2], ACCENT[3], 0.8)
    if not OPT._escRegistered then
        OPT._escRegistered = true
        table.insert(UISpecialFrames, "TGXGOptionsWindow")
    end

    ------------------------------------------------------------
    -- Header: logo banner (or text title) + credit line
    ------------------------------------------------------------
    local headerH = 40
    local logo = _win:CreateTexture(nil, "ARTWORK")
    local setOk = logo:SetTexture("Interface\\AddOns\\TGXG_Interrupt\\Media\\logo.png")
    local hasLogo = (setOk == true) or (setOk == nil and logo:GetTexture() ~= nil)
    if hasLogo then
        local innerW  = WINDOW_W - 2
        local bannerH = math.floor(innerW / BANNER_ASPECT + 0.5)
        logo:SetPoint("TOPLEFT",  _win, "TOPLEFT",  1, -1)
        logo:SetPoint("TOPRIGHT", _win, "TOPRIGHT", -1, -1)
        logo:SetHeight(bannerH)
        headerH = bannerH + 2
        local ver = _win:CreateFontString(nil, "OVERLAY")
        ver:SetFont(STANDARD_TEXT_FONT, 10, "OUTLINE")
        ver:SetPoint("BOTTOMRIGHT", logo, "BOTTOMRIGHT", -6, 4)
        ver:SetTextColor(0.8, 0.8, 0.8)
        ver:SetText("v" .. TGX.VERSION .. "  |cffaaaaaa—|r  |cff33ff99" .. CREDIT .. "|r")
    else
        logo:Hide()
        local title = _win:CreateFontString(nil, "OVERLAY")
        title:SetFont(STANDARD_TEXT_FONT, 16, "OUTLINE")
        title:SetPoint("TOP", _win, "TOP", 0, -12)
        title:SetText("|cff33ff99TGXG|r Interrupt  |cff888888v" .. TGX.VERSION .. "|r")
        local credit = _win:CreateFontString(nil, "OVERLAY")
        credit:SetFont(STANDARD_TEXT_FONT, 10, "")
        credit:SetPoint("TOP", title, "BOTTOM", 0, -2)
        credit:SetTextColor(0.2, 1.0, 0.6)
        credit:SetText(CREDIT)
        headerH = 54
    end

    local close = CreateFrame("Button", nil, _win, "UIPanelCloseButton")
    close:SetPoint("TOPRIGHT", _win, "TOPRIGHT", -2, -2)

    local sep = _win:CreateTexture(nil, "ARTWORK")
    sep:SetColorTexture(ACCENT[1], ACCENT[2], ACCENT[3], 0.25)
    sep:SetPoint("TOPLEFT", _win, "TOPLEFT", 8, -headerH)
    sep:SetPoint("TOPRIGHT", _win, "TOPRIGHT", -8, -headerH)
    sep:SetHeight(1)

    ------------------------------------------------------------
    -- Scrollable body
    ------------------------------------------------------------
    _scroll = CreateFrame("ScrollFrame", "TGXGOptionsScroll", _win, "UIPanelScrollFrameTemplate")
    _scroll:SetPoint("TOPLEFT", _win, "TOPLEFT", 4, -(headerH + 4))
    _scroll:SetPoint("BOTTOMRIGHT", _win, "BOTTOMRIGHT", -26, 8)

    _content = CreateFrame("Frame", nil, _scroll)
    _content:SetSize(WINDOW_W - 30, 10)
    _scroll:SetScrollChild(_content)

    ------------------------------------------------------------
    -- Mode toggle (spans the top of column 1)
    ------------------------------------------------------------
    local colTop = { x = COL1_X, y = -6 }
    Checkbox(colTop, S.EXPERT, "expertMode", function() RebuildWindow() end)
    if not EXPERT then Note(colTop, S.HINT_NORMAL) end
    local startY = colTop.y - 4

    ------------------------------------------------------------
    -- Column 1: Tracker + Alerts & assignment (+ permissions)
    ------------------------------------------------------------
    local col1 = { x = COL1_X, y = startY }
    Section(col1, S.SEC_TRACKER)
    Checkbox(col1, S.ENABLE_TRACKER, "trackerEnabled", function() TGX.Tracker:UpdateVisibility() end)
    Checkbox(col1, S.LOCKED, "locked", function()
        if TGX.Tracker then TGX.Tracker:ApplyLock() end
    end)
    Checkbox(col1, S.MM_ENABLE, "minimapButton", function() OPT:UpdateMinimapButton() end)
    Checkbox(col1, S.HIST_ENABLE, "historyFeedEnabled", function() TGX.Tracker:UpdateFeed() end)
    Slider(col1, S.SCALE, "scale", 50, 200, 5, RefreshAll)
    if EXPERT then
        Checkbox(col1, S.SHOW_OWN,     "showOwnBar",     RefreshAll)
        Checkbox(col1, S.SHOW_TITLE,   "showTitle",      RefreshAll)
        Checkbox(col1, S.GROW_UP,      "growUpward",     RefreshAll)
        Checkbox(col1, S.CLASS_COLORS, "classColorBars", RefreshAll)
        Checkbox(col1, S.HIDE_SOLO,    "hideOutOfGroup", function() TGX.Tracker:UpdateVisibility() end)
        Slider(col1, S.BAR_WIDTH,  "barWidth",  120, 400, 5, RefreshAll)
        Slider(col1, S.BAR_HEIGHT, "barHeight", 16, 48, 1, RefreshAll)
        Slider(col1, S.FONT_SIZE,  "fontSize",  8, 20, 1, RefreshAll)
    end

    col1.y = col1.y - 6
    Section(col1, S.SEC_ALERTS)
    Checkbox(col1, S.AL_ENABLE,  "kickAlertEnabled")
    Checkbox(col1, S.AL_SOUND,   "kickAlertSound")
    Checkbox(col1, S.CCF_ENABLE, "ccFallbackEnabled")
    Checkbox(col1, S.AS_ENABLE,  "autoAssignEnabled")
    Checkbox(col1, S.ROT_ENABLE, "rotationEnabled", function()
        if TGX.Rotation then TGX.Rotation:Rebuild(true) end
    end)
    Note(col1, S.ROT_NOTE)
    if EXPERT then
        Checkbox(col1, S.AL_FOCUS,    "kickAlertFocus")
        Checkbox(col1, S.AL_UNKNOWN,  "kickAlertUnknown")
        Checkbox(col1, S.AL_SPELLDB,  "spellDBEnabled")
        Checkbox(col1, S.AS_ANNOUNCE, "assignAnnounceChat")
        Checkbox(col1, S.AS_SOUND,    "assignAlertSound")
        Checkbox(col1, S.FF_ENABLE,   "failFeedbackEnabled")
        Checkbox(col1, S.FF_SOUND,    "failFeedbackSound")
    end

    -- Assignment permissions: shown in BOTH modes (explicit user feature),
    -- with the explanation + recommendation right below the toggles.
    col1.y = col1.y - 6
    Section(col1, S.SEC_ASSIGNPERM)
    Checkbox(col1, S.AP_ASSIST, "assignAllowAssist")
    Checkbox(col1, S.AP_ALL,    "assignAllowAll")
    Note(col1, S.AP_NOTE)

    ------------------------------------------------------------
    -- Column 2: Blizzard cast bars + own-kick icon
    ------------------------------------------------------------
    local col2 = { x = COL2_X, y = startY }
    Section(col2, S.SEC_CASTBAR)
    Checkbox(col2, S.CB_ENABLE, "castbarEnabled", function() TGX.Castbar:ApplySettings() end)
    Checkbox(col2, S.CB_LOCK,   "castbarLocked",  function() TGX.Castbar:ApplyLock() end)
    Slider(col2, S.CB_SCALE,   "castbarScale",      50, 250, 5, function() TGX.Castbar:ApplySettings() end)
    Slider(col2, S.CB_F_SCALE, "castbarFocusScale", 50, 250, 5, function() TGX.Castbar:ApplySettings() end)
    if EXPERT then
        Checkbox(col2, S.CB_FOCUS, "castbarFocus", function() TGX.Castbar:ApplySettings() end)
        Slider(col2, S.CB_WIDTH,    "castbarBarWidth",       0, 400, 5, function() TGX.Castbar:ApplySettings() end)
        Slider(col2, S.CB_HEIGHT,   "castbarBarHeight",      0, 48, 1,  function() TGX.Castbar:ApplySettings() end)
        Slider(col2, S.CB_F_WIDTH,  "castbarFocusBarWidth",  0, 400, 5, function() TGX.Castbar:ApplySettings() end)
        Slider(col2, S.CB_F_HEIGHT, "castbarFocusBarHeight", 0, 48, 1,  function() TGX.Castbar:ApplySettings() end)
    end

    local bResetT = Button(S.CB_RESET_T, 150, function() TGX.Castbar:ResetPosition("target") end)
    bResetT:SetPoint("TOPLEFT", _content, "TOPLEFT", COL2_X + 4, col2.y)
    local bResetF = Button(S.CB_RESET_F, 150, function() TGX.Castbar:ResetPosition("focus") end)
    bResetF:SetPoint("LEFT", bResetT, "RIGHT", 8, 0)
    col2.y = col2.y - 28
    Note(col2, S.CB_HINT)

    col2.y = col2.y - 6
    Section(col2, S.SEC_KICKICON)
    Checkbox(col2, S.KI_ENABLE, "kickIconEnabled", function() TGX.KickIcon:ApplySettings() end)
    Checkbox(col2, S.KI_LOCK, "kickIconLocked", function()
        TGX.KickIcon:ApplyLock()
        TGX.KickIcon:UpdateVisibility()
    end)
    Slider(col2, S.KI_SIZE, "kickIconSize", 24, 128, 4, function() TGX.KickIcon:ApplySettings() end)
    if EXPERT then
        Checkbox(col2, S.KI_COMBAT, "kickIconCombatOnly", function()
            TGX.KickIcon:UpdateVisibility()
        end)
    end

    ------------------------------------------------------------
    -- Bottom row: buttons + hint
    ------------------------------------------------------------
    local bottomY = math.min(col1.y, col2.y) - 10
    local bTest = Button(S.BTN_TEST, 110, function() TGX:StartTestMode() end)
    bTest:SetPoint("TOPLEFT", _content, "TOPLEFT", COL1_X, bottomY)
    local bAssign = Button(S.BTN_ASSIGN, 130, function() TGX.Assign:Run() end)
    bAssign:SetPoint("LEFT", bTest, "RIGHT", 8, 0)
    local bClear = Button(S.BTN_CLEAR, 130, function() TGX.Assign:Clear() end)
    bClear:SetPoint("LEFT", bAssign, "RIGHT", 8, 0)
    bottomY = bottomY - 30

    local hint = _content:CreateFontString(nil, "OVERLAY")
    hint:SetFont(STANDARD_TEXT_FONT, 11, "")
    hint:SetTextColor(0.6, 0.6, 0.6)
    hint:SetPoint("TOPLEFT", _content, "TOPLEFT", COL1_X, bottomY)
    hint:SetWidth(WINDOW_W - 60)
    hint:SetJustifyH("LEFT")
    hint:SetText(S.HINT_MOVE)
    bottomY = bottomY - 24

    _content:SetHeight(-bottomY + 10)
end

function OPT:Toggle()
    if not _win then Build() end
    if _win:IsShown() then
        _win:Hide()
        if TGX.testMode then TGX:StopTestMode() end
    else
        _win:Show()
    end
end
