-- Utility: Get Class Color
local function GetClassColor()
    local _, class = UnitClass("player")
    local color = RAID_CLASS_COLORS and RAID_CLASS_COLORS[class]
    if not color then
        color = { r = 1, g = 1, b = 1 }
    end
    return color.r or 1, color.g or 1, color.b or 1
end

-- Helper: Set fontstring color to class color
local function SetClassColorText(fontString)
    if fontString and fontString.SetTextColor then
        local r, g, b = GetClassColor()
        fontString:SetTextColor(r, g, b, 1)
    end
end

-- ChayBar.lua
-- ChayBar v4.8.4: Dragon GUI | Class Theme | Settings Drag Tab | GUI Resize Handle | Foreground Color Fix
-- Retail / Midnight (12.0+)

local addonName, ChayBar = ...
ChayBar = ChayBar or {}

------------------------------------------------------------
------------------------------------------------------------
-- Media Check
------------------------------------------------------------
if not ChayBar.Media then
    print("|cffff0000ChayBar Error:|r Media.lua not loaded. Check TOC.")
    return
end

local TEX   = ChayBar.Media.Textures
local FONT  = ChayBar.Media.Fonts
local BARS  = ChayBar.Media.Bars
local ICONS = ChayBar.Media.Icons
local SIZE  = ChayBar.Media.Sizes or { BarWidth = 320, BarHeight = 18 }

------------------------------------------------------------
-- SavedVariables
------------------------------------------------------------
ChayBarDB = ChayBarDB or {}

-- Defaults
if not ChayBarDB.barTextureKey then ChayBarDB.barTextureKey = "JiberishBushido1" end
if ChayBarDB.locked == nil then ChayBarDB.locked = false end
if ChayBarDB.scale == nil then ChayBarDB.scale = 1 end
if ChayBarDB.enabled == nil then ChayBarDB.enabled = true end

------------------------------------------------------------
-- SavedVariables
------------------------------------------------------------
ChayBarDB = ChayBarDB or {}

-- Defaults
if ChayBarDB.locked == nil then ChayBarDB.locked = false end
if ChayBarDB.scale == nil then ChayBarDB.scale = 1 end
if ChayBarDB.enabled == nil then ChayBarDB.enabled = true end
if type(ChayBarDB.width) ~= "number" then ChayBarDB.width = SIZE.BarWidth or 320 end
if type(ChayBarDB.height) ~= "number" then ChayBarDB.height = SIZE.BarHeight or 18 end
if ChayBarDB.showText == nil then ChayBarDB.showText = true end
if ChayBarDB.reverse == nil then ChayBarDB.reverse = false end
if ChayBarDB.font == nil then ChayBarDB.font = "Expressway" end
if ChayBarDB.fontSize == nil then ChayBarDB.fontSize = 14 end
if ChayBarDB.minimapAngle == nil then ChayBarDB.minimapAngle = 225 end
if ChayBarDB.paladinProcThreshold ~= 3 and ChayBarDB.paladinProcThreshold ~= 5 then ChayBarDB.paladinProcThreshold = 3 end

-- Proc glow options
if not ChayBarDB.glowColor then ChayBarDB.glowColor = { 0.8, 0.2, 1.0, 1.0 } end
if type(ChayBarDB.glowScale) ~= "number" then ChayBarDB.glowScale = 1.35 end
if type(ChayBarDB.glowSpeed) ~= "number" then ChayBarDB.glowSpeed = 0.4 end
if type(ChayBarDB.glowOffsetY) ~= "number" then ChayBarDB.glowOffsetY = 0 end
if type(ChayBarDB.glowOffsetX) ~= "number" then ChayBarDB.glowOffsetX = 0 end
if type(ChayBarDB.GlowIntensity) ~= "number" then ChayBarDB.GlowIntensity = 1.0 end

if ChayBarDB.haloTextureKey == nil then ChayBarDB.haloTextureKey = "spellactivationoverlay_0" end
if ChayBarDB.animMode == nil then ChayBarDB.animMode = "SCROLL_H" end

if not ChayBarDB.foregroundColor then ChayBarDB.foregroundColor = { 0.65, 0.15, 0.85, 1 } end
if not ChayBarDB.backgroundColor then ChayBarDB.backgroundColor = { 0.08, 0.08, 0.08, 0.9 } end

if type(ChayBarDB.point) ~= "table" then
    ChayBarDB.point = { "CENTER", "CENTER", 0, -220 }
end

local isTesting = false
local isProcActive = false

------------------------------------------------------------
-- Multi-Class Configuration
------------------------------------------------------------
local CLASS_CONFIG = {
    WARLOCK = { power = Enum.PowerType.SoulShards, name = "Soul Shards" },
    PALADIN = { power = Enum.PowerType.HolyPower,  name = "Holy Power" },
    EVOKER  = { power = Enum.PowerType.Essence,    name = "Essence" },
    MONK    = { power = Enum.PowerType.Chi,        name = "Chi", spec = 3 },
    MAGE    = { power = Enum.PowerType.ArcaneCharges, name = "Arcane Charges", spec = 1 },
    ROGUE   = { power = Enum.PowerType.ComboPoints, name = "Combo Points" },
    DRUID   = { dynamic = true, targetScope = true },
    DEMONHUNTER = { power = Enum.PowerType.Fury, name = "Fury" },
    WARRIOR = { power = Enum.PowerType.Rage, name = "Rage" },
    DEATHKNIGHT = { power = Enum.PowerType.RunicPower, name = "Runic Power" },
}

local playerClass = nil
local classData = nil

------------------------------------------------------------
-- Config Window
------------------------------------------------------------
local function ApplyElvUIStyle(frame, borderAlpha)
    if not frame.SetBackdrop then Mixin(frame, BackdropTemplateMixin) end
    frame:SetBackdrop({
        bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
        edgeFile = "Interface\\Buttons\\WHITE8x8",
        tile = false, tileSize = 0, edgeSize = 1,
        insets = { left = 1, right = 1, top = 1, bottom = 1 }
    })
    frame:SetBackdropColor(0.02, 0.02, 0.025, 0.92)
    frame:SetBackdropBorderColor(0.55, 0.02, 0.02, borderAlpha or 1)
    if not frame.shadow then
        local shadow = CreateFrame("Frame", nil, frame, "BackdropTemplate")
        shadow:SetPoint("TOPLEFT", -4, 4)
        shadow:SetPoint("BOTTOMRIGHT", 4, -4)
        shadow:SetFrameLevel(frame:GetFrameLevel() - 1)
        shadow:SetBackdrop({
            edgeFile = "Interface\\Buttons\\WHITE8x8",
            edgeSize = 4,
        })
        shadow:SetBackdropBorderColor(0, 0, 0, 0.72)
        frame.shadow = shadow
    end
end

-- HELPER: Style a frame to look like a Rounded Status Bar Button (Class Colored)
local classStyledFrames = {}

local function StyleAsClassBar(f)
    if not f then return end
    if not f.SetBackdrop then Mixin(f, BackdropTemplateMixin) end
    if not f.__ChayBarClassStyled then
        f.__ChayBarClassStyled = true
        table.insert(classStyledFrames, f)
    end

    f:SetBackdrop({
        edgeFile = "Interface\\Buttons\\WHITE8x8",
        edgeSize = 1,
        bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
        tile = false, tileSize = 0,
        insets = { left = 1, right = 1, top = 1, bottom = 1 }
    })

    local r, g, b = GetClassColor()

    f:SetBackdropColor(0.045, 0.035, 0.035, 0.94)
    f:SetBackdropBorderColor(math.max(r, 0.65), math.max(g * 0.35, 0.03), math.max(b * 0.35, 0.03), 1)

    if f.SetStatusBarTexture then
        f:SetMinMaxValues(0, 1)
        f:SetValue(1)
        f:SetStatusBarTexture("Interface\\AddOns\\ChayBar\\Media\\Bars\\JiberishBushido1.tga")
        f:SetStatusBarColor(0.20, 0.015, 0.015, 0.82)
    end

    if f.sb then f.sb:Hide() end

    if not f.text then
        f.text = f:CreateFontString(nil, "OVERLAY", "GameFontNormalHuge")
        f.text:SetPoint("CENTER")
        f.text:SetTextColor(1, 0.82, 0, 1)
        f.text:SetJustifyH("CENTER")
    end
    f.text:SetFont("Interface\\AddOns\\ChayBar\\Media\\Fonts\\Expressway.ttf", 15, "OUTLINE")
    f.text:SetShadowColor(0, 0, 0, 0.95)
    f.text:SetShadowOffset(1, -1)

    if not f.gloss then
        f.gloss = f:CreateTexture(nil, "ARTWORK", nil, 1)
        f.gloss:SetPoint("TOPLEFT", 2, -2)
        f.gloss:SetPoint("BOTTOMRIGHT", -2, 2)
        f.gloss:SetTexture("Interface\\Buttons\\WHITE8x8")
        f.gloss:SetVertexColor(1, 1, 1, 0.035)
    end

    if not f.hl then
        f.hl = f:CreateTexture(nil, "HIGHLIGHT")
        f.hl:SetAllPoints(f)
        f.hl:SetTexture("Interface\\Buttons\\UI-Listbox-Highlight")
        f.hl:SetAlpha(0.22)
        f.hl:SetBlendMode("ADD")
    end
end

local cfg = CreateFrame("Frame", "ChayBarConfigWindow", UIParent, "BackdropTemplate")
cfg:SetSize(ChayBarDB.guiWidth or 900, ChayBarDB.guiHeight or 850)
cfg:SetPoint("CENTER")
cfg:SetFrameStrata("HIGH")
cfg:SetToplevel(true)
cfg:SetResizable(true)
if cfg.SetResizeBounds then
    cfg:SetResizeBounds(720, 640, 1200, 1000)
end
cfg:SetClipsChildren(true)
cfg:SetBackdrop({
    bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
    edgeFile = "Interface\\Buttons\\WHITE8x8",
    tile = false, tileSize = 0, edgeSize = 2,
    insets = { left = 1, right = 1, top = 1, bottom = 1 }
})
cfg:SetBackdropColor(0.015, 0.012, 0.012, 0.98)
cfg:SetBackdropBorderColor(0.75, 0.02, 0.02, 1)

local guiBackground = cfg:CreateTexture(nil, "BACKGROUND", nil, -8)
guiBackground:SetPoint("TOPLEFT", cfg, "TOPLEFT", 2, -2)
guiBackground:SetPoint("BOTTOMRIGHT", cfg, "BOTTOMRIGHT", -2, 2)
guiBackground:SetTexture("Interface\\AddOns\\ChayBar\\Media\\GUI_DragonBackground.png")
guiBackground:SetTexCoord(0, 1, 0, 1)
guiBackground:SetAlpha(0.30)

local guiVignette = cfg:CreateTexture(nil, "BACKGROUND", nil, -7)
guiVignette:SetPoint("TOPLEFT", cfg, "TOPLEFT", 2, -2)
guiVignette:SetPoint("BOTTOMRIGHT", cfg, "BOTTOMRIGHT", -2, 2)
guiVignette:SetTexture("Interface\\ChatFrame\\ChatFrameBackground")
guiVignette:SetVertexColor(0, 0, 0, 0.52)

local topAccent = cfg:CreateTexture(nil, "BORDER")
topAccent:SetPoint("TOPLEFT", cfg, "TOPLEFT", 1, -1)
topAccent:SetPoint("TOPRIGHT", cfg, "TOPRIGHT", -1, -1)
topAccent:SetHeight(72)
topAccent:SetTexture("Interface\\ChatFrame\\ChatFrameBackground")
topAccent:SetVertexColor(0.11, 0.0, 0.0, 0.78)

local bottomAccent = cfg:CreateTexture(nil, "BORDER")
bottomAccent:SetPoint("BOTTOMLEFT", cfg, "BOTTOMLEFT", 1, 1)
bottomAccent:SetPoint("BOTTOMRIGHT", cfg, "BOTTOMRIGHT", -1, 1)
bottomAccent:SetHeight(52)
bottomAccent:SetTexture("Interface\\ChatFrame\\ChatFrameBackground")
bottomAccent:SetVertexColor(0.08, 0.0, 0.0, 0.68)


local cfgDragTab = CreateFrame("Button", "ChayBar_ConfigDragTab", cfg, "BackdropTemplate")
cfgDragTab:SetSize(150, 34)
cfgDragTab:SetPoint("BOTTOMLEFT", cfg, "BOTTOMLEFT", 12, 0)
cfgDragTab:SetFrameLevel(cfg:GetFrameLevel() + 20)
cfgDragTab:EnableMouse(true)
cfgDragTab:RegisterForDrag("LeftButton")
cfgDragTab:SetBackdrop({
    bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
    edgeFile = "Interface\\Buttons\\WHITE8x8",
    tile = false, tileSize = 0, edgeSize = 1,
    insets = { left = 1, right = 1, top = 1, bottom = 1 }
})
cfgDragTab:SetBackdropColor(0.12, 0.015, 0.015, 0.98)
cfgDragTab:SetBackdropBorderColor(0.85, 0.05, 0.05, 1)
cfgDragTab.texture = cfgDragTab:CreateTexture(nil, "ARTWORK")
cfgDragTab.texture:SetPoint("TOPLEFT", 4, -4)
cfgDragTab.texture:SetPoint("BOTTOMRIGHT", -4, 4)
cfgDragTab.texture:SetTexture("Interface\\AddOns\\ChayBar\\Media\\Bars\\JiberishBushido1.tga")
cfgDragTab.texture:SetVertexColor(0.75, 0.05, 0.05, 0.82)
cfgDragTab.texture:SetAlpha(0.70)
cfgDragTab.text = cfgDragTab:CreateFontString(nil, "OVERLAY", "GameFontNormal")
cfgDragTab.text:SetPoint("CENTER", cfgDragTab, "CENTER", 0, 0)
cfgDragTab.text:SetText("DRAG")
cfgDragTab.text:SetFont("Interface\\AddOns\\ChayBar\\Media\\Fonts\\Expressway.ttf", 16, "OUTLINE")
cfgDragTab.text:SetTextColor(1, 1, 1, 1)
cfgDragTab.text:SetShadowColor(0, 0, 0, 1)
cfgDragTab.text:SetShadowOffset(1, -1)
cfgDragTab:SetScript("OnDragStart", function()
    cfg:StartMoving()
end)
cfgDragTab:SetScript("OnDragStop", function()
    cfg:StopMovingOrSizing()
end)
cfgDragTab:SetScript("OnEnter", function(self)
    self:SetAlpha(1)
end)
cfgDragTab:SetScript("OnLeave", function(self)
    self:SetAlpha(0.92)
end)
cfgDragTab:SetAlpha(0.92)


local cfgResizeTab = CreateFrame("Button", "ChayBar_ConfigResizeTab", cfg, "BackdropTemplate")
cfgResizeTab:SetSize(44, 44)
cfgResizeTab:SetPoint("BOTTOMRIGHT", cfg, "BOTTOMRIGHT", -6, 6)
cfgResizeTab:SetFrameLevel(cfg:GetFrameLevel() + 30)
cfgResizeTab:EnableMouse(true)
cfgResizeTab:SetBackdrop({
    bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
    edgeFile = "Interface\\Buttons\\WHITE8x8",
    tile = false, tileSize = 0, edgeSize = 1,
    insets = { left = 1, right = 1, top = 1, bottom = 1 }
})
cfgResizeTab:SetBackdropColor(0.10, 0.015, 0.015, 0.96)
cfgResizeTab:SetBackdropBorderColor(0.85, 0.05, 0.05, 1)
cfgResizeTab.texture = cfgResizeTab:CreateTexture(nil, "ARTWORK")
cfgResizeTab.texture:SetPoint("TOPLEFT", 4, -4)
cfgResizeTab.texture:SetPoint("BOTTOMRIGHT", -4, 4)
cfgResizeTab.texture:SetTexture("Interface\\AddOns\\ChayBar\\Media\\Bars\\JiberishBushido1.tga")
cfgResizeTab.texture:SetVertexColor(0.75, 0.05, 0.05, 0.78)
cfgResizeTab.texture:SetAlpha(0.72)
cfgResizeTab.line1 = cfgResizeTab:CreateTexture(nil, "OVERLAY")
cfgResizeTab.line1:SetTexture("Interface\\Buttons\\WHITE8x8")
cfgResizeTab.line1:SetSize(23, 2)
cfgResizeTab.line1:SetPoint("BOTTOMRIGHT", cfgResizeTab, "BOTTOMRIGHT", -7, 11)
cfgResizeTab.line1:SetRotation(-0.785398)
cfgResizeTab.line1:SetVertexColor(1, 1, 1, 0.85)
cfgResizeTab.line2 = cfgResizeTab:CreateTexture(nil, "OVERLAY")
cfgResizeTab.line2:SetTexture("Interface\\Buttons\\WHITE8x8")
cfgResizeTab.line2:SetSize(16, 2)
cfgResizeTab.line2:SetPoint("BOTTOMRIGHT", cfgResizeTab, "BOTTOMRIGHT", -7, 19)
cfgResizeTab.line2:SetRotation(-0.785398)
cfgResizeTab.line2:SetVertexColor(1, 1, 1, 0.70)
cfgResizeTab.text = cfgResizeTab:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
cfgResizeTab.text:SetPoint("BOTTOM", cfgResizeTab, "BOTTOM", 0, 3)
cfgResizeTab.text:SetText("SIZE")
cfgResizeTab.text:SetFont("Interface\\AddOns\\ChayBar\\Media\\Fonts\\Expressway.ttf", 8, "OUTLINE")
cfgResizeTab.text:SetTextColor(1, 1, 1, 1)
cfgResizeTab:RegisterForClicks("LeftButtonDown", "LeftButtonUp")
cfgResizeTab:SetScript("OnMouseDown", function(self, button)
    if button == "LeftButton" then
        cfg:StartSizing("BOTTOMRIGHT", true)
    end
end)
cfgResizeTab:SetScript("OnMouseUp", function(self, button)
    if button == "LeftButton" then
        cfg:StopMovingOrSizing()
        ChayBarDB.guiWidth = math.floor((cfg:GetWidth() or 900) + 0.5)
        ChayBarDB.guiHeight = math.floor((cfg:GetHeight() or 850) + 0.5)
    end
end)
cfgResizeTab:SetScript("OnHide", function()
    cfg:StopMovingOrSizing()
    ChayBarDB.guiWidth = math.floor((cfg:GetWidth() or 900) + 0.5)
    ChayBarDB.guiHeight = math.floor((cfg:GetHeight() or 850) + 0.5)
end)
cfgResizeTab:SetScript("OnEnter", function(self)
    self:SetAlpha(1)
end)
cfgResizeTab:SetScript("OnLeave", function(self)
    self:SetAlpha(0.92)
end)
cfgResizeTab:SetAlpha(0.92)

local guiLogo = cfg:CreateTexture(nil, "ARTWORK", nil, 2)
guiLogo:SetSize(96, 96)
guiLogo:SetPoint("TOPLEFT", cfg, "TOPLEFT", 22, -10)
guiLogo:SetTexture("Interface\\AddOns\\ChayBar\\Media\\GUI_ChayLogo.png")
guiLogo:SetAlpha(1)

local content = cfg

cfg:SetMovable(true)
cfg:EnableMouse(true)
cfg:RegisterForDrag("LeftButton")
cfg:SetScript("OnDragStart", cfg.StartMoving)
cfg:SetScript("OnDragStop", cfg.StopMovingOrSizing)
cfg:Hide()

local title = cfg:CreateFontString(nil, "OVERLAY", "GameFontNormalHuge")
title:SetPoint("TOP", 36, -24)
title:SetText("ChayBar Settings")
title:SetFont("Interface\\AddOns\\ChayBar\\Media\\Fonts\\Montserrat-Black.ttf", 30, "OUTLINE")
title:SetTextColor(0.96, 0.96, 0.96, 1)
title:SetShadowColor(0.75, 0, 0, 0.9)
title:SetShadowOffset(2, -2)
title:SetDrawLayer("OVERLAY", 7)

local titleSub = cfg:CreateFontString(nil, "OVERLAY", "GameFontNormal")
titleSub:SetPoint("TOP", title, "BOTTOM", 0, -2)
titleSub:SetText("Dragon-forged resource bar controls")
titleSub:SetFont("Interface\\AddOns\\ChayBar\\Media\\Fonts\\Expressway.ttf", 13, "OUTLINE")
titleSub:SetTextColor(0.95, 0.35, 0.35, 1)
titleSub:SetShadowColor(0, 0, 0, 0.95)
titleSub:SetShadowOffset(1, -1)
titleSub:SetDrawLayer("OVERLAY", 7)

-- GUI Scale Dropdown
local scaleOptions = {
    { key = 0.75, text = "75%" },
    { key = 0.90, text = "90%" },
    { key = 1.0, text = "100%" },
    { key = 1.10, text = "110%" },
}
local guiScale = 1.0
local function SetGUIScale(val)
    guiScale = val
    cfg:SetScale(val * 0.675)
end
local scaleDD = CreateFrame("Frame", nil, cfg, "UIDropDownMenuTemplate, BackdropTemplate")
UIDropDownMenu_SetWidth(scaleDD, 80)
scaleDD:SetPoint("TOPRIGHT", cfg, "TOPRIGHT", -60, -22)
ApplyElvUIStyle(scaleDD, 0.12)
local function InitScaleDD(self, level)
    for _, item in ipairs(scaleOptions) do
        local info = UIDropDownMenu_CreateInfo()
        info.text = item.text
        info.value = item.key
        info.checked = (item.key == guiScale)
        info.func = function(btnSelf)
            UIDropDownMenu_SetSelectedValue(scaleDD, btnSelf.value)
            SetGUIScale(btnSelf.value)
            CloseDropDownMenus()
        end
        UIDropDownMenu_AddButton(info, level)
    end
end
UIDropDownMenu_Initialize(scaleDD, InitScaleDD)
UIDropDownMenu_SetSelectedValue(scaleDD, 1.0)
UIDropDownMenu_SetText(scaleDD, "100%")
SetGUIScale(1.0)

local bar, bg, text
local procParent
local frameBack, frameFront
local texBack, texFront
local minimapButton

local function EnsureColorTable(dbKey, fallback)
    if type(ChayBarDB[dbKey]) ~= "table" then
        ChayBarDB[dbKey] = { fallback[1], fallback[2], fallback[3], fallback[4] }
    end

    local c = ChayBarDB[dbKey]
    for i = 1, 4 do
        if type(c[i]) ~= "number" then
            c[i] = fallback[i]
        end
    end

    return c
end

local function ApplyForegroundColorToBar()
    if not bar or not bar.SetStatusBarColor then return end
    local c = EnsureColorTable("foregroundColor", { 0.65, 0.15, 0.85, 1 })
    bar:SetStatusBarColor(c[1], c[2], c[3], c[4])
end

local function ApplyBackgroundColorToBar()
    if not bg or not bg.SetVertexColor then return end
    local c = EnsureColorTable("backgroundColor", { 0.08, 0.08, 0.08, 0.9 })
    bg:SetVertexColor(c[1], c[2], c[3], c[4])
end

local function RefreshClassTheme()
    local r, g, b = GetClassColor()

    if cfg and cfg.SetBackdropBorderColor then
        cfg:SetBackdropBorderColor(r, g, b, 1)
    end

    if topAccent then
        topAccent:SetVertexColor(r * 0.22, g * 0.08, b * 0.08, 0.82)
    end

    if bottomAccent then
        bottomAccent:SetVertexColor(r * 0.16, g * 0.06, b * 0.06, 0.70)
    end

    if title then
        title:SetTextColor(math.max(r, 0.82), math.max(g, 0.82), math.max(b, 0.82), 1)
    end

    if titleSub then
        titleSub:SetTextColor(math.max(r * 0.85, 0.72), math.max(g * 0.85, 0.72), math.max(b * 0.85, 0.72), 0.96)
    end

    for _, styledFrame in ipairs(classStyledFrames) do
        if styledFrame and styledFrame.SetBackdropBorderColor then
            styledFrame:SetBackdropBorderColor(math.max(r, 0.65), math.max(g, 0.08), math.max(b, 0.08), 1)
        end
        if styledFrame and styledFrame.SetStatusBarColor then
            styledFrame:SetStatusBarColor(r * 0.28, g * 0.12, b * 0.12, 0.84)
        end
        if styledFrame and styledFrame.text and styledFrame.text.SetTextColor then
            styledFrame.text:SetTextColor(math.max(r, 0.82), math.max(g, 0.82), math.max(b, 0.82), 1)
        end
    end

    ApplyForegroundColorToBar()

    if cfgDragTab then
        if cfgDragTab.SetBackdropColor then
            cfgDragTab:SetBackdropColor(r * 0.18, g * 0.06, b * 0.06, 0.98)
            cfgDragTab:SetBackdropBorderColor(r, g, b, 1)
        end
        if cfgDragTab.texture then
            cfgDragTab.texture:SetVertexColor(r, g, b, 0.82)
        end
        if cfgDragTab.text then
            cfgDragTab.text:SetTextColor(1, 1, 1, 1)
        end
    end

    if cfgResizeTab then
        if cfgResizeTab.SetBackdropColor then
            cfgResizeTab:SetBackdropColor(r * 0.18, g * 0.06, b * 0.06, 0.98)
            cfgResizeTab:SetBackdropBorderColor(r, g, b, 1)
        end
        if cfgResizeTab.texture then
            cfgResizeTab.texture:SetVertexColor(r, g, b, 0.78)
        end
        if cfgResizeTab.line1 then
            cfgResizeTab.line1:SetVertexColor(math.max(r, 0.85), math.max(g, 0.85), math.max(b, 0.85), 0.85)
        end
        if cfgResizeTab.line2 then
            cfgResizeTab.line2:SetVertexColor(math.max(r, 0.75), math.max(g, 0.75), math.max(b, 0.75), 0.70)
        end
        if cfgResizeTab.text then
            cfgResizeTab.text:SetTextColor(1, 1, 1, 1)
        end
    end
end

local function Clamp(v, lo, hi)
    if v < lo then return lo end
    if v > hi then return hi end
    return v
end

local function CheckSpecValidity()
    if not classData then return false end
    if not classData.spec then return true end
    local spec = GetSpecialization()
    if not spec then return true end
    return spec == classData.spec
end

-- ==========================================
-- Safe Math Wrappers for Secret Numbers
-- ==========================================
local function SafeMathFloor(val)
    local success, res = pcall(function() return math.floor(val + 0.0001) end)
    return success and res or val
end

local function SafeClamp(val, minVal, maxVal)
    local success, res = pcall(function() return Clamp(val, minVal, maxVal) end)
    return success and res or val
end

local function SafeCompareGlow(current, max)
    local success, res = pcall(function() return current >= max end)
    return success and res or false
end

local function GetPaladinProcThreshold()
    local threshold = tonumber(ChayBarDB.paladinProcThreshold) or 3
    if threshold ~= 3 and threshold ~= 5 then
        threshold = 3
        ChayBarDB.paladinProcThreshold = threshold
    end
    return threshold
end

local function SafeComparePaladin(current)
    local threshold = GetPaladinProcThreshold()
    local success, res = pcall(function() return current >= threshold end)
    return success and res or false
end

local function SafeIsZero(val)
    local success, res = pcall(function() return val == 0 end)
    return success and res or false
end

local function SafeConcatText(current, max)
    local success, res = pcall(function() return current .. " / " .. max end)
    if success then return res end
    return current
end

local function GetActiveResource()
    if not CheckSpecValidity() or not classData then return 0, 1, 0 end

    local pType = classData.power

    if classData.dynamic then
        pType = UnitPowerType("player")
        if pType ~= Enum.PowerType.ComboPoints and pType ~= Enum.PowerType.Rage then
            return 0, 1, 0
        end
    end

    if classData.targetScope and not isTesting then
        if not UnitExists("target") or UnitIsDead("target") or not UnitCanAttack("player", "target") then
            local leftovers = UnitPower("player", pType)
            if SafeIsZero(leftovers) then
                local m = UnitPowerMax("player", pType)
                if m < 1 then m = 5 end
                return 0, m, 0
            end
        end
    end

    if isTesting then
        local m = UnitPowerMax("player", pType)
        if m < 1 then m = 5 end
        return m, m, m
    end

    if playerClass == "WARLOCK" then
        local fragments = UnitPower("player", pType, true)
        local maxFragments = UnitPowerMax("player", pType, true)
        if maxFragments < 1 then maxFragments = 50 end

        local success, exactShards = pcall(function() return fragments / 10 end)
        if success then
            local maxShards = maxFragments / 10
            local displayShards = math.floor(exactShards + 0.0001)
            return Clamp(exactShards, 0, maxShards), maxShards, displayShards
        else
            local standardShards = UnitPower("player", pType)
            local standardMax = UnitPowerMax("player", pType)
            if standardMax < 1 then standardMax = 5 end
            return standardShards, standardMax, standardShards
        end
    end

    local current = UnitPower("player", pType)
    local max = UnitPowerMax("player", pType)
    if max < 1 then max = 1 end

    local displayCurrent = SafeMathFloor(current)
    return SafeClamp(current, 0, max), max, displayCurrent
end

-- HALO TEXTURES
local function GetHaloTexturePath(key)
    if TEX[key] then return TEX[key] end
    return TEX.spellactivationoverlay_0 or "Interface\\SpellActivationOverlay\\IconAlert"
end

local function UpdateLockState()
    if not bar then return end
    local unlocked = not ChayBarDB.locked and ChayBarDB.enabled
    bar:EnableMouse(unlocked)
end

local function ApplyBarSettings()
    if not bar then return end

    bar:SetScale(tonumber(ChayBarDB.scale) or 1)
    local w = tonumber(ChayBarDB.width) or SIZE.BarWidth or 320
    local h = tonumber(ChayBarDB.height) or SIZE.BarHeight or 18
    ChayBarDB.width, ChayBarDB.height = w, h
    bar:SetSize(w, h)

    local barTexPath = BARS[ChayBarDB.barTextureKey] or BARS["JiberishBushido1"] or "Interface\\TargetingFrame\\UI-StatusBar"
    bar:SetStatusBarTexture(barTexPath)
    if bg then bg:SetTexture(barTexPath) end
    bar:SetReverseFill(ChayBarDB.reverse)
    ApplyForegroundColorToBar()

    RefreshClassTheme()

    if bg then
        bg:SetAllPoints(bar)
        ApplyBackgroundColorToBar()
    end

    if text then
        text:SetShown(ChayBarDB.showText and true or false)
        local fontPath = FONT[ChayBarDB.font] or FONT.Expressway or "Fonts\\FRIZQT__.TTF"
        text:SetFont(fontPath, (tonumber(ChayBarDB.fontSize) or 14) + 12, "OUTLINE")
        text:SetTextColor(1, 1, 1, 1)
        text:SetShadowColor(0, 0, 0, 1)
        text:SetShadowOffset(2, -2)
    end

    local gs = tonumber(ChayBarDB.glowScale) or 1.35
    local offY = tonumber(ChayBarDB.glowOffsetY) or 0
    local offX = tonumber(ChayBarDB.glowOffsetX) or 0
    local intensity = tonumber(ChayBarDB.GlowIntensity) or 1.0

    local c = ChayBarDB.glowColor
    if type(c) ~= "table" then ChayBarDB.glowColor = { 1, 1, 1, 0.85 }; c = ChayBarDB.glowColor end
    local cr, cg, cb, ca = c[1], c[2], c[3], c[4]
    local finalR, finalG, finalB = cr * intensity, cg * intensity, cb * intensity

    if procParent then
        procParent:SetSize(w * gs, h * gs)
        procParent:ClearAllPoints()
        procParent:SetPoint("CENTER", bar, "CENTER", offX, offY)
    end

    if frameBack then frameBack:SetAllPoints(procParent) end
    if frameFront then frameFront:SetAllPoints(procParent) end

    local key = tostring(ChayBarDB.haloTextureKey or "spellactivationoverlay_0")
    local path = GetHaloTexturePath(key)

    if texFront then
        texFront:SetVertexColor(finalR, finalG, finalB, ca)
        texFront:SetTexture(path)
    end

    if texBack then
        texBack:SetVertexColor(finalR, finalG, finalB, ca)
        texBack:SetTexture(path)
    end

    UpdateLockState()

    if not ChayBarDB.enabled then
        bar:Hide()
        if procParent then
            procParent:SetScript("OnUpdate", nil)
            procParent:Hide()
        end
    end
end

local scrollPos = 0
local function ScrollUpdateFunc(self, elapsed)
    local speed = (tonumber(ChayBarDB.glowSpeed) or 0.4)
    scrollPos = scrollPos + (elapsed * speed)
    if scrollPos > 1 then scrollPos = scrollPos - 1 end

    local invPos = 1 - scrollPos

    if ChayBarDB.animMode == "SCROLL_V" then
        if texFront then texFront:SetTexCoord(0, 1, scrollPos, scrollPos + 1) end
        if texBack then texBack:SetTexCoord(0, 1, invPos, invPos + 1) end
    else
        if texFront then texFront:SetTexCoord(scrollPos, scrollPos + 1, 0, 1) end
        if texBack then texBack:SetTexCoord(invPos, invPos + 1, 0, 1) end
    end
end

local function RebuildAnimations()
    if not procParent then return end
    procParent:SetScript("OnUpdate", nil)
    if texFront then texFront:SetTexCoord(0, 1, 0, 1) end
    if texBack then texBack:SetTexCoord(0, 1, 0, 1) end
    scrollPos = 0
    procParent:SetScript("OnUpdate", ScrollUpdateFunc)
end

local function SetProcActive(active)
    if not procParent then return end
    if not ChayBarDB.enabled then
        active = false
    end
    if active == isProcActive then return end
    isProcActive = active

    if active then
        procParent:Show()
        frameBack:Show()
        frameFront:Show()
        RebuildAnimations()
    else
        procParent:SetScript("OnUpdate", nil)
        procParent:Hide()
    end
end

local function UpdateResource()
    if not bar then return end
    RefreshClassTheme()

    if not ChayBarDB.enabled then
        if bar:IsShown() then bar:Hide() end
        if procParent and procParent:IsShown() then
            procParent:SetScript("OnUpdate", nil)
            procParent:Hide()
        end
        isProcActive = false
        return
    end

    if not CheckSpecValidity() then
        if bar:IsShown() then bar:Hide() end
        if procParent and procParent:IsShown() then procParent:Hide() end
        return
    end

    local current, max, displayCurrent = GetActiveResource()

    if (classData and classData.targetScope and SafeIsZero(current) and not isTesting) or (classData and classData.dynamic and max <= 1) then
        if bar:IsShown() then bar:Hide() end
        if procParent and procParent:IsShown() then procParent:Hide() end
        return
    end

    if not bar:IsShown() then bar:Show() end

    bar:SetMinMaxValues(0, max)
    bar:SetValue(current)

    if text then
        text:SetText(SafeConcatText(displayCurrent, max))
        if ChayBarDB.showText then text:Show() else text:Hide() end
    end

    local shouldGlow = false
    if playerClass == "PALADIN" then
        shouldGlow = SafeComparePaladin(displayCurrent)
    else
        shouldGlow = SafeCompareGlow(displayCurrent, max)
    end

    if playerClass == "EVOKER" and not UnitAffectingCombat("player") then
        shouldGlow = false
    end

    SetProcActive(shouldGlow)
end

local function OpenColorPicker(colorTable, applyFunc)
    if type(colorTable) ~= "table" then return end
    local function ColorCallback()
        local r, g, b = ColorPickerFrame:GetColorRGB()
        local a = 1 - (ColorPickerFrame:GetColorAlpha() or 0)
        if r then
            colorTable[1], colorTable[2], colorTable[3], colorTable[4] = r, g, b, a
            applyFunc()
        end
    end

    if ColorPickerFrame and ColorPickerFrame.SetupColorPickerAndShow then
        local info = {
            r = colorTable[1] or 1, g = colorTable[2] or 1, b = colorTable[3] or 1,
            opacity = 1 - (colorTable[4] or 1), hasOpacity = true,
            swatchFunc = ColorCallback,
            opacityFunc = ColorCallback,
            cancelFunc = function(prev)
                if type(prev) == "table" then
                    colorTable[1] = prev.r or prev[1] or colorTable[1]
                    colorTable[2] = prev.g or prev[2] or colorTable[2]
                    colorTable[3] = prev.b or prev[3] or colorTable[3]
                    local op = prev.opacity or prev[4]
                    if type(op) == "number" then colorTable[4] = 1 - op end
                end
                applyFunc()
            end,
        }
        ColorPickerFrame:SetupColorPickerAndShow(info)
    end
end

local function CreateLabel(parent, textStr, anchor, rel, x, y)
    local fs = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    fs:SetPoint(anchor, rel, anchor, x, y)
    fs:SetText(textStr)
    return fs
end

local function CreateDropdown(parent, width, items, initialValue, onSelect, maxVisible)
    local dd = CreateFrame("Frame", nil, parent, "UIDropDownMenuTemplate")
    UIDropDownMenu_SetWidth(dd, width)
    dd:SetFrameLevel(parent:GetFrameLevel() + 5)

    maxVisible = maxVisible or #items
    local scrollOffsetLocal = 0

    local function RefreshDropdown()
        UIDropDownMenu_Initialize(dd, function(self, level)
            local total = #items
            local startIdx = scrollOffsetLocal + 1
            local endIdx = math.min(scrollOffsetLocal + maxVisible, total)
            for i = startIdx, endIdx do
                local item = items[i]
                local info = UIDropDownMenu_CreateInfo()
                info.text = item.text
                info.value = item.key
                info.checked = (item.key == initialValue)
                info.func = function(btnSelf)
                    UIDropDownMenu_SetSelectedValue(dd, btnSelf.value)
                    UIDropDownMenu_SetText(dd, btnSelf:GetText())
                    if onSelect then onSelect(btnSelf.value) end
                    CloseDropDownMenus()
                end
                UIDropDownMenu_AddButton(info, level)
            end
        end)
    end

    if maxVisible < #items then
        dd:EnableMouseWheel(true)
        dd:SetScript("OnMouseWheel", function(self, delta)
            local total = #items
            if total <= maxVisible then return end
            if delta < 0 and (scrollOffsetLocal + maxVisible) < total then
                scrollOffsetLocal = scrollOffsetLocal + 1
                RefreshDropdown()
                ToggleDropDownMenu(1, nil, dd)
            elseif delta > 0 and scrollOffsetLocal > 0 then
                scrollOffsetLocal = scrollOffsetLocal - 1
                RefreshDropdown()
                ToggleDropDownMenu(1, nil, dd)
            end
        end)
    end

    RefreshDropdown()
    UIDropDownMenu_SetSelectedValue(dd, initialValue)
    for _, item in ipairs(items) do
        if item.key == initialValue then UIDropDownMenu_SetText(dd, item.text); break end
    end
    return dd
end

------------------------------------------------------------
-- Config Buttons
------------------------------------------------------------
local RefreshBarDDList
local MARGIN = 40

-- 1. Foreground Color
local fgBtn = CreateFrame("StatusBar", nil, content, "BackdropTemplate")
fgBtn:SetPoint("TOP", content, "TOP", 0, -90)
fgBtn:SetPoint("LEFT", content, "LEFT", MARGIN, 0)
fgBtn:SetPoint("RIGHT", content, "RIGHT", -MARGIN, 0)
fgBtn:SetHeight(22)
StyleAsClassBar(fgBtn)
fgBtn.text:SetText("Foreground Color")
fgBtn:SetScript("OnMouseUp", function()
    OpenColorPicker(ChayBarDB.foregroundColor, function()
        ApplyForegroundColorToBar()
        ApplyBarSettings()
        UpdateResource()
        if RefreshBarDDList then RefreshBarDDList() end
    end)
end)

-- 2. Background Color
local bgBtn = CreateFrame("StatusBar", nil, content, "BackdropTemplate")
bgBtn:SetPoint("TOP", fgBtn, "BOTTOM", 0, -30)
bgBtn:SetPoint("LEFT", content, "LEFT", MARGIN, 0)
bgBtn:SetPoint("RIGHT", content, "RIGHT", -MARGIN, 0)
bgBtn:SetHeight(22)
StyleAsClassBar(bgBtn)
bgBtn.text:SetText("Background Color")
bgBtn:SetScript("OnMouseUp", function()
    OpenColorPicker(ChayBarDB.backgroundColor, function()
        ApplyBackgroundColorToBar()
        ApplyBarSettings()
        UpdateResource()
        if RefreshBarDDList then RefreshBarDDList() end
    end)
end)

-- 3. Proc Glow Color
local glowBtn = CreateFrame("StatusBar", nil, content, "BackdropTemplate")
glowBtn:SetPoint("TOP", bgBtn, "BOTTOM", 0, -30)
glowBtn:SetPoint("LEFT", content, "LEFT", MARGIN, 0)
glowBtn:SetPoint("RIGHT", content, "RIGHT", -MARGIN - 100, 0)
glowBtn:SetHeight(22)
StyleAsClassBar(glowBtn)
glowBtn.text:SetText("Proc Glow Color")
glowBtn:SetScript("OnMouseUp", function()
    OpenColorPicker(ChayBarDB.glowColor, function()
        ApplyBarSettings()
        UpdateResource()
    end)
end)

-- Halo Texture Dropdown
local haloLabel = CreateLabel(content, "", "TOP", glowBtn, 0, -32)
local haloList = {}
for k, v in pairs(TEX) do
    local niceName = k:gsub("_", " "):lower():gsub("^%l", string.upper)
    table.insert(haloList, { key = k, text = niceName })
end
table.sort(haloList, function(a, b) return a.text < b.text end)

local maxVisibleHalo = 8
local scrollOffsetHalo = 0
local haloDropdownOpen = false
local selectedHaloKey = ChayBarDB.haloTextureKey or "spellactivationoverlay_0"

local haloDD = CreateFrame("StatusBar", nil, content, "BackdropTemplate")
haloDD:SetPoint("TOP", haloLabel, "BOTTOM", 0, -24)
haloDD:SetPoint("LEFT", content, "LEFT", MARGIN, 0)
haloDD:SetPoint("RIGHT", content, "RIGHT", -MARGIN - 100, 0)
haloDD:SetHeight(22)
StyleAsClassBar(haloDD)

local initialHaloText = selectedHaloKey
for _, item in ipairs(haloList) do
    if item.key == selectedHaloKey then initialHaloText = item.text; break end
end
haloDD.text:SetText(initialHaloText)

local haloDDList = CreateFrame("Frame", nil, haloDD, BackdropTemplateMixin and "BackdropTemplate")
haloDDList:SetSize(haloDD:GetWidth(), maxVisibleHalo * 22)
haloDDList:SetPoint("TOPLEFT", haloDD, "BOTTOMLEFT", 0, -2)
haloDDList:SetFrameStrata("DIALOG")
haloDDList:SetBackdrop({ bgFile = "Interface/Tooltips/UI-Tooltip-Background", edgeFile = "Interface/Tooltips/UI-Tooltip-Border", tile = true, tileSize = 8, edgeSize = 8, insets = { left = 1, right = 1, top = 1, bottom = 1 } })
haloDDList:SetBackdropColor(0, 0, 0, 0.95)
haloDDList:Hide()

local haloDDButtons = {}
for i = 1, maxVisibleHalo do
    local btn = CreateFrame("Button", nil, haloDDList)
    btn:SetHeight(22)
    btn:SetPoint("TOPLEFT", haloDDList, "TOPLEFT", 0, -((i - 1) * 22))
    btn:SetPoint("RIGHT", haloDDList, "RIGHT", 0, 0)
    btn.text = btn:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    btn.text:SetPoint("LEFT", btn, "LEFT", 8, 0)
    btn.text:SetPoint("RIGHT", btn, "RIGHT", -8, 0)
    btn.text:SetJustifyH("LEFT")
    btn:SetHighlightTexture("Interface/QuestFrame/UI-QuestTitleHighlight")
    btn:EnableMouse(true)
    haloDDButtons[i] = btn
end

local function RefreshHaloDDList()
    local total = #haloList
    for i = 1, maxVisibleHalo do
        local idx = scrollOffsetHalo + i
        local btn = haloDDButtons[i]
        if idx <= total then
            local item = haloList[idx]
            btn.text:SetText(item.text)
            btn:Show()
            btn:SetScript("OnClick", function()
                selectedHaloKey = item.key
                ChayBarDB.haloTextureKey = item.key
                haloDD.text:SetText(item.text)
                isProcActive = false
                ApplyBarSettings()
                UpdateResource()
                haloDDList:Hide()
                haloDropdownOpen = false
            end)
            btn:SetScript("OnEnter", function(self) self:GetHighlightTexture():Show() end)
            btn:SetScript("OnLeave", function(self) self:GetHighlightTexture():Hide() end)
            if item.key == selectedHaloKey then
                btn.text:SetTextColor(1, 0.82, 0, 1)
            else
                btn.text:SetTextColor(1, 1, 1, 1)
            end
        else
            btn:Hide()
        end
    end
end

haloDD:SetScript("OnMouseUp", function()
    if haloDropdownOpen then
        haloDDList:Hide()
        haloDropdownOpen = false
    else
        haloDDList:SetWidth(haloDD:GetWidth())
        haloDDList:SetPoint("TOPLEFT", haloDD, "BOTTOMLEFT", 0, -2)
        haloDDList:Show()
        haloDropdownOpen = true
        RefreshHaloDDList()
    end
end)

haloDDList:EnableMouseWheel(true)
haloDDList:SetScript("OnMouseWheel", function(self, delta)
    local total = #haloList
    if total <= maxVisibleHalo then return end
    if delta < 0 and (scrollOffsetHalo + maxVisibleHalo) < total then
        scrollOffsetHalo = scrollOffsetHalo + 1
        RefreshHaloDDList()
    elseif delta > 0 and scrollOffsetHalo > 0 then
        scrollOffsetHalo = scrollOffsetHalo - 1
        RefreshHaloDDList()
    end
end)

haloDDList:SetScript("OnHide", function()
    haloDropdownOpen = false
end)

local function GlobalHaloDDListHider()
    if haloDropdownOpen and not MouseIsOver(haloDDList) and not MouseIsOver(haloDD) then
        haloDDList:Hide()
    end
end
haloDD:SetScript("OnLeave", function() C_Timer.After(0.1, function() GlobalHaloDDListHider() end) end)
haloDDList:SetScript("OnLeave", function() C_Timer.After(0.1, function() GlobalHaloDDListHider() end) end)

local haloText = content:CreateFontString(nil, "OVERLAY", "GameFontNormal")
haloText:SetPoint("LEFT", haloDD, "RIGHT", 10, 2)
haloText:SetText("Glow Options:")
SetClassColorText(haloText)

local haloScrollLabel = content:CreateFontString(nil, "OVERLAY", "GameFontNormal")
haloScrollLabel:SetPoint("BOTTOM", haloDD, "TOP", 0, 2)
haloScrollLabel:SetText("(Mouse Scroll)")
haloScrollLabel:SetFont("Fonts\\FRIZQT__.TTF", 12, "OUTLINE")
SetClassColorText(haloScrollLabel)

-- Proc Animation Dropdown
local animLabel = CreateLabel(content, "", "TOP", haloDD, 0, -30)
local animList = {
    { key = "SCROLL_H", text = "3D Spin (Horizontal)" },
    { key = "SCROLL_V", text = "3D Spin (Vertical)" },
}
local maxVisibleAnim = 8
local scrollOffsetAnim = 0
local animDropdownOpen = false
local selectedAnimKey = ChayBarDB.animMode or "SCROLL_H"

local animDD = CreateFrame("StatusBar", nil, content, "BackdropTemplate")
animDD:SetPoint("TOP", animLabel, "BOTTOM", 0, -30)
animDD:SetPoint("LEFT", content, "LEFT", MARGIN, 0)
animDD:SetPoint("RIGHT", content, "RIGHT", -MARGIN - 100, 0)
animDD:SetHeight(22)
StyleAsClassBar(animDD)

for _, item in ipairs(animList) do
    if item.key == selectedAnimKey then animDD.text:SetText(item.text); break end
end

local animDDList = CreateFrame("Frame", nil, animDD, BackdropTemplateMixin and "BackdropTemplate")
animDDList:SetSize(animDD:GetWidth(), maxVisibleAnim * 22)
animDDList:SetPoint("TOPLEFT", animDD, "BOTTOMLEFT", 0, -2)
animDDList:SetFrameStrata("DIALOG")
animDDList:SetBackdrop({ bgFile = "Interface/Tooltips/UI-Tooltip-Background", edgeFile = "Interface/Tooltips/UI-Tooltip-Border", tile = true, tileSize = 8, edgeSize = 8, insets = { left = 1, right = 1, top = 1, bottom = 1 } })
animDDList:SetBackdropColor(0, 0, 0, 0.95)
animDDList:Hide()

local animDDButtons = {}
for i = 1, maxVisibleAnim do
    local btn = CreateFrame("Button", nil, animDDList)
    btn:SetHeight(22)
    btn:SetPoint("TOPLEFT", animDDList, "TOPLEFT", 0, -((i - 1) * 22))
    btn:SetPoint("RIGHT", animDDList, "RIGHT", 0, 0)
    btn.text = btn:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    btn.text:SetPoint("LEFT", btn, "LEFT", 8, 0)
    btn.text:SetPoint("RIGHT", btn, "RIGHT", -8, 0)
    btn.text:SetJustifyH("LEFT")
    btn:SetHighlightTexture("Interface/QuestFrame/UI-QuestTitleHighlight")
    btn:EnableMouse(true)
    animDDButtons[i] = btn
end

local function RefreshAnimDDList()
    local total = #animList
    for i = 1, maxVisibleAnim do
        local idx = scrollOffsetAnim + i
        local btn = animDDButtons[i]
        if idx <= total then
            local item = animList[idx]
            btn.text:SetText(item.text)
            btn:Show()
            btn:SetScript("OnClick", function()
                selectedAnimKey = item.key
                ChayBarDB.animMode = item.key
                animDD.text:SetText(item.text)
                isProcActive = false
                ApplyBarSettings()
                UpdateResource()
                animDDList:Hide()
                animDropdownOpen = false
            end)
            btn:SetScript("OnEnter", function(self) self:GetHighlightTexture():Show() end)
            btn:SetScript("OnLeave", function(self) self:GetHighlightTexture():Hide() end)
            if item.key == selectedAnimKey then
                btn.text:SetTextColor(1, 0.82, 0, 1)
            else
                btn.text:SetTextColor(1, 1, 1, 1)
            end
        else
            btn:Hide()
        end
    end
end

animDD:SetScript("OnMouseUp", function()
    if animDropdownOpen then
        animDDList:Hide()
        animDropdownOpen = false
    else
        animDDList:SetWidth(animDD:GetWidth())
        animDDList:SetPoint("TOPLEFT", animDD, "BOTTOMLEFT", 0, -2)
        animDDList:Show()
        animDropdownOpen = true
        RefreshAnimDDList()
    end
end)

animDDList:EnableMouseWheel(true)
animDDList:SetScript("OnMouseWheel", function(self, delta)
    local total = #animList
    if total <= maxVisibleAnim then return end
    if delta < 0 and (scrollOffsetAnim + maxVisibleAnim) < total then
        scrollOffsetAnim = scrollOffsetAnim + 1
        RefreshAnimDDList()
    elseif delta > 0 and scrollOffsetAnim > 0 then
        scrollOffsetAnim = scrollOffsetAnim - 1
        RefreshAnimDDList()
    end
end)

animDDList:SetScript("OnHide", function()
    animDropdownOpen = false
end)

local function GlobalAnimDDListHider()
    if animDropdownOpen and not MouseIsOver(animDDList) and not MouseIsOver(animDD) then
        animDDList:Hide()
    end
end
animDD:SetScript("OnLeave", function() C_Timer.After(0.1, function() GlobalAnimDDListHider() end) end)
animDDList:SetScript("OnLeave", function() C_Timer.After(0.1, function() GlobalAnimDDListHider() end) end)

local animText = content:CreateFontString(nil, "OVERLAY", "GameFontNormal")
animText:SetPoint("LEFT", animDD, "RIGHT", 10, 2)
animText:SetText("Proc Animation:")
SetClassColorText(animText)

local animScrollLabel = content:CreateFontString(nil, "OVERLAY", "GameFontNormal")
animScrollLabel:SetPoint("BOTTOM", animDD, "TOP", 0, 2)
animScrollLabel:SetText("(Mouse Scroll)")
animScrollLabel:SetFont("Fonts\\FRIZQT__.TTF", 12, "OUTLINE")
SetClassColorText(animScrollLabel)

------------------------------------------------------------
-- Bar Texture Dropdown with LIVE PREVIEW
------------------------------------------------------------
local barLabel = CreateLabel(content, "", "TOP", animDD, 0, -30)
local barList = {}
for k, _ in pairs(BARS) do
    table.insert(barList, { key = k, text = k })
end
table.sort(barList, function(a, b) return a.text < b.text end)

local BAR_DD_ROW_HEIGHT = 34
local BAR_DD_PREVIEW_FILL = 0.72
local maxVisible = 8
local scrollOffset = 0
local barDropdownOpen = false
local selectedBarKey = ChayBarDB.barTextureKey or "JiberishBushido1"

local barDD = CreateFrame("StatusBar", nil, content, "BackdropTemplate")
barDD:SetPoint("TOP", barLabel, "BOTTOM", 0, -30)
barDD:SetPoint("LEFT", content, "LEFT", MARGIN, 0)
barDD:SetPoint("RIGHT", content, "RIGHT", -MARGIN - 100, 0)
barDD:SetHeight(22)
StyleAsClassBar(barDD)

for _, item in ipairs(barList) do
    if item.key == selectedBarKey then
        barDD.text:SetText(item.text)
        break
    end
end

local barDDList = CreateFrame("Frame", nil, barDD, BackdropTemplateMixin and "BackdropTemplate")
barDDList:SetSize(barDD:GetWidth(), maxVisible * BAR_DD_ROW_HEIGHT)
barDDList:SetPoint("TOPLEFT", barDD, "BOTTOMLEFT", 0, -2)
barDDList:SetFrameStrata("DIALOG")
barDDList:SetBackdrop({
    bgFile = "Interface/Tooltips/UI-Tooltip-Background",
    edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
    tile = true,
    tileSize = 8,
    edgeSize = 8,
    insets = { left = 1, right = 1, top = 1, bottom = 1 }
})
barDDList:SetBackdropColor(0, 0, 0, 0.95)
barDDList:Hide()

local barDDButtons = {}
for i = 1, maxVisible do
    local btn = CreateFrame("Button", nil, barDDList)
    btn:SetHeight(BAR_DD_ROW_HEIGHT)
    btn:SetPoint("TOPLEFT", barDDList, "TOPLEFT", 0, -((i - 1) * BAR_DD_ROW_HEIGHT))
    btn:SetPoint("RIGHT", barDDList, "RIGHT", 0, 0)
    btn:EnableMouse(true)
    btn:SetHighlightTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")

    btn.text = btn:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    btn.text:SetPoint("LEFT", btn, "LEFT", 8, 0)
    btn.text:SetWidth(150)
    btn.text:SetJustifyH("LEFT")

    btn.previewBorder = CreateFrame("Frame", nil, btn, "BackdropTemplate")
    btn.previewBorder:SetPoint("RIGHT", btn, "RIGHT", -10, 0)
    btn.previewBorder:SetSize(170, 16)
    btn.previewBorder:SetBackdrop({
        bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
        edgeFile = "Interface\\Buttons\\WHITE8x8",
        tile = false,
        tileSize = 0,
        edgeSize = 1,
        insets = { left = 1, right = 1, top = 1, bottom = 1 }
    })
    btn.previewBorder:SetBackdropColor(0, 0, 0, 0.75)
    btn.previewBorder:SetBackdropBorderColor(0.20, 0.20, 0.20, 1)

    btn.previewBG = btn.previewBorder:CreateTexture(nil, "BACKGROUND")
    btn.previewBG:SetAllPoints()
    btn.previewBG:SetTexCoord(0, 1, 0, 1)

    btn.preview = CreateFrame("StatusBar", nil, btn.previewBorder)
    btn.preview:SetAllPoints()
    btn.preview:SetMinMaxValues(0, 1)
    btn.preview:SetValue(BAR_DD_PREVIEW_FILL)

    btn.previewFillTex = btn.preview:CreateTexture(nil, "ARTWORK")
    btn.previewFillTex:SetAllPoints()
    btn.preview:SetStatusBarTexture(btn.previewFillTex)

    barDDButtons[i] = btn
end

RefreshBarDDList = function()
    local total = #barList
    local fg = ChayBarDB.foregroundColor or { 0.65, 0.15, 0.85, 1 }
    local bgc = ChayBarDB.backgroundColor or { 0.08, 0.08, 0.08, 0.9 }
    local previewHeight = math.max(8, math.min(20, tonumber(ChayBarDB.height) or 18))

    barDDList:SetHeight(maxVisible * BAR_DD_ROW_HEIGHT)

    for i = 1, maxVisible do
        local idx = scrollOffset + i
        local btn = barDDButtons[i]

        if idx <= total then
            local item = barList[idx]
            local texPath = BARS[item.key] or BARS["JiberishBushido1"] or "Interface\\TargetingFrame\\UI-StatusBar"

            btn.text:SetText(item.text)
            btn:Show()

            btn.previewBorder:SetHeight(previewHeight)
            btn.previewBorder:ClearAllPoints()
            btn.previewBorder:SetPoint("RIGHT", btn, "RIGHT", -10, 0)
            btn.previewBorder:SetWidth(170)

            btn.previewBG:SetTexture(texPath)
            btn.previewBG:SetVertexColor(bgc[1] or 0.08, bgc[2] or 0.08, bgc[3] or 0.08, bgc[4] or 0.9)

            btn.preview:SetStatusBarTexture(texPath)
            btn.preview:SetStatusBarColor(fg[1] or 0.65, fg[2] or 0.15, fg[3] or 0.85, fg[4] or 1)
            btn.preview:SetReverseFill(ChayBarDB.reverse and true or false)
            btn.preview:SetMinMaxValues(0, 1)
            btn.preview:SetValue(BAR_DD_PREVIEW_FILL)

            btn:SetScript("OnClick", function()
                selectedBarKey = item.key
                ChayBarDB.barTextureKey = item.key
                barDD.text:SetText(item.text)
                ApplyBarSettings()
                UpdateResource()
                barDDList:Hide()
                barDropdownOpen = false
            end)

            btn:SetScript("OnEnter", function(self)
                local hl = self:GetHighlightTexture()
                if hl then hl:Show() end
            end)

            btn:SetScript("OnLeave", function(self)
                local hl = self:GetHighlightTexture()
                if hl then hl:Hide() end
            end)

            if item.key == selectedBarKey then
                btn.text:SetTextColor(1, 0.82, 0, 1)
                btn.previewBorder:SetBackdropBorderColor(1, 0.82, 0, 1)
            else
                btn.text:SetTextColor(1, 1, 1, 1)
                btn.previewBorder:SetBackdropBorderColor(0.20, 0.20, 0.20, 1)
            end
        else
            btn:Hide()
        end
    end
end

barDD:SetScript("OnMouseUp", function()
    if barDropdownOpen then
        barDDList:Hide()
        barDropdownOpen = false
    else
        barDDList:SetWidth(barDD:GetWidth())
        barDDList:SetPoint("TOPLEFT", barDD, "BOTTOMLEFT", 0, -2)
        barDDList:Show()
        barDropdownOpen = true
        RefreshBarDDList()
    end
end)

barDDList:EnableMouseWheel(true)
barDDList:SetScript("OnMouseWheel", function(self, delta)
    local total = #barList
    if total <= maxVisible then return end
    if delta < 0 and (scrollOffset + maxVisible) < total then
        scrollOffset = scrollOffset + 1
        RefreshBarDDList()
    elseif delta > 0 and scrollOffset > 0 then
        scrollOffset = scrollOffset - 1
        RefreshBarDDList()
    end
end)

barDDList:SetScript("OnHide", function()
    barDropdownOpen = false
end)

local function GlobalBarDDListHider()
    if barDropdownOpen and not MouseIsOver(barDDList) and not MouseIsOver(barDD) then
        barDDList:Hide()
    end
end
barDD:SetScript("OnLeave", function() C_Timer.After(0.1, function() GlobalBarDDListHider() end) end)
barDDList:SetScript("OnLeave", function() C_Timer.After(0.1, function() GlobalBarDDListHider() end) end)

local barText = content:CreateFontString(nil, "OVERLAY", "GameFontNormal")
barText:SetPoint("LEFT", barDD, "RIGHT", 10, 2)
barText:SetText("Bar Texture:")
SetClassColorText(barText)

local barScrollLabel = content:CreateFontString(nil, "OVERLAY", "GameFontNormal")
barScrollLabel:SetPoint("BOTTOM", barDD, "TOP", 0, 2)
barScrollLabel:SetText("(Mouse Scroll)")
barScrollLabel:SetFont("Fonts\\FRIZQT__.TTF", 12, "OUTLINE")
SetClassColorText(barScrollLabel)

-- Sliders
local scaleSlider = CreateFrame("Slider", nil, content, "OptionsSliderTemplate")
scaleSlider:SetPoint("TOP", barDD, "BOTTOM", 0, -40)
scaleSlider:SetPoint("LEFT", content, "LEFT", MARGIN, 0)
scaleSlider:SetPoint("RIGHT", content, "RIGHT", -MARGIN, 0)
scaleSlider:SetHeight(16)
scaleSlider:SetMinMaxValues(0.5, 1.5)
scaleSlider:SetValueStep(0.05)
scaleSlider:SetValue(ChayBarDB.scale)
scaleSlider.Text:SetText("Scale")
scaleSlider:SetScript("OnValueChanged", function(_, v)
    ChayBarDB.scale = v
    isProcActive = false
    ApplyBarSettings()
    RefreshBarDDList()
    UpdateResource()
end)

local widthSlider = CreateFrame("Slider", nil, content, "OptionsSliderTemplate")
widthSlider:SetPoint("TOP", scaleSlider, "BOTTOM", 0, -26)
widthSlider:SetPoint("LEFT", content, "LEFT", MARGIN, 0)
widthSlider:SetPoint("RIGHT", content, "RIGHT", -MARGIN, 0)
widthSlider:SetHeight(16)
widthSlider:SetMinMaxValues(120, 600)
widthSlider:SetValueStep(1)
widthSlider:SetValue(ChayBarDB.width)
widthSlider.Text:SetText("Width")
widthSlider:SetScript("OnValueChanged", function(_, v)
    ChayBarDB.width = v
    isProcActive = false
    ApplyBarSettings()
    RefreshBarDDList()
    UpdateResource()
end)

local heightSlider = CreateFrame("Slider", nil, content, "OptionsSliderTemplate")
heightSlider:SetPoint("TOP", widthSlider, "BOTTOM", 0, -26)
heightSlider:SetPoint("LEFT", content, "LEFT", MARGIN, 0)
heightSlider:SetPoint("RIGHT", content, "RIGHT", -MARGIN, 0)
heightSlider:SetHeight(16)
heightSlider:SetMinMaxValues(8, 40)
heightSlider:SetValueStep(1)
heightSlider:SetValue(ChayBarDB.height)
heightSlider.Text:SetText("Height")
heightSlider:SetScript("OnValueChanged", function(_, v)
    ChayBarDB.height = v
    isProcActive = false
    ApplyBarSettings()
    RefreshBarDDList()
    UpdateResource()
end)

local glowScaleSlider = CreateFrame("Slider", nil, content, "OptionsSliderTemplate")
glowScaleSlider:SetPoint("TOP", heightSlider, "BOTTOM", 0, -26)
glowScaleSlider:SetPoint("LEFT", content, "LEFT", MARGIN, 0)
glowScaleSlider:SetPoint("RIGHT", content, "RIGHT", -MARGIN, 0)
glowScaleSlider:SetHeight(16)
glowScaleSlider:SetMinMaxValues(0.5, 4.0)
glowScaleSlider:SetValueStep(0.05)
glowScaleSlider:SetValue(ChayBarDB.glowScale)
glowScaleSlider.Text:SetText("Proc Glow Size")
glowScaleSlider:SetScript("OnValueChanged", function(_, v)
    ChayBarDB.glowScale = v
    isProcActive = false
    ApplyBarSettings()
    UpdateResource()
end)

local glowSpeedSlider = CreateFrame("Slider", nil, content, "OptionsSliderTemplate")
glowSpeedSlider:SetPoint("TOP", glowScaleSlider, "BOTTOM", 0, -26)
glowSpeedSlider:SetPoint("LEFT", content, "LEFT", MARGIN, 0)
glowSpeedSlider:SetPoint("RIGHT", content, "RIGHT", -MARGIN, 0)
glowSpeedSlider:SetHeight(16)
glowSpeedSlider:SetMinMaxValues(0.10, 3.00)
glowSpeedSlider:SetValueStep(0.05)
glowSpeedSlider:SetValue(ChayBarDB.glowSpeed)
glowSpeedSlider.Text:SetText("Proc Speed")
glowSpeedSlider:SetScript("OnValueChanged", function(_, v)
    ChayBarDB.glowSpeed = v
    isProcActive = false
    ApplyBarSettings()
    UpdateResource()
end)

local glowOffsetYSlider = CreateFrame("Slider", nil, content, "OptionsSliderTemplate")
glowOffsetYSlider:SetPoint("TOP", glowSpeedSlider, "BOTTOM", 0, -26)
glowOffsetYSlider:SetPoint("LEFT", content, "LEFT", MARGIN, 0)
glowOffsetYSlider:SetPoint("RIGHT", content, "RIGHT", -MARGIN, 0)
glowOffsetYSlider:SetHeight(16)
glowOffsetYSlider:SetMinMaxValues(-60, 60)
glowOffsetYSlider:SetValueStep(1)
glowOffsetYSlider:SetValue(ChayBarDB.glowOffsetY)
glowOffsetYSlider.Text:SetText("Proc Offset Y (Vertical): " .. (ChayBarDB.glowOffsetY or 0))
glowOffsetYSlider:SetScript("OnValueChanged", function(_, v)
    local val = math.floor(v)
    ChayBarDB.glowOffsetY = val
    glowOffsetYSlider.Text:SetText("Proc Offset Y (Vertical): " .. val)
    isProcActive = false
    ApplyBarSettings()
    UpdateResource()
end)

local glowOffsetXSlider = CreateFrame("Slider", nil, content, "OptionsSliderTemplate")
glowOffsetXSlider:SetPoint("TOP", glowOffsetYSlider, "BOTTOM", 0, -26)
glowOffsetXSlider:SetPoint("LEFT", content, "LEFT", MARGIN, 0)
glowOffsetXSlider:SetPoint("RIGHT", content, "RIGHT", -MARGIN, 0)
glowOffsetXSlider:SetHeight(16)
glowOffsetXSlider:SetMinMaxValues(-60, 60)
glowOffsetXSlider:SetValueStep(1)
glowOffsetXSlider:SetValue(ChayBarDB.glowOffsetX)
glowOffsetXSlider.Text:SetText("Proc Offset X (Horizontal): " .. (ChayBarDB.glowOffsetX or 0))
glowOffsetXSlider:SetScript("OnValueChanged", function(_, v)
    local val = math.floor(v)
    ChayBarDB.glowOffsetX = val
    glowOffsetXSlider.Text:SetText("Proc Offset X (Horizontal): " .. val)
    isProcActive = false
    ApplyBarSettings()
    UpdateResource()
end)

local glowAlphaSlider = CreateFrame("Slider", nil, content, "OptionsSliderTemplate")
glowAlphaSlider:SetPoint("TOP", glowOffsetXSlider, "BOTTOM", 0, -26)
glowAlphaSlider:SetPoint("LEFT", content, "LEFT", MARGIN, 0)
glowAlphaSlider:SetPoint("RIGHT", content, "RIGHT", -MARGIN, 0)
glowAlphaSlider:SetHeight(16)
glowAlphaSlider:SetMinMaxValues(0, 3)
glowAlphaSlider:SetValueStep(0.1)
glowAlphaSlider:SetValue(ChayBarDB.GlowIntensity)
glowAlphaSlider.Text:SetText("Glow Intensity: " .. math.floor((ChayBarDB.GlowIntensity or 1) * 100) .. "%")
glowAlphaSlider:SetScript("OnValueChanged", function(_, v)
    ChayBarDB.GlowIntensity = v
    glowAlphaSlider.Text:SetText("Glow Intensity: " .. math.floor(v * 100) .. "%")
    isProcActive = false
    ApplyBarSettings()
    UpdateResource()
end)

local paladinProcBtn = CreateFrame("StatusBar", nil, content, "BackdropTemplate")
paladinProcBtn:SetSize(220, 32)
paladinProcBtn:SetPoint("TOP", glowAlphaSlider, "BOTTOM", 0, -24)
StyleAsClassBar(paladinProcBtn)

local function RefreshPaladinProcButtonText()
    paladinProcBtn.text:SetText("Paladin Proc: " .. GetPaladinProcThreshold() .. " Holy Power")
end

paladinProcBtn:SetScript("OnMouseUp", function()
    ChayBarDB.paladinProcThreshold = (GetPaladinProcThreshold() == 3) and 5 or 3
    isProcActive = false
    RefreshPaladinProcButtonText()
    UpdateResource()
end)
RefreshPaladinProcButtonText()

-- Bottom buttons
local BOTTOM_BTN_HEIGHT = 36
local BOTTOM_BTN_WIDTH = 132
local BOTTOM_BTN_SPACING = 12
local totalWidth = (BOTTOM_BTN_WIDTH * 4) + (BOTTOM_BTN_SPACING * 3)
local parentWidth = content:GetWidth() or 900
local startX = (parentWidth - totalWidth) / 2

local testBtn = CreateFrame("StatusBar", nil, content, "BackdropTemplate")
testBtn:EnableMouse(true)
testBtn:SetFrameLevel(content:GetFrameLevel() + 25)
testBtn:SetSize(BOTTOM_BTN_WIDTH, BOTTOM_BTN_HEIGHT)
testBtn:SetPoint("TOPLEFT", content, "TOPLEFT", startX, glowAlphaSlider:GetBottom() - content:GetTop() - 76)
StyleAsClassBar(testBtn)
testBtn.text:SetText("Test Proc")
testBtn:SetScript("OnMouseUp", function()
    isTesting = not isTesting
    if isTesting then
        testBtn.text:SetText("Stop Test")
    else
        testBtn.text:SetText("Test Proc")
    end
    UpdateResource()
end)

local offBtn = CreateFrame("StatusBar", nil, content, "BackdropTemplate")
offBtn:EnableMouse(true)
offBtn:SetFrameLevel(content:GetFrameLevel() + 25)
offBtn:SetSize(BOTTOM_BTN_WIDTH, BOTTOM_BTN_HEIGHT)
offBtn:SetPoint("LEFT", testBtn, "RIGHT", BOTTOM_BTN_SPACING, 0)
StyleAsClassBar(offBtn)

local function RefreshOffButtonText()
    if ChayBarDB.enabled then
        offBtn.text:SetText("Bar: ON")
    else
        offBtn.text:SetText("Bar: OFF")
    end
end

offBtn:SetScript("OnMouseUp", function()
    ChayBarDB.enabled = not ChayBarDB.enabled
    if not ChayBarDB.enabled then
        isTesting = false
        testBtn.text:SetText("Test Proc")
    end
    isProcActive = false
    RefreshOffButtonText()
    ApplyBarSettings()
    UpdateResource()
end)
RefreshOffButtonText()

local closeBtn = CreateFrame("StatusBar", nil, content, "BackdropTemplate")
closeBtn:EnableMouse(true)
closeBtn:SetFrameLevel(content:GetFrameLevel() + 25)
closeBtn:SetSize(BOTTOM_BTN_WIDTH, BOTTOM_BTN_HEIGHT)
closeBtn:SetPoint("LEFT", offBtn, "RIGHT", BOTTOM_BTN_SPACING, 0)
StyleAsClassBar(closeBtn)
closeBtn.text:SetText("Close")
closeBtn:SetScript("OnMouseUp", function() cfg:Hide() end)

local lockBtn = CreateFrame("StatusBar", nil, content, "BackdropTemplate")
lockBtn:EnableMouse(true)
lockBtn:SetFrameLevel(content:GetFrameLevel() + 25)
lockBtn:SetSize(BOTTOM_BTN_WIDTH, BOTTOM_BTN_HEIGHT)
lockBtn:SetPoint("LEFT", closeBtn, "RIGHT", BOTTOM_BTN_SPACING, 0)
StyleAsClassBar(lockBtn)
lockBtn.text:SetText("Lock Bar")
lockBtn:SetScript("OnMouseUp", function()
    ChayBarDB.locked = not ChayBarDB.locked
    if ChayBarDB.locked then
        lockBtn.text:SetText("Unlock Bar")
    else
        lockBtn.text:SetText("Lock Bar")
    end
    UpdateLockState()
    print("|cff00ff00ChayBar:|r Bar & Window are now " .. (ChayBarDB.locked and "LOCKED" or "UNLOCKED"))
end)

------------------------------------------------------------
-- Minimap Helper
------------------------------------------------------------
local function PlaceMinimapButton(btn, angle)
    if not Minimap then return end
    local r = 78
    local rad = math.rad(angle)
    btn:SetPoint("CENTER", Minimap, "CENTER", math.cos(rad) * r, math.sin(rad) * r)
end

local function CreateMinimapButton()
    if minimapButton then return end
    minimapButton = CreateFrame("Button", "ChayBar_MinimapButton", Minimap)
    minimapButton:SetSize(32, 32)
    minimapButton:RegisterForClicks("LeftButtonUp", "RightButtonUp")
    minimapButton:RegisterForDrag("LeftButton")
    minimapButton:EnableMouse(true)
    minimapButton:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight", "ADD")

    local icon = minimapButton:CreateTexture(nil, "ARTWORK")
    icon:SetAllPoints(minimapButton)
    icon:SetTexture("Interface\\AddOns\\ChayBar\\Media\\Icons\\MinimapIcon.tga")

    minimapButton:SetFrameStrata("HIGH")
    minimapButton:SetFrameLevel(10)

    minimapButton:SetScript("OnClick", function(_, btn)
        if btn == "LeftButton" then
            cfg:SetShown(not cfg:IsShown())
        elseif btn == "RightButton" then
            ChayBarDB.locked = not ChayBarDB.locked
            UpdateLockState()
        end
    end)

    minimapButton:SetScript("OnDragStart", function() minimapButton.dragging = true end)
    minimapButton:SetScript("OnDragStop", function() minimapButton.dragging = false end)
    minimapButton:SetScript("OnUpdate", function()
        if not minimapButton.dragging then return end
        if not Minimap then return end
        local cx, cy = Minimap:GetCenter()
        local mx, my = GetCursorPosition()
        local s = Minimap:GetEffectiveScale()
        local angle = math.deg(math.atan2(my / s - cy, mx / s - cx))
        ChayBarDB.minimapAngle = angle
        PlaceMinimapButton(minimapButton, angle)
    end)

    PlaceMinimapButton(minimapButton, ChayBarDB.minimapAngle)
    minimapButton:Show()
end

local function CreateBar()
    if bar then return end
    if not classData then return end

    print("|cff00ff00ChayBar:|r Loaded for " .. playerClass)

    bar = CreateFrame("StatusBar", "ChayBar_ShardBar", UIParent)
    local _, maxPower = GetActiveResource()
    bar:SetMinMaxValues(0, maxPower)

    local barTex = BARS[ChayBarDB.barTextureKey] or BARS["JiberishBushido1"] or "Interface\\TargetingFrame\\UI-StatusBar"
    bar:SetStatusBarTexture(barTex)
    bar:SetClipsChildren(false)
    bar:SetFrameStrata("LOW")

    if type(ChayBarDB.point) ~= "table" or #ChayBarDB.point < 4 or
       type(ChayBarDB.point[1]) ~= "string" or type(ChayBarDB.point[2]) ~= "string" then
        ChayBarDB.point = { "CENTER", "CENTER", 0, -220 }
    end

    bar:SetPoint(ChayBarDB.point[1], UIParent, ChayBarDB.point[2], ChayBarDB.point[3], ChayBarDB.point[4])
    bar:SetMovable(true)
    bar:EnableMouse(true)
    bar:RegisterForDrag("LeftButton")

    bg = bar:CreateTexture(nil, "BACKGROUND")
    bg:SetTexture(barTex)
    bg:SetAllPoints()

    text = bar:CreateFontString(nil, "OVERLAY")
    text:SetPoint("CENTER")
    text:SetFont("Fonts\\FRIZQT__.TTF", (tonumber(ChayBarDB.fontSize) or 14) + 12, "OUTLINE")
    text:SetTextColor(1, 1, 1, 1)

    procParent = CreateFrame("Frame", nil, UIParent)
    procParent:SetPoint("CENTER", bar, "CENTER", ChayBarDB.glowOffsetX or 0, ChayBarDB.glowOffsetY or 0)
    procParent:Hide()

    frameBack = CreateFrame("Frame", nil, procParent)
    frameBack:SetFrameStrata("BACKGROUND")
    frameBack:SetAllPoints(procParent)
    texBack = frameBack:CreateTexture(nil, "ARTWORK")
    texBack:SetAllPoints(frameBack)
    texBack:SetBlendMode("ADD")

    frameFront = CreateFrame("Frame", nil, procParent)
    frameFront:SetFrameStrata("DIALOG")
    frameFront:SetAllPoints(procParent)
    texFront = frameFront:CreateTexture(nil, "ARTWORK")
    texFront:SetAllPoints(frameFront)
    texFront:SetBlendMode("ADD")

    bar:SetScript("OnDragStart", function(self)
        if not ChayBarDB.locked and ChayBarDB.enabled then
            self:StartMoving()
        end
    end)

    bar:SetScript("OnDragStop", function(self)
        self:StopMovingOrSizing()
        local p, _, rp, x, y = self:GetPoint()
        ChayBarDB.point = { p, rp, x, y }
        if procParent then
            procParent:ClearAllPoints()
            procParent:SetPoint("CENTER", bar, "CENTER", ChayBarDB.glowOffsetX or 0, ChayBarDB.glowOffsetY or 0)
        end
    end)

    ApplyBarSettings()

    if ChayBarDB.enabled then
        bar:Show()
    else
        bar:Hide()
    end

    UpdateResource()
end

local function InitAddon()
    local _, pClass = UnitClass("player")
    if not pClass then return end
    playerClass = pClass
    classData = CLASS_CONFIG[playerClass]
    if not classData and pClass == "DEMONHUNTER" then
        classData = { power = Enum.PowerType.Fury, name = "Fury" }
    end
    if not classData then return end
    RefreshClassTheme()
    CreateBar()

    if ChayBarDB.enabled and bar then
        bar:Show()
    end

    C_Timer.After(0, function()
        if bar and ChayBarDB.enabled then
            UpdateResource()
        end
    end)

    C_Timer.After(0.1, function()
        if bar and ChayBarDB.enabled then
            UpdateResource()
        end
    end)
end

local ev = CreateFrame("Frame")
ev:RegisterEvent("PLAYER_LOGIN")
ev:RegisterEvent("PLAYER_ENTERING_WORLD")
ev:RegisterEvent("PLAYER_TARGET_CHANGED")
ev:RegisterUnitEvent("UNIT_POWER_UPDATE", "player")
ev:RegisterUnitEvent("UNIT_POWER_FREQUENT", "player")
ev:RegisterEvent("PLAYER_TALENT_UPDATE")
ev:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED")
ev:RegisterEvent("PLAYER_REGEN_DISABLED")
ev:RegisterEvent("PLAYER_REGEN_ENABLED")

ev:SetScript("OnEvent", function(_, event, unit, powerType)
    if event == "PLAYER_LOGIN" then
        CreateMinimapButton()
    end
    if event == "PLAYER_ENTERING_WORLD" then
        InitAddon()
    end
    if not bar then return end

    if event == "PLAYER_TALENT_UPDATE" or event == "PLAYER_SPECIALIZATION_CHANGED" then
        UpdateResource()
        return
    end
    if event == "PLAYER_TARGET_CHANGED" then
        if CheckSpecValidity() then UpdateResource() end
        return
    end
    if event == "PLAYER_REGEN_DISABLED" or event == "PLAYER_REGEN_ENABLED" then
        if CheckSpecValidity() then UpdateResource() end
        return
    end

    if unit == "player" then
        if CheckSpecValidity() then UpdateResource() end
    end
end)

SLASH_CHAYBAR1 = "/chaybar"
SLASH_CHAYBAR2 = "/cb"
SlashCmdList.CHAYBAR = function(msg)
    msg = (msg or ""):lower()

    if msg == "lock" then
        ChayBarDB.locked = not ChayBarDB.locked
        UpdateLockState()
        print("|cff00ff00ChayBar:|r Bar is now " .. (ChayBarDB.locked and "LOCKED" or "UNLOCKED"))

    elseif msg == "reset" and bar then
        bar:ClearAllPoints()
        bar:SetPoint("CENTER", UIParent, "CENTER", 0, -220)
        ChayBarDB.point = { "CENTER", "CENTER", 0, -220 }
        if procParent then
            procParent:ClearAllPoints()
            procParent:SetPoint("CENTER", bar, "CENTER", ChayBarDB.glowOffsetX or 0, ChayBarDB.glowOffsetY or 0)
        end
        print("|cff00ff00ChayBar:|r Position reset.")

    elseif msg == "test" then
        isTesting = not isTesting
        print("|cff00ff00ChayBar:|r Test mode " .. (isTesting and "enabled" or "disabled"))
        UpdateResource()

    elseif msg == "off" then
        ChayBarDB.enabled = false
        isTesting = false
        isProcActive = false
        if offBtn and offBtn.text then RefreshOffButtonText() end
        ApplyBarSettings()
        UpdateResource()
        print("|cff00ff00ChayBar:|r Bar disabled.")

    elseif msg == "on" then
        ChayBarDB.enabled = true
        isProcActive = false
        if offBtn and offBtn.text then RefreshOffButtonText() end
        ApplyBarSettings()
        if bar then bar:Show() end
        RefreshBarDDList()
        UpdateResource()
        print("|cff00ff00ChayBar:|r Bar enabled.")

    else
        cfg:SetShown(not cfg:IsShown())
        UpdateLockState()
        RefreshBarDDList()
        if offBtn and offBtn.text then RefreshOffButtonText() end
    end
end