local addonName, MSUF = ...
MSUF = MSUF or _G.MSUF_NS or {}

local M = MSUF.MSUF2 or _G.MSUF2 or {}
MSUF.MSUF2 = M

local A = MSUF.Assistant or {}
MSUF.Assistant = A
M.Assistant = A

-- Global color, scale, and tooltip assistant setting domain.
-- Depends on MSUF_AssistantRegistry_Global.lua for shared registry helpers.
local ctx = A.GlobalRegistry and A.GlobalRegistry.ColorSettings
if type(ctx) ~= "table" then return end

local Registry = ctx.Registry
M = ctx.M or M
MSUF = ctx.MSUF or MSUF
local EnsureDB = ctx.EnsureDB
local GeneralDB = ctx.GeneralDB
local BarsDB = ctx.BarsDB
local GameplayDB = ctx.GameplayDB
local ClampNumber = ctx.ClampNumber
local CallGlobal = ctx.CallGlobal
local ApplyGeneral = ctx.ApplyGeneral
local ApplyVisuals = ctx.ApplyVisuals
local ApplyColors = ctx.ApplyColors
local ApplyCastbarColors = ctx.ApplyCastbarColors
local ApplyGameplayColors = ctx.ApplyGameplayColors
local ApplyClassPowerColors = ctx.ApplyClassPowerColors
local ApplyAuraColors = ctx.ApplyAuraColors
local ApplyPortraitColors = ctx.ApplyPortraitColors
local ApplyBarOutline = ctx.ApplyBarOutline
local RegisterGeneralBoolean = ctx.RegisterGeneralBoolean
local RegisterGeneralNumberSetting = ctx.RegisterGeneralNumberSetting
local RegisterGeneralEnum = ctx.RegisterGeneralEnum
local RegisterGameplayBoolean = ctx.RegisterGameplayBoolean
local GLOBAL_SCOPE_ORDER = ctx.GLOBAL_SCOPE_ORDER or {}
local NormalizeGlobalScope = ctx.NormalizeGlobalScope
local GlobalScopeLabel = ctx.GlobalScopeLabel
local GlobalScopeRead = ctx.GlobalScopeRead
local GlobalScopeWrite = ctx.GlobalScopeWrite
local GlobalScopeAliases = ctx.GlobalScopeAliases

if not (Registry and type(Registry.RegisterSetting) == "function" and type(Registry.RegisterAction) == "function") then return end
if type(GeneralDB) ~= "function" or type(EnsureDB) ~= "function" then return end
if type(ClampNumber) ~= "function" or type(RegisterGeneralBoolean) ~= "function" then return end

do
local COLOR_ALIASES = {
    gray = "grey",
    violet = "purple",
    aqua = "cyan",
    teal = "turquoise",
    weiss = "white",
    schwarz = "black",
    rot = "red",
    gruen = "green",
    blau = "blue",
    gelb = "yellow",
    lila = "purple",
    rosa = "pink",
    tuerkis = "turquoise",
}

local FALLBACK_COLORS = {
    white = { 1, 1, 1 },
    black = { 0, 0, 0 },
    red = { 1, 0, 0 },
    green = { 0, 1, 0 },
    blue = { 0, 0, 1 },
    yellow = { 1, 1, 0 },
    cyan = { 0, 1, 1 },
    magenta = { 1, 0, 1 },
    orange = { 1, 0.5, 0 },
    purple = { 0.6, 0, 0.8 },
    pink = { 1, 0.6, 0.8 },
    turquoise = { 0, 0.9, 0.8 },
    grey = { 0.5, 0.5, 0.5 },
    brown = { 0.6, 0.3, 0.1 },
    gold = { 1, 0.85, 0.1 },
}

local function Clamp01(value)
    value = tonumber(value) or 0
    if value < 0 then return 0 end
    if value > 1 then return 1 end
    return value
end

local function ColorFromName(name)
    name = tostring(name or ""):lower()
    name = COLOR_ALIASES[name] or name
    local palette = (MSUF and MSUF.MSUF_FONT_COLORS) or _G.MSUF_FONT_COLORS or FALLBACK_COLORS
    local color = palette and palette[name]
    if type(color) == "table" then
        return Clamp01(color[1] or color.r or 1), Clamp01(color[2] or color.g or 1), Clamp01(color[3] or color.b or 1), name
    end
    color = FALLBACK_COLORS[name]
    if type(color) == "table" then return color[1], color[2], color[3], name end
    return nil
end
A.ColorFromName = A.ColorFromName or ColorFromName

local function HexToColor(hex)
    hex = tostring(hex or ""):match("^#?(%x%x%x%x%x%x)$")
    if not hex then return nil end
    local r = tonumber(hex:sub(1, 2), 16) or 255
    local g = tonumber(hex:sub(3, 4), 16) or 255
    local b = tonumber(hex:sub(5, 6), 16) or 255
    return r / 255, g / 255, b / 255, "#" .. hex:upper()
end
A.HexToColor = A.HexToColor or HexToColor

local function ColorAPI()
    return (MSUF and MSUF._colorsAPI) or {}
end

local function ColorValue(r, g, b, label)
    return {
        r = Clamp01(r),
        g = Clamp01(g),
        b = Clamp01(b),
        label = label,
    }
end

local function ColorComponents(value, dr, dg, db)
    if type(value) == "table" then
        return Clamp01(value.r or value[1] or dr), Clamp01(value.g or value[2] or dg), Clamp01(value.b or value[3] or db)
    end
    if type(value) == "string" then
        local r, g, b = ColorFromName(value)
        if r then return r, g, b end
    end
    return Clamp01(dr), Clamp01(dg), Clamp01(db)
end

local function ColorSame(a, b)
    if type(a) ~= "table" or type(b) ~= "table" then return a == b end
    local ar, ag, ab = ColorComponents(a, 0, 0, 0)
    local br, bg, bb = ColorComponents(b, 0, 0, 0)
    return math.abs(ar - br) < 0.0005 and math.abs(ag - bg) < 0.0005 and math.abs(ab - bb) < 0.0005
end

local function ColorSetting(key, label, aliases, getRGB, setRGB, opts)
    opts = opts or {}
    Registry:RegisterSetting({
        key = key,
        label = label,
        category = opts.category or "Colors",
        unit = opts.unit or "global",
        frameType = opts.frameType or "colors",
        attribute = opts.attribute or key,
        type = "color",
        aliases = aliases,
        exactAliases = opts.exactAliases,
        get = function()
            local r, g, b, colorLabel = getRGB()
            return ColorValue(r, g, b, colorLabel)
        end,
        set = function(value)
            local r, g, b = ColorComponents(value, opts.defaultR or 1, opts.defaultG or 1, opts.defaultB or 1)
            setRGB(r, g, b, value)
        end,
        sameValue = ColorSame,
        apply = opts.apply or ApplyColors,
        combatSafe = opts.combatSafe == true,
    })
end

local function ApiRGB(getName, dr, dg, db, fallback)
    local fn = ColorAPI()[getName]
    if type(fn) == "function" then
        local r, g, b = fn()
        if type(r) == "number" and type(g) == "number" and type(b) == "number" then return r, g, b end
    end
    if type(fallback) == "function" then
        local r, g, b = fallback()
        if type(r) == "number" and type(g) == "number" and type(b) == "number" then return r, g, b end
    end
    return dr, dg, db
end

local function ApiSetRGB(setName, r, g, b, alpha)
    local fn = ColorAPI()[setName]
    if type(fn) == "function" then
        if alpha ~= nil then fn(r, g, b, alpha) else fn(r, g, b) end
        return true
    end
    return false
end

local function GeneralRGB(prefix, dr, dg, db)
    local g = GeneralDB()
    return tonumber(g[prefix .. "R"]) or dr, tonumber(g[prefix .. "G"]) or dg, tonumber(g[prefix .. "B"]) or db
end

local function SetGeneralRGB(prefix, r, gCol, b)
    local g = GeneralDB()
    g[prefix .. "R"], g[prefix .. "G"], g[prefix .. "B"] = r, gCol, b
end

local function GeneralRGBAlias(primaryPrefix, legacyPrefix, dr, dg, db)
    local g = GeneralDB()
    return tonumber(g[primaryPrefix .. "R"]) or tonumber(g[legacyPrefix .. "R"]) or dr,
        tonumber(g[primaryPrefix .. "G"]) or tonumber(g[legacyPrefix .. "G"]) or dg,
        tonumber(g[primaryPrefix .. "B"]) or tonumber(g[legacyPrefix .. "B"]) or db
end

local function SetGeneralRGBAlias(primaryPrefix, legacyPrefix, r, gCol, b)
    local g = GeneralDB()
    g[primaryPrefix .. "R"], g[primaryPrefix .. "G"], g[primaryPrefix .. "B"] = r, gCol, b
    g[legacyPrefix .. "R"], g[legacyPrefix .. "G"], g[legacyPrefix .. "B"] = r, gCol, b
end

local function TableRGB(tbl, key, dr, dg, db)
    local t = tbl and tbl[key]
    if type(t) == "table" then
        local r = tonumber(t.r or t[1] or t["1"])
        local g = tonumber(t.g or t[2] or t["2"])
        local b = tonumber(t.b or t[3] or t["3"])
        if r and g and b then return r, g, b end
    end
    return dr, dg, db
end

local function SetTableRGB(tbl, key, r, gCol, b)
    if type(tbl) == "table" then tbl[key] = { r, gCol, b } end
end

local function EnsurePowerOverrides()
    local g = GeneralDB()
    g.powerColorOverrides = type(g.powerColorOverrides) == "table" and g.powerColorOverrides or {}
    return g.powerColorOverrides
end

local function PowerDefaultRGB(token)
    local color = _G.PowerBarColor and token and _G.PowerBarColor[token]
    if type(color) == "table" then
        local r = tonumber(color.r or color[1])
        local g = tonumber(color.g or color[2])
        local b = tonumber(color.b or color[3])
        if r and g and b then return r, g, b end
    end
    return 0.8, 0.8, 0.8
end

local function PowerOverrideRGB(token)
    local dr, dg, db = PowerDefaultRGB(token)
    return TableRGB(GeneralDB().powerColorOverrides, token, dr, dg, db)
end

local function SetPowerOverrideRGB(token, r, gCol, b)
    EnsurePowerOverrides()[token] = { r, gCol, b }
end

local CP_SLOT_DEFAULTS = {
    COMBO_POINTS_1 = { 0.00, 0.95, 1.00 },
    COMBO_POINTS_2 = { 0.00, 0.95, 1.00 },
    COMBO_POINTS_3 = { 1.00, 1.00, 0.00 },
    COMBO_POINTS_4 = { 1.00, 1.00, 0.00 },
    COMBO_POINTS_5 = { 1.00, 1.00, 0.00 },
    COMBO_POINTS_6 = { 1.00, 0.05, 0.05 },
    COMBO_POINTS_7 = { 1.00, 0.05, 0.05 },
}

local function EnsureClassPowerOverrides()
    local g = GeneralDB()
    g.classPowerColorOverrides = type(g.classPowerColorOverrides) == "table" and g.classPowerColorOverrides or {}
    g.classPowerBgColorOverrides = type(g.classPowerBgColorOverrides) == "table" and g.classPowerBgColorOverrides or {}
    return g
end

local function ClassPowerDefaultRGB(token)
    local slot = CP_SLOT_DEFAULTS[token]
    if slot then return slot[1], slot[2], slot[3] end
    if token == "CHARGED" then return 0.60, 0.20, 0.80 end
    if token == "RESOURCE_TEXT" then return ApiRGB("GetGlobalFontColor", 1, 1, 1, function() return GeneralRGB("fontColorCustom", 1, 1, 1) end) end
    if token == "SOUL_FRAGMENTS" then return 0.00, 0.80, 0.00 end
    if token == "SOUL_FRAGMENTS_META" then return 0.60, 0.20, 0.93 end
    if token == "MAELSTROM" or token == "MAELSTROM_POWER" then return PowerDefaultRGB("MAELSTROM") end
    if token == "MAELSTROM_ABOVE_5" then return 1.00, 0.50, 0.00 end
    if token == "ASTRAL_POWER" or token == "AP_PREDICTION" then return PowerDefaultRGB("LUNAR_POWER") end
    if token == "ECLIPSE_SOLAR" then return 0.82, 0.56, 0.25 end
    if token == "ECLIPSE_LUNAR" then return 0.41, 0.49, 0.82 end
    if token == "ECLIPSE_CA" then return 0.30, 1.00, 0.43 end
    if token == "STAGGER_GREEN" then return 0.52, 1.00, 0.52 end
    if token == "STAGGER_YELLOW" then return 1.00, 0.98, 0.72 end
    if token == "STAGGER_RED" then return 1.00, 0.42, 0.42 end
    if token == "SOUL_FRAGMENTS_VENG" then return 0.34, 0.06, 0.46 end
    if token == "INSANITY" then return PowerDefaultRGB("INSANITY") end
    if token == "WHIRLWIND" then return 0.20, 0.80, 0.20 end
    if token == "TIP_OF_THE_SPEAR" then return 0.60, 0.80, 0.20 end
    if token == "ICICLES" then return 0.50, 0.80, 1.00 end
    if token == "EBON_MIGHT" then return 0.40, 0.80, 0.60 end
    return PowerDefaultRGB(token)
end

local function ClassPowerRGB(token)
    local dr, dg, db = ClassPowerDefaultRGB(token)
    return TableRGB(GeneralDB().classPowerColorOverrides, token, dr, dg, db)
end

local function SetClassPowerRGB(token, r, gCol, b)
    EnsureClassPowerOverrides().classPowerColorOverrides[token] = { r, gCol, b }
end

local function ClassPowerBgRGB(token)
    return TableRGB(GeneralDB().classPowerBgColorOverrides, token, 0, 0, 0)
end

local function SetClassPowerBgRGB(token, r, gCol, b)
    EnsureClassPowerOverrides().classPowerBgColorOverrides[token] = { r, gCol, b }
end

local function AuraSharedDB()
    local db = GeneralDB()
    db.auras3 = type(db.auras3) == "table" and db.auras3 or {}
    db.auras3.shared = type(db.auras3.shared) == "table" and db.auras3.shared or {}
    return db.auras3.shared
end

local function SetAllPortraitRGB(prefix, r, gCol, b)
    local general = GeneralDB()
    general[prefix .. "R"], general[prefix .. "G"], general[prefix .. "B"] = r, gCol, b
    local db = EnsureDB()
    for _, unit in ipairs({ "player", "target", "focus", "targettarget", "focustarget", "pet", "boss" }) do
        db[unit] = type(db[unit]) == "table" and db[unit] or {}
        db[unit][prefix .. "R"], db[unit][prefix .. "G"], db[unit][prefix .. "B"] = r, gCol, b
    end
end


function A.Workflow.ClampScale(value, minValue, maxValue)
    return ClampNumber(value, minValue or 0.25, maxValue or 1.5, 0.01)
end

function A.Workflow.GlobalScaleState()
    local g = GeneralDB()
    g.UIScale = type(g.UIScale) == "table" and g.UIScale or { Enabled = false, Scale = 1 }
    local ui = g.UIScale
    ui.Enabled = ui.Enabled == true
    ui.Scale = A.Workflow.ClampScale(ui.Scale, 0.3, 1.5) or 1
    return g, ui
end

function A.Workflow.PixelScale()
    if type(_G.MSUF_GetPixelPerfectScale) == "function" then
        local value = tonumber(_G.MSUF_GetPixelPerfectScale())
        if value then return A.Workflow.ClampScale(value, 0.3, 1.5) or 1 end
    end
    if type(_G.GetPhysicalScreenSize) == "function" then
        local _, height = _G.GetPhysicalScreenSize()
        height = tonumber(height)
        if height and height > 0 then return A.Workflow.ClampScale(768 / height, 0.3, 1.5) or 1 end
    end
    return 1
end

function A.Workflow.GlobalScalePresetValue(preset)
    preset = tostring(preset or "custom"):lower()
    if preset == "1080" or preset == "1080p" then return true, 768 / 1080, "1080p" end
    if preset == "1440" or preset == "1440p" then return true, 768 / 1440, "1440p" end
    if preset == "4k" or preset == "2160" or preset == "2160p" then return true, 768 / 2160, "4k" end
    if preset == "pixel" or preset == "pixel perfect" then return true, A.Workflow.PixelScale(), "pixel" end
    if preset == "off" or preset == "auto" or preset == "disabled" then return false, 1, "auto" end
    return nil, nil, nil
end

function A.Workflow.SetGlobalScaleState(enabled, value, preset)
    local g, ui = A.Workflow.GlobalScaleState()
    ui.Enabled = enabled == true
    ui.Scale = A.Workflow.ClampScale(value or ui.Scale, 0.3, 1.5) or 1
    g.globalUiScalePreset = preset or (ui.Enabled and "custom" or "auto")
    g.globalUiScaleValue = ui.Enabled and ui.Scale or nil
end

function A.Workflow.PushGlobalScale()
    local _, ui = A.Workflow.GlobalScaleState()
    if ui.Enabled and type(_G.MSUF_SetGlobalUiScale) == "function" then
        _G.MSUF_SetGlobalUiScale(ui.Scale, true)
    elseif (not ui.Enabled) and type(_G.MSUF_ResetGlobalUiScale) == "function" then
        _G.MSUF_ResetGlobalUiScale(true)
    end
    ApplyGeneral("MSUF_ASSISTANT_GLOBAL_UI_SCALE", { preview = true, applyAll = false })
end

function A.Workflow.ApplyScalePreset(preset)
    local enabled, value, key = A.Workflow.GlobalScalePresetValue(preset)
    if enabled == nil then return false, "I do not know that global UI scale preset." end
    A.Workflow.SetGlobalScaleState(enabled, value, key)
    A.Workflow.PushGlobalScale()
    return true, enabled and ("Done. Applied global UI scale preset " .. tostring(key) .. ".") or "Done. Global UI scale override is off."
end

function A.Workflow.ApplyMsufScale(value)
    local scale = A.Workflow.ClampScale(value, 0.25, 1.5) or 1
    GeneralDB().msufUiScale = scale
    if type(_G.MSUF_ApplyMsufScale) == "function" then _G.MSUF_ApplyMsufScale(scale) end
    ApplyGeneral("MSUF_ASSISTANT_MSUF_SCALE", { preview = true, applyAll = false })
    local UF = MSUF and MSUF.UF
    if UF and type(UF.Apply) == "function" then UF.Apply(nil) end
end

function A.Workflow.ApplyMenuScale(value)
    local scale = A.Workflow.ClampScale(value, 0.25, 1.5) or 1
    GeneralDB().slashMenuScale = scale
    if M and M.frame and type(M.frame.SetScale) == "function" then
        M.frame:SetScale((M.GetEffectiveMenuScale and M.GetEffectiveMenuScale(scale)) or scale)
    end
end

function A.Workflow.ModuleStyleEnabled()
    if type(_G.MSUF_StyleIsEnabled) == "function" then return _G.MSUF_StyleIsEnabled() and true or false end
    return GeneralDB().styleEnabled ~= false
end

function A.Workflow.SetModuleStyleEnabled(enabled)
    enabled = enabled and true or false
    if type(_G.MSUF_SetStyleEnabled) == "function" then
        _G.MSUF_SetStyleEnabled(enabled)
    else
        GeneralDB().styleEnabled = enabled
    end
    GeneralDB().styleEnabled = enabled
    CallGlobal("MSUF_ApplyModules")
end

function A.Workflow.NormalizeDropdownStyleMode(mode)
    mode = tostring(mode or "msuf"):lower()
    if mode == "old" or mode == "blizzard" or mode == "legacy" then return "old" end
    return "msuf"
end

function A.Workflow.DropdownStyleMode()
    if type(_G.MSUF_GetDropdownStyleMode) == "function" then return A.Workflow.NormalizeDropdownStyleMode(_G.MSUF_GetDropdownStyleMode()) end
    return A.Workflow.NormalizeDropdownStyleMode(GeneralDB().dropdownStyleMode)
end

function A.Workflow.SetDropdownStyleMode(mode)
    mode = A.Workflow.NormalizeDropdownStyleMode(mode)
    if type(_G.MSUF_ApplyDropdownStyleModeImmediate) == "function" then
        _G.MSUF_ApplyDropdownStyleModeImmediate(mode)
    elseif type(_G.MSUF_SetDropdownStyleMode) == "function" then
        _G.MSUF_SetDropdownStyleMode(mode)
        GeneralDB().dropdownStyleMode = mode
    else
        GeneralDB().dropdownStyleMode = mode
    end
end

function A.Workflow.NormalizeTooltipMode(mode)
    mode = tostring(mode or "ALWAYS"):upper()
    if mode == "OOC" or mode == "MODIFIER" or mode == "NEVER" then return mode end
    if mode == "OFF" then return "NEVER" end
    return "ALWAYS"
end

function A.Workflow.NormalizeTooltipModifier(modifier)
    modifier = tostring(modifier or "ALT"):upper()
    if modifier == "CTRL" or modifier == "SHIFT" then return modifier end
    return "ALT"
end

function A.Workflow.ReadTooltipProvider()
    local g = GeneralDB()
    if g.unitTooltipProvider == "MSUF" then return "MSUF" end
    if g.unitTooltipProvider == "GAME" then return "GAME" end
    return g.disableUnitInfoTooltips == false and "MSUF" or "GAME"
end

function A.Workflow.ReadTooltipAnchor()
    local g = GeneralDB()
    local anchor = g.unitTooltipAnchor
    if anchor == "EXTERNAL" or anchor == "FIXED" or anchor == "CURSOR" then return anchor end
    if A.Workflow.ReadTooltipProvider() == "MSUF" then
        return g.unitInfoTooltipStyle == "modern" and "CURSOR" or "FIXED"
    end
    if type(g.tooltipPosX) == "number" and type(g.tooltipPosY) == "number" then return "FIXED" end
    if g.unitInfoTooltipStyle == "modern" then return "CURSOR" end
    return "EXTERNAL"
end

function A.Workflow.RefreshTooltipPreview()
    local tooltips = MSUF and MSUF.Tooltips
    if tooltips and type(tooltips.Refresh) == "function" then tooltips.Refresh() end
    local editActive = _G.MSUF_UnitEditModeActive == true
    if not editActive and type(_G.MSUF_IsMSUFEditModeActive) == "function" then editActive = _G.MSUF_IsMSUFEditModeActive() and true or false end
    if editActive and type(_G.MSUF_Tooltip_ShowEditPreview) == "function" then _G.MSUF_Tooltip_ShowEditPreview() end
end

function A.Workflow.WriteTooltipSettings(provider, anchor)
    local g = GeneralDB()
    provider = provider == "MSUF" and "MSUF" or "GAME"
    if anchor ~= "FIXED" and anchor ~= "CURSOR" and anchor ~= "EXTERNAL" then anchor = "EXTERNAL" end
    if provider == "MSUF" and anchor == "EXTERNAL" then anchor = "FIXED" end
    g.unitTooltipProvider = provider
    g.unitTooltipAnchor = anchor
    g.disableUnitInfoTooltips = provider ~= "MSUF"
    g.unitInfoTooltipStyle = anchor == "CURSOR" and "modern" or "classic"
    ApplyGeneral("MSUF_ASSISTANT_TOOLTIPS", { preview = false, applyAll = false, notify = false })
    A.Workflow.RefreshTooltipPreview()
end

function A.Workflow.WriteTooltipBehavior(mode, modifier)
    local g = GeneralDB()
    g.unitTooltipMode = A.Workflow.NormalizeTooltipMode(mode)
    g.unitTooltipModifier = A.Workflow.NormalizeTooltipModifier(modifier)
    ApplyGeneral("MSUF_ASSISTANT_TOOLTIP_BEHAVIOR", { preview = false, applyAll = false, notify = false })
    A.Workflow.RefreshTooltipPreview()
end


Registry:RegisterSetting({
    key = "general.globalUiScale",
    label = "Global WoW UI Scale",
    category = "Dashboard / Scaling",
    unit = "global",
    frameType = "dashboard",
    attribute = "globalUiScale",
    type = "number",
    min = 0.3,
    max = 1.5,
    step = 0.01,
    percent = true,
    aliases = { "global ui scale", "wow ui scale", "global wow scale", "global scale" },
    get = function()
        local _, ui = A.Workflow.GlobalScaleState()
        return ui.Scale
    end,
    set = function(value)
        A.Workflow.SetGlobalScaleState(true, value, "custom")
    end,
    apply = function() A.Workflow.PushGlobalScale() end,
    combatSafe = false,
})

Registry:RegisterSetting({
    key = "general.globalUiScaleEnabled",
    label = "Global WoW UI Scale Override",
    category = "Dashboard / Scaling",
    unit = "global",
    frameType = "dashboard",
    attribute = "globalUiScaleEnabled",
    type = "boolean",
    aliases = { "global ui scale override", "wow ui scale override", "global scale override" },
    get = function()
        local _, ui = A.Workflow.GlobalScaleState()
        return ui.Enabled == true
    end,
    set = function(value)
        local _, ui = A.Workflow.GlobalScaleState()
        A.Workflow.SetGlobalScaleState(value and true or false, ui.Scale, value and "custom" or "auto")
    end,
    apply = function() A.Workflow.PushGlobalScale() end,
    combatSafe = false,
})

Registry:RegisterSetting({
    key = "general.msufUiScale",
    label = "MSUF Frame Scale",
    category = "Dashboard / Scaling",
    unit = "global",
    frameType = "dashboard",
    attribute = "msufFrameScale",
    type = "number",
    min = 0.25,
    max = 1.5,
    step = 0.01,
    percent = true,
    aliases = { "msuf frame scale", "msuf ui scale", "unit frame scale", "frame scale" },
    get = function() return A.Workflow.ClampScale(GeneralDB().msufUiScale or 1, 0.25, 1.5) or 1 end,
    set = function(value) GeneralDB().msufUiScale = A.Workflow.ClampScale(value, 0.25, 1.5) or 1 end,
    apply = function() A.Workflow.ApplyMsufScale(GeneralDB().msufUiScale or 1) end,
    combatSafe = false,
})

Registry:RegisterSetting({
    key = "general.slashMenuScale",
    label = "MSUF Menu Scale",
    category = "Dashboard / Scaling",
    unit = "global",
    frameType = "dashboard",
    attribute = "menuScale",
    type = "number",
    min = 0.25,
    max = 1.5,
    step = 0.01,
    percent = true,
    aliases = { "msuf menu scale", "menu scale", "configuration menu scale", "dashboard scale" },
    get = function() return A.Workflow.ClampScale(GeneralDB().slashMenuScale or 1, 0.25, 1.5) or 1 end,
    set = function(value) GeneralDB().slashMenuScale = A.Workflow.ClampScale(value, 0.25, 1.5) or 1 end,
    apply = function() A.Workflow.ApplyMenuScale(GeneralDB().slashMenuScale or 1) end,
    combatSafe = false,
})

Registry:RegisterAction({
    key = "apply_global_scale_preset",
    label = "Apply Global UI Scale Preset",
    type = "preset",
    combatSafe = false,
    captureSnapshot = true,
    run = function(args)
        return A.Workflow.ApplyScalePreset(args and args.preset)
    end,
})

Registry:RegisterAction({
    key = "set_global_font_color",
    label = "Set Global Font Color",
    type = "color",
    combatSafe = false,
    captureSnapshot = true,
    run = function(args)
        local r, g, b = args and args.r, args and args.g, args and args.b
        if type(args and args.color) == "string" then
            local cr, cg, cb = ColorFromName(args.color)
            if cr then r, g, b = cr, cg, cb end
        end
        if type(r) ~= "number" or type(g) ~= "number" or type(b) ~= "number" then
            return false, "I need a color name, hex value, or RGB value."
        end
        r, g, b = Clamp01(r), Clamp01(g), Clamp01(b)
        local api = MSUF and MSUF._colorsAPI
        if api and type(api.SetGlobalFontColor) == "function" then
            api.SetGlobalFontColor(r, g, b)
        else
            local gen = GeneralDB()
            gen.useCustomFontColor = true
            gen.fontColorCustomR, gen.fontColorCustomG, gen.fontColorCustomB = r, g, b
        end
        ApplyVisuals("MSUF_ASSISTANT_FONT_COLOR_CUSTOM")
        return true, "Done. Global font color set to " .. tostring(args and args.label or args and args.color or "custom") .. "."
    end,
})

Registry:RegisterAction({
    key = "reset_global_font_color",
    label = "Reset Global Font Color",
    type = "color",
    combatSafe = false,
    captureSnapshot = true,
    run = function()
        local api = MSUF and MSUF._colorsAPI
        if api and type(api.ResetGlobalFontToPalette) == "function" then
            api.ResetGlobalFontToPalette()
        else
            local gen = GeneralDB()
            gen.useCustomFontColor = false
            gen.fontColorCustomR, gen.fontColorCustomG, gen.fontColorCustomB = nil, nil, nil
        end
        ApplyVisuals("MSUF_ASSISTANT_FONT_COLOR_RESET")
        return true, "Done. Global font color follows the palette again."
    end,
})

local function RegisterAssistantColorSettings()
ColorSetting("general.customFontColor", "Global Font Color", {
    "custom font color", "main font color", "global custom font color",
}, function()
    return ApiRGB("GetGlobalFontColor", 1, 1, 1, function() return GeneralRGB("fontColorCustom", 1, 1, 1) end)
end, function(r, g, b)
    if not ApiSetRGB("SetGlobalFontColor", r, g, b) then
        local gen = GeneralDB()
        gen.useCustomFontColor = true
        gen.fontColorCustomR, gen.fontColorCustomG, gen.fontColorCustomB = r, g, b
    end
end, { category = "Colors / Global Font", attribute = "customFontColor", apply = ApplyColors })

local COLOR_CLASS_TOKENS = {
    "WARRIOR", "PALADIN", "HUNTER", "ROGUE", "PRIEST", "DEATHKNIGHT", "SHAMAN",
    "MAGE", "WARLOCK", "MONK", "DRUID", "DEMONHUNTER", "EVOKER",
}
local COLOR_CLASS_LABELS = {
    WARRIOR = "Warrior",
    PALADIN = "Paladin",
    HUNTER = "Hunter",
    ROGUE = "Rogue",
    PRIEST = "Priest",
    DEATHKNIGHT = "Death Knight",
    SHAMAN = "Shaman",
    MAGE = "Mage",
    WARLOCK = "Warlock",
    MONK = "Monk",
    DRUID = "Druid",
    DEMONHUNTER = "Demon Hunter",
    EVOKER = "Evoker",
}

for i = 1, #COLOR_CLASS_TOKENS do
    local token = COLOR_CLASS_TOKENS[i]
    local label = COLOR_CLASS_LABELS[token] or token
    local lower = label:lower()
    ColorSetting("classColors." .. token, label .. " Class Bar Color", {
        lower .. " class color", lower .. " class bar color", lower .. " bar color", lower .. " color",
    }, function()
        local fn = ColorAPI().GetClassColor
        if type(fn) == "function" then return fn(token) end
        local db = GeneralDB()
        if type(db.classColors) == "table" then
            local color = db.classColors[token]
            if type(color) == "table" then return color.r or color[1] or 1, color.g or color[2] or 1, color.b or color[3] or 1 end
        end
        local rc = _G.RAID_CLASS_COLORS and _G.RAID_CLASS_COLORS[token]
        if rc then return rc.r, rc.g, rc.b end
        return 1, 1, 1
    end, function(r, g, b)
        local fn = ColorAPI().SetClassColor
        if type(fn) == "function" then
            fn(token, r, g, b)
        else
            local db = GeneralDB()
            db.classColors = type(db.classColors) == "table" and db.classColors or {}
            db.classColors[token] = { r = r, g = g, b = b }
        end
    end, { category = "Colors / Class Bar", attribute = "classColor", apply = ApplyColors })
end

ColorSetting("general.classBarBgColor", "Bar Background Tint", {
    "bar background tint", "bar tint", "class bar background color", "bar background color",
}, function()
    return ApiRGB("GetClassBarBgColor", 0, 0, 0, function() return GeneralRGB("classBarBg", 0, 0, 0) end)
end, function(r, g, b)
    if not ApiSetRGB("SetClassBarBgColor", r, g, b) then SetGeneralRGB("classBarBg", r, g, b) end
end, { category = "Colors / Bar Background", attribute = "barBackgroundTint", defaultR = 0, defaultG = 0, defaultB = 0, apply = ApplyColors })

Registry:RegisterSetting({
    key = "general.barBgMatchHPColor",
    label = "Background Follows HP Color",
    category = "Colors / Bar Background",
    unit = "global",
    frameType = "colors",
    attribute = "barBackgroundFollowsHP",
    type = "boolean",
    aliases = { "background follows hp color", "bar background follows hp", "background matches hp" },
    get = function()
        local fn = ColorAPI().GetBarBgMatchHP
        if type(fn) == "function" then return fn() == true end
        return GeneralDB().barBgMatchHPColor == true
    end,
    set = function(value)
        local fn = ColorAPI().SetBarBgMatchHP
        if type(fn) == "function" then
            fn(value and true or false)
        else
            local g = GeneralDB()
            g.barBgMatchHPColor = value and true or false
            if value then g.barBgClassColor = false end
        end
    end,
    apply = ApplyColors,
    combatSafe = false,
})

Registry:RegisterSetting({
    key = "general.barBgClassColor",
    label = "Health Background Follows Class Color",
    category = "Colors / Bar Background",
    unit = "global",
    frameType = "colors",
    attribute = "barBackgroundFollowsClass",
    type = "boolean",
    aliases = { "health background follows class color", "bar background class color", "background follows class color" },
    get = function()
        local fn = ColorAPI().GetBarBgClassColor
        if type(fn) == "function" then return fn() == true end
        return GeneralDB().barBgClassColor == true
    end,
    set = function(value)
        local fn = ColorAPI().SetBarBgClassColor
        if type(fn) == "function" then
            fn(value and true or false)
        else
            local g = GeneralDB()
            g.barBgClassColor = value and true or false
            if value then g.barBgMatchHPColor = false end
        end
    end,
    apply = ApplyColors,
    combatSafe = false,
})

RegisterGeneralBoolean("darkBgCustomColor", "darkModeCustomBackgroundColor", "Custom Color In Dark Mode", false, {
    "custom color in dark mode", "dark mode custom background color", "dark mode custom color",
}, { category = "Colors / Bar Background", frameType = "colors", apply = ApplyColors, reason = "MSUF_ASSISTANT_DARK_MODE_CUSTOM_COLOR" })

ColorSetting("general.unifiedBarColor", "Unified Bar Color", {
    "unified bar color", "unified color", "all frames color",
}, function()
    return GeneralRGB("unifiedBar", 0.10, 0.60, 0.90)
end, function(r, g, b)
    SetGeneralRGB("unifiedBar", r, g, b)
end, { category = "Colors / Unitframe Global Coloring", attribute = "unifiedBarColor", defaultR = 0.10, defaultG = 0.60, defaultB = 0.90, apply = ApplyColors })

RegisterGeneralNumberSetting("darkBarGray", "darkModeBarColor", "Dark Mode Bar Color", 0.07, 0, 1, {
    "dark mode bar color", "dark bar color", "dark mode brightness", "dark bar brightness",
}, { category = "Colors / Unitframe Global Coloring", frameType = "colors", apply = ApplyColors, reason = "MSUF_ASSISTANT_DARK_BAR_GRAY", step = 0.01, percent = true })

RegisterGeneralBoolean("enableHealthGradient", "healthColorGradient", "Health Color Gradient", true, {
    "health color gradient", "color health by gradient", "unitframe health gradient",
}, { category = "Colors / Unitframe Global Coloring", frameType = "colors", apply = ApplyColors, reason = "MSUF_ASSISTANT_HEALTH_COLOR_GRADIENT" })

local COLOR_NPC_ROWS = {
    { key = "friendly", label = "Friendly NPC Color", dr = 0, dg = 1, db = 0, aliases = { "friendly npc color", "friendly reaction color" } },
    { key = "neutral", label = "Neutral NPC Color", dr = 1, dg = 1, db = 0, aliases = { "neutral npc color", "neutral reaction color" } },
    { key = "enemy", label = "Enemy NPC Color", dr = 0.85, dg = 0.10, db = 0.10, aliases = { "enemy npc color", "hostile npc color", "enemy reaction color" } },
    { key = "dead", label = "Dead NPC Color", dr = 0.40, dg = 0.40, db = 0.40, aliases = { "dead npc color", "dead unit color" } },
}

for i = 1, #COLOR_NPC_ROWS do
    local row = COLOR_NPC_ROWS[i]
    ColorSetting("npcColors." .. row.key, row.label, row.aliases, function()
        local fn = ColorAPI().GetNPCColor
        if type(fn) == "function" then return fn(row.key) end
        return TableRGB(GeneralDB().npcColors, row.key, row.dr, row.dg, row.db)
    end, function(r, g, b)
        local fn = ColorAPI().SetNPCColor
        if type(fn) == "function" then
            fn(row.key, r, g, b)
        else
            local db = GeneralDB()
            db.npcColors = type(db.npcColors) == "table" and db.npcColors or {}
            db.npcColors[row.key] = { r = r, g = g, b = b }
        end
    end, { category = "Colors / Unitframe Colors", attribute = "npcColor", defaultR = row.dr, defaultG = row.dg, defaultB = row.db, apply = ApplyColors })
end

ColorSetting("general.petFrameColor", "Pet Frame Color", {
    "pet frame color", "pet color", "pet bar color",
}, function()
    return ApiRGB("GetPetFrameColor", 0, 0.8, 0, function() return GeneralRGB("petFrameColor", 0, 0.8, 0) end)
end, function(r, g, b)
    if not ApiSetRGB("SetPetFrameColor", r, g, b) then SetGeneralRGB("petFrameColor", r, g, b) end
end, { category = "Colors / Unitframe Colors", attribute = "petColor", defaultR = 0, defaultG = 0.8, defaultB = 0, apply = ApplyColors })

Registry:RegisterSetting({
    key = "general.npcColorMode",
    label = "NPC Type Colors",
    category = "Colors / NPC Type",
    unit = "global",
    frameType = "colors",
    attribute = "npcTypeColors",
    type = "boolean",
    aliases = { "npc type colors", "npc type coloring", "npc role colors" },
    get = function()
        local fn = ColorAPI().GetNPCColorMode
        if type(fn) == "function" then return fn() == "type" end
        return GeneralDB().npcColorMode == "type"
    end,
    set = function(value)
        local mode = value and "type" or "reaction"
        local fn = ColorAPI().SetNPCColorMode
        if type(fn) == "function" then fn(mode) else GeneralDB().npcColorMode = mode end
    end,
    apply = ApplyColors,
    combatSafe = false,
})
RegisterGeneralBoolean("npcTypeColorBar", "npcTypeColorHPBar", "NPC Type Color HP Bar", true, {
    "npc type color hp bar", "npc type color health bar", "npc role color hp",
}, { category = "Colors / NPC Type", frameType = "colors", apply = ApplyColors, reason = "MSUF_ASSISTANT_NPC_TYPE_HP_COLOR" })
RegisterGeneralBoolean("npcTypeColorText", "npcTypeColorNameText", "NPC Type Color Name Text", true, {
    "npc type color name text", "npc type color names", "npc role color names",
}, { category = "Colors / NPC Type", frameType = "colors", apply = ApplyColors, reason = "MSUF_ASSISTANT_NPC_TYPE_TEXT_COLOR" })
for _, item in ipairs({
    { key = "npcTypeTarget", label = "NPC Type Color Target", aliases = { "npc type colors target", "target npc type colors" } },
    { key = "npcTypeFocus", label = "NPC Type Color Focus", aliases = { "npc type colors focus", "focus npc type colors" } },
    { key = "npcTypeBoss", label = "NPC Type Color Boss", aliases = { "npc type colors boss", "boss npc type colors" } },
    { key = "npcTypeToT", label = "NPC Type Color Target of Target", aliases = { "npc type colors targettarget", "targettarget npc type colors", "tot npc type colors" } },
}) do
    RegisterGeneralBoolean(item.key, item.key, item.label, true, item.aliases, {
        category = "Colors / NPC Type",
        frameType = "colors",
        apply = ApplyColors,
        reason = "MSUF_ASSISTANT_" .. item.key,
    })
end

local COLOR_NPC_TYPE_ROWS = {
    { key = "npcBoss", label = "Boss NPC Type Color", dr = 0.74, dg = 0.11, db = 0, aliases = { "boss npc type color", "npc boss color", "boss type color" } },
    { key = "npcMiniboss", label = "Miniboss NPC Type Color", dr = 0.56, dg = 0, db = 0.74, aliases = { "miniboss npc type color", "lieutenant npc color", "npc miniboss color" } },
    { key = "npcCaster", label = "Caster NPC Type Color", dr = 0, dg = 0.45, db = 0.74, aliases = { "caster npc type color", "npc caster color", "caster type color" } },
    { key = "npcMelee", label = "Melee NPC Type Color", dr = 0.99, dg = 0.99, db = 0.99, aliases = { "melee npc type color", "npc melee color", "melee type color" } },
    { key = "npcRegular", label = "Regular NPC Type Color", dr = 0.70, dg = 0.56, db = 0.33, aliases = { "regular npc type color", "npc regular color", "regular type color" } },
}
for i = 1, #COLOR_NPC_TYPE_ROWS do
    local row = COLOR_NPC_TYPE_ROWS[i]
    ColorSetting("npcColors." .. row.key, row.label, row.aliases, function()
        local fn = ColorAPI().GetNPCColor
        if type(fn) == "function" then return fn(row.key) end
        return TableRGB(GeneralDB().npcColors, row.key, row.dr, row.dg, row.db)
    end, function(r, g, b)
        local fn = ColorAPI().SetNPCColor
        if type(fn) == "function" then
            fn(row.key, r, g, b)
        else
            local db = GeneralDB()
            db.npcColors = type(db.npcColors) == "table" and db.npcColors or {}
            db.npcColors[row.key] = { r = r, g = g, b = b }
        end
    end, { category = "Colors / NPC Type", attribute = "npcTypeColor", defaultR = row.dr, defaultG = row.dg, defaultB = row.db, apply = ApplyColors })
end

ColorSetting("general.absorbBarColor", "Absorb Bar Color", {
    "absorb bar color", "absorb color", "absorb overlay color",
}, function()
    return ApiRGB("GetAbsorbOverlayColor", 1, 1, 1, function() return GeneralRGB("absorbBarColor", 1, 1, 1) end)
end, function(r, g, b)
    if not ApiSetRGB("SetAbsorbOverlayColor", r, g, b, 0.45) then SetGeneralRGB("absorbBarColor", r, g, b) end
end, { category = "Colors / Bar Colors", attribute = "absorbColor", apply = ApplyColors })
ColorSetting("general.healAbsorbBarColor", "Heal-Absorb Bar Color", {
    "heal absorb bar color", "heal absorb color", "heal-absorb color",
}, function()
    return ApiRGB("GetHealAbsorbOverlayColor", 0.7, 0, 0, function() return GeneralRGB("healAbsorbBarColor", 0.7, 0, 0) end)
end, function(r, g, b)
    if not ApiSetRGB("SetHealAbsorbOverlayColor", r, g, b, 0.45) then SetGeneralRGB("healAbsorbBarColor", r, g, b) end
end, { category = "Colors / Bar Colors", attribute = "healAbsorbColor", defaultR = 0.7, apply = ApplyColors })
ColorSetting("general.powerBarBgColor", "Power Bar Background Color", {
    "power bar background color", "power background color", "mana bar background color",
}, function()
    return ApiRGB("GetPowerBarBackgroundColor", 0, 0, 0, function() return GeneralRGB("powerBarBgColor", 0, 0, 0) end)
end, function(r, g, b)
    if not ApiSetRGB("SetPowerBarBackgroundColor", r, g, b) then SetGeneralRGB("powerBarBgColor", r, g, b) end
end, { category = "Colors / Bar Colors", attribute = "powerBackgroundColor", defaultR = 0, defaultG = 0, defaultB = 0, apply = ApplyColors })
ColorSetting("general.aggroBorderColor", "Aggro Border Color", {
    "aggro border color", "threat border color", "aggro outline color",
}, function()
    return ApiRGB("GetAggroBorderColor", 1, 0.5, 0, function() return GeneralRGBAlias("hlAggroColor", "aggroBorderColor", 1, 0.5, 0) end)
end, function(r, g, b)
    if not ApiSetRGB("SetAggroBorderColor", r, g, b) then SetGeneralRGBAlias("hlAggroColor", "aggroBorderColor", r, g, b) end
end, { category = "Colors / Bar Colors", attribute = "aggroBorderColor", defaultR = 1, defaultG = 0.5, defaultB = 0, apply = ApplyColors })
ColorSetting("general.purgeBorderColor", "Purge Border Color", {
    "purge border color", "purgeable border color", "purge outline color",
}, function()
    return GeneralRGBAlias("hlPurgeColor", "purgeBorderColor", 1, 0.85, 0)
end, function(r, g, b)
    SetGeneralRGBAlias("hlPurgeColor", "purgeBorderColor", r, g, b)
end, { category = "Colors / Bar Colors", attribute = "purgeBorderColor", defaultR = 1, defaultG = 0.85, defaultB = 0, apply = ApplyColors })
ColorSetting("general.barOutlineColor", "Bar Outline Color", {
    "bar outline color", "frame outline color", "bar border color", "bars border color", "border outline color", "outline border color",
}, function()
    return ApiRGB("GetBarOutlineColor", 0, 0, 0, function() return GeneralRGB("barOutlineColor", 0, 0, 0) end)
end, function(r, g, b)
    local gdb = GeneralDB()
    gdb.barOutlineColorMode = nil
    gdb.barOutlineColorA = 1
    if not ApiSetRGB("SetBarOutlineColor", r, g, b) then SetGeneralRGB("barOutlineColor", r, g, b) end
end, { category = "Colors / Bar Colors", attribute = "barOutlineColor", defaultR = 0, defaultG = 0, defaultB = 0, apply = ApplyColors })
for _, scope in ipairs(GLOBAL_SCOPE_ORDER) do
    Registry:RegisterSetting({
        key = "barScope." .. NormalizeGlobalScope(scope) .. ".barOutlineColor",
        label = GlobalScopeLabel(scope) .. " Bar Outline Color",
        category = "Global / Bars / Scoped",
        unit = NormalizeGlobalScope(scope),
        frameType = "globalBars",
        attribute = "barOutlineColor",
        type = "color",
        aliases = GlobalScopeAliases(scope, { "bar outline color", "frame outline color", "bar border color", "bars border color", "border outline color", "outline border color", "border color", "outline color" }),
        get = function()
            return {
                r = Clamp01(GlobalScopeRead(scope, "hlOverride", GeneralDB(), "barOutlineColorR", 0)),
                g = Clamp01(GlobalScopeRead(scope, "hlOverride", GeneralDB(), "barOutlineColorG", 0)),
                b = Clamp01(GlobalScopeRead(scope, "hlOverride", GeneralDB(), "barOutlineColorB", 0)),
            }
        end,
        set = function(value)
            local r, g, b = ColorComponents(value, 0, 0, 0)
            GlobalScopeWrite(scope, "hlOverride", GeneralDB(), "barOutlineColorR", r)
            GlobalScopeWrite(scope, "hlOverride", GeneralDB(), "barOutlineColorG", g)
            GlobalScopeWrite(scope, "hlOverride", GeneralDB(), "barOutlineColorB", b)
        end,
        sameValue = ColorSame,
        apply = function() ApplyBarOutline("MSUF_ASSISTANT_SCOPED_BAR_OUTLINE_COLOR") end,
        combatSafe = false,
    })
end
RegisterGeneralBoolean("powerBarBgMatchBarColor", "powerBackgroundMatchesHP", "Power Background Matches HP", false, {
    "power background matches hp", "power bar background matches hp", "power background follows hp",
}, { category = "Colors / Bar Colors", frameType = "colors", apply = ApplyColors, reason = "MSUF_ASSISTANT_POWER_BG_MATCH_HP" })

RegisterGeneralEnum("hlDispelColorMode", "dispelColorMode", "Dispel Color Mode", "SINGLE", { "SINGLE", "TYPE" }, {
    "dispel color mode", "dispel colors mode", "debuff type color mode",
}, {
    category = "Colors / Dispel",
    frameType = "colors",
    apply = ApplyColors,
    reason = "MSUF_ASSISTANT_DISPEL_COLOR_MODE",
    valueAliases = { single = "SINGLE", one = "SINGLE", type = "TYPE", types = "TYPE", pertype = "TYPE", debufftype = "TYPE" },
})
ColorSetting("general.hlDispelColor", "Dispel Color", {
    "dispel color", "dispel border color", "all dispel color", "single dispel color",
}, function()
    return GeneralRGBAlias("hlDispelColor", "dispelBorderColor", 0.25, 0.75, 1)
end, function(r, g, b)
    SetGeneralRGBAlias("hlDispelColor", "dispelBorderColor", r, g, b)
end, { category = "Colors / Dispel", attribute = "dispelColor", defaultR = 0.25, defaultG = 0.75, defaultB = 1, apply = ApplyColors })

for _, row in ipairs({
    { key = "Magic", label = "Magic Dispel Color", dr = 0.20, dg = 0.60, db = 1.00, aliases = { "magic dispel color", "magic debuff color" } },
    { key = "Curse", label = "Curse Dispel Color", dr = 0.60, dg = 0.00, db = 1.00, aliases = { "curse dispel color", "curse debuff color" } },
    { key = "Disease", label = "Disease Dispel Color", dr = 0.60, dg = 0.40, db = 0.00, aliases = { "disease dispel color", "disease debuff color" } },
    { key = "Poison", label = "Poison Dispel Color", dr = 0.00, dg = 0.60, db = 0.00, aliases = { "poison dispel color", "poison debuff color" } },
    { key = "Bleed", label = "Bleed Dispel Color", dr = 0.80, dg = 0.10, db = 0.10, aliases = { "bleed dispel color", "bleed debuff color" } },
}) do
    ColorSetting("general.dispelType" .. row.key, row.label, row.aliases, function()
        return GeneralRGB("dispelType" .. row.key, row.dr, row.dg, row.db)
    end, function(r, g, b)
        SetGeneralRGB("dispelType" .. row.key, r, g, b)
    end, { category = "Colors / Dispel", attribute = "dispelTypeColor", defaultR = row.dr, defaultG = row.dg, defaultB = row.db, apply = ApplyColors })
end

for _, row in ipairs({
    { key = "castbarInterruptible", label = "Interruptible Cast Color", get = "GetInterruptibleCastColor", set = "SetInterruptibleCastColor", dr = 0, dg = 0.9, db = 0.8, aliases = { "interruptible cast color", "interruptible castbar color", "castbar interruptible color", "interrupt castbar color", "castbar interrupt color", "kickable cast color", "kickable castbar color" } },
    { key = "castbarNonInterruptible", label = "Non-Interruptible Cast Color", get = "GetNonInterruptibleCastColor", set = "SetNonInterruptibleCastColor", dr = 0.4, dg = 0.01, db = 0.01, aliases = { "non interruptible cast color", "non interruptible castbar color", "noninterruptible cast color", "noninterruptible castbar color", "not interruptible castbar color", "uninterruptible cast color", "uninterruptible castbar color", "unkickable cast color", "unkickable castbar color", "not kickable castbar color" } },
    { key = "castbarInterruptFeedback", label = "Interrupt Feedback Cast Color", get = "GetInterruptFeedbackCastColor", set = "SetInterruptFeedbackCastColor", dr = 1, dg = 0.82, db = 0, aliases = { "interrupt feedback color", "castbar interrupt feedback color", "interrupt color all castbars", "interrupt color for all castbars", "interrupted cast color", "interrupted castbar color", "after interrupt cast color" } },
    { key = "castbarFont", label = "Castbar Text Color", get = "GetCastbarTextColor", set = "SetCastbarTextColor", dr = 1, dg = 1, db = 1, aliases = { "castbar text color", "castbar font color", "cast bar text color", "castbar spell name color", "castbar spell name text color", "castbar spell color", "castbar spell text color", "spell name color", "spell text color" } },
}) do
    ColorSetting("general." .. row.key .. "Color", row.label, row.aliases, function()
        return ApiRGB(row.get, row.dr, row.dg, row.db, function() return GeneralRGB(row.key, row.dr, row.dg, row.db) end)
    end, function(r, g, b)
        local fallbackPrefix = row.key
        if row.key == "castbarFont" then fallbackPrefix = "castbarFont" end
        if not ApiSetRGB(row.set, r, g, b) then SetGeneralRGB(fallbackPrefix, r, g, b) end
    end, { category = "Colors / Castbar", attribute = row.key .. "Color", defaultR = row.dr, defaultG = row.dg, defaultB = row.db, apply = ApplyCastbarColors })
end

ColorSetting("general.castbarBorderColor", "Castbar Border Color", {
    "castbar border color", "cast bar border color", "castbar outline color",
}, function()
    return ApiRGB("GetCastbarBorderColor", 0, 0, 0, function() return GeneralRGB("castbarBorder", 0, 0, 0) end)
end, function(r, g, b)
    if not ApiSetRGB("SetCastbarBorderColor", r, g, b, 1) then SetGeneralRGB("castbarBorder", r, g, b) end
end, { category = "Colors / Castbar", attribute = "castbarBorderColor", defaultR = 0, defaultG = 0, defaultB = 0, apply = ApplyCastbarColors })

ColorSetting("general.castbarBackgroundColor", "Castbar Background Color", {
    "castbar background color", "cast bar background color", "castbar bg color",
}, function()
    return ApiRGB("GetCastbarBackgroundColor", 0.10, 0.10, 0.10, function() return GeneralRGB("castbarBg", 0.10, 0.10, 0.10) end)
end, function(r, g, b)
    if not ApiSetRGB("SetCastbarBackgroundColor", r, g, b, 0.85) then SetGeneralRGB("castbarBg", r, g, b) end
end, { category = "Colors / Castbar", attribute = "castbarBackgroundColor", defaultR = 0.10, defaultG = 0.10, defaultB = 0.10, apply = ApplyCastbarColors })

RegisterGeneralBoolean("playerCastbarOverrideEnabled", "playerCastbarOverride", "Player Castbar Color Override", true, {
    "player castbar color override", "player castbar override", "player cast color override",
}, { category = "Colors / Castbar", frameType = "colors", apply = ApplyCastbarColors, reason = "MSUF_ASSISTANT_PLAYER_CASTBAR_OVERRIDE" })
RegisterGeneralEnum("playerCastbarOverrideMode", "playerCastbarOverrideMode", "Player Castbar Override Mode", "CLASS", { "CLASS", "CUSTOM" }, {
    "player castbar override mode", "player castbar color mode",
}, {
    category = "Colors / Castbar",
    frameType = "colors",
    apply = ApplyCastbarColors,
    reason = "MSUF_ASSISTANT_PLAYER_CASTBAR_OVERRIDE_MODE",
    valueAliases = { class = "CLASS", classcolor = "CLASS", custom = "CUSTOM", color = "CUSTOM", manual = "CUSTOM" },
})
ColorSetting("general.playerCastbarOverrideColor", "Player Castbar Override Color", {
    "player castbar override color", "player castbar custom color", "player cast custom color",
}, function()
    return ApiRGB("GetPlayerCastbarOverrideColor", 0, 0.6, 1, function() return GeneralRGB("playerCastbarOverride", 0, 0.6, 1) end)
end, function(r, g, b)
    if not ApiSetRGB("SetPlayerCastbarOverrideColor", r, g, b) then SetGeneralRGB("playerCastbarOverride", r, g, b) end
end, { category = "Colors / Castbar", attribute = "playerCastbarOverrideColor", defaultR = 0, defaultG = 0.6, defaultB = 1, apply = ApplyCastbarColors })

ColorSetting("general.kickReadyColor", "Kick Ready Color", {
    "kick ready color", "interrupt ready color", "ready kick color",
}, function()
    return TableRGB(GeneralDB(), "kickReadyColor", 0, 1, 0)
end, function(r, g, b)
    SetTableRGB(GeneralDB(), "kickReadyColor", r, g, b)
end, { category = "Colors / Castbar", attribute = "kickReadyColor", defaultR = 0, defaultG = 1, defaultB = 0, apply = ApplyCastbarColors })
ColorSetting("general.kickNotReadyColor", "Kick Not Ready Color", {
    "kick not ready color", "interrupt not ready color", "kick cooldown color",
}, function()
    return TableRGB(GeneralDB(), "kickNotReadyColor", 1, 0, 0)
end, function(r, g, b)
    SetTableRGB(GeneralDB(), "kickNotReadyColor", r, g, b)
end, { category = "Colors / Castbar", attribute = "kickNotReadyColor", defaultR = 1, defaultG = 0, defaultB = 0, apply = ApplyCastbarColors })

RegisterGeneralBoolean("highlightEnabled", "mouseoverHighlight", "Mouseover Highlight", true, {
    "mouseover highlight", "hover highlight", "unitframe mouseover highlight",
}, { category = "Colors / Mouseover Highlight", frameType = "colors", apply = ApplyColors, reason = "MSUF_ASSISTANT_MOUSEOVER_HIGHLIGHT" })
ColorSetting("general.highlightColor", "Mouseover Highlight Color", {
    "mouseover highlight color", "hover highlight color", "unitframe highlight color",
}, function()
    local color = GeneralDB().highlightColor
    if type(color) == "table" then return TableRGB(GeneralDB(), "highlightColor", 1, 1, 1) end
    local r, g, b = ColorFromName(color or "white")
    return r or 1, g or 1, b or 1
end, function(r, g, b)
    GeneralDB().highlightColor = { r, g, b }
end, { category = "Colors / Mouseover Highlight", attribute = "mouseoverHighlightColor", apply = ApplyColors })
ColorSetting("general.bossTargetHighlightColor", "Boss Target Highlight Color", {
    "boss target highlight color", "boss target color", "boss target border highlight color",
}, function()
    return TableRGB(GeneralDB(), "bossTargetHighlightColor", 1, 0.82, 0)
end, function(r, g, b)
    SetTableRGB(GeneralDB(), "bossTargetHighlightColor", r, g, b)
end, { category = "Colors / Mouseover Highlight", attribute = "bossTargetHighlightColor", defaultR = 1, defaultG = 0.82, defaultB = 0, apply = ApplyColors })

ColorSetting("gameplay.combatTimerColor", "Combat Timer Text Color", {
    "combat timer text color", "combat timer color",
}, function()
    return TableRGB(GameplayDB(), "combatTimerColor", 1, 1, 1)
end, function(r, g, b)
    SetTableRGB(GameplayDB(), "combatTimerColor", r, g, b)
end, { category = "Colors / Gameplay", frameType = "gameplay", attribute = "combatTimerColor", apply = ApplyGameplayColors })
ColorSetting("gameplay.combatStateEnterColor", "Combat Enter Text Color", {
    "combat enter text color", "combat enter color", "combat state enter color",
}, function()
    return TableRGB(GameplayDB(), "combatStateEnterColor", 1, 1, 1)
end, function(r, g, b)
    local gp = GameplayDB()
    SetTableRGB(gp, "combatStateEnterColor", r, g, b)
    if gp.combatStateColorSync then SetTableRGB(gp, "combatStateLeaveColor", r, g, b) end
end, { category = "Colors / Gameplay", frameType = "gameplay", attribute = "combatStateEnterColor", apply = ApplyGameplayColors })
ColorSetting("gameplay.combatStateLeaveColor", "Combat Leave Text Color", {
    "combat leave text color", "combat leave color", "combat state leave color",
}, function()
    return TableRGB(GameplayDB(), "combatStateLeaveColor", 0.7, 0.7, 0.7)
end, function(r, g, b)
    SetTableRGB(GameplayDB(), "combatStateLeaveColor", r, g, b)
end, { category = "Colors / Gameplay", frameType = "gameplay", attribute = "combatStateLeaveColor", defaultR = 0.7, defaultG = 0.7, defaultB = 0.7, apply = ApplyGameplayColors })
RegisterGameplayBoolean("combatStateColorSync", "combatStateColorSync", "Sync Combat State Colors", false, {
    "sync combat state colors", "sync combat enter leave colors", "same combat state colors",
}, { category = "Colors / Gameplay", frameType = "gameplay", apply = ApplyGameplayColors, reason = "MSUF_ASSISTANT_COMBAT_STATE_COLOR_SYNC" })
ColorSetting("gameplay.crosshairInRangeColor", "Crosshair In-Range Color", {
    "crosshair in range color", "combat crosshair in range color", "melee range in color",
}, function()
    return TableRGB(GameplayDB(), "crosshairInRangeColor", 0, 1, 0)
end, function(r, g, b)
    SetTableRGB(GameplayDB(), "crosshairInRangeColor", r, g, b)
end, { category = "Colors / Gameplay", frameType = "gameplay", attribute = "crosshairInRangeColor", defaultR = 0, defaultG = 1, defaultB = 0, apply = ApplyGameplayColors })
ColorSetting("gameplay.crosshairOutRangeColor", "Crosshair Out-of-Range Color", {
    "crosshair out of range color", "crosshair out-of-range color", "combat crosshair out range color", "melee range out color",
}, function()
    return TableRGB(GameplayDB(), "crosshairOutRangeColor", 1, 0, 0)
end, function(r, g, b)
    SetTableRGB(GameplayDB(), "crosshairOutRangeColor", r, g, b)
end, { category = "Colors / Gameplay", frameType = "gameplay", attribute = "crosshairOutRangeColor", defaultR = 1, defaultG = 0, defaultB = 0, apply = ApplyGameplayColors })

local COLOR_POWER_TOKENS = {
    { key = "MANA", label = "Mana" },
    { key = "RAGE", label = "Rage" },
    { key = "ENERGY", label = "Energy" },
    { key = "FOCUS", label = "Focus" },
    { key = "RUNIC_POWER", label = "Runic Power" },
    { key = "INSANITY", label = "Insanity" },
    { key = "FURY", label = "Fury" },
    { key = "PAIN", label = "Pain" },
    { key = "ESSENCE", label = "Essence" },
    { key = "LUNAR_POWER", label = "Astral Power" },
    { key = "MAELSTROM", label = "Maelstrom" },
}
A.PowerColorTokens = COLOR_POWER_TOKENS
for i = 1, #COLOR_POWER_TOKENS do
    local token = COLOR_POWER_TOKENS[i].key
    local label = COLOR_POWER_TOKENS[i].label
    local lower = label:lower()
    local aliases = { lower .. " power color", lower .. " bar color", lower .. " resource color" }
    if token ~= "FOCUS" then aliases[#aliases + 1] = lower .. " color" end
    ColorSetting("general.powerColorOverrides." .. token, label .. " Power Bar Color", aliases, function()
        return PowerOverrideRGB(token)
    end, function(r, g, b)
        SetPowerOverrideRGB(token, r, g, b)
    end, { category = "Colors / Power", attribute = "powerColor", apply = ApplyColors })
end

local function KnownPowerColorToken(token)
    token = tostring(token or ""):upper():gsub("%s+", "_")
    for i = 1, #COLOR_POWER_TOKENS do
        local row = COLOR_POWER_TOKENS[i]
        if row.key == token then return row.key, row.label end
    end
    return nil, nil
end

Registry:RegisterAction({
    key = "reset_power_color_token",
    label = "Reset Power Bar Token Color",
    type = "color",
    combatSafe = false,
    captureSnapshot = true,
    run = function(args)
        local token, label = KnownPowerColorToken(args and args.token)
        if not token then return false, "I need a known power color token." end
        EnsurePowerOverrides()[token] = nil
        ApplyColors("MSUF_ASSISTANT_RESET_POWER_COLOR_TOKEN")
        return true, "Done. Reset " .. tostring(label) .. " power bar color."
    end,
})

local COLOR_CP_TOKENS = {
    { key = "COMBO_POINTS", label = "Combo Points" },
    { key = "HOLY_POWER", label = "Holy Power" },
    { key = "SOUL_SHARDS", label = "Soul Shards" },
    { key = "CHI", label = "Chi" },
    { key = "ARCANE_CHARGES", label = "Arcane Charges" },
    { key = "RUNES", label = "Runes" },
    { key = "ESSENCE", label = "Essence" },
    { key = "CHARGED", label = "Empowered / Charged" },
    { key = "SOUL_FRAGMENTS", label = "Soul Fragments" },
    { key = "SOUL_FRAGMENTS_META", label = "Soul Fragments Void Meta" },
    { key = "MAELSTROM", label = "Maelstrom Weapon" },
    { key = "MAELSTROM_ABOVE_5", label = "Maelstrom Weapon 5+" },
    { key = "ASTRAL_POWER", label = "Astral Power" },
    { key = "AP_PREDICTION", label = "Astral Prediction" },
    { key = "ECLIPSE_SOLAR", label = "Eclipse Solar" },
    { key = "ECLIPSE_LUNAR", label = "Eclipse Lunar" },
    { key = "ECLIPSE_CA", label = "Celestial Alignment" },
    { key = "STAGGER_GREEN", label = "Stagger Light" },
    { key = "STAGGER_YELLOW", label = "Stagger Moderate" },
    { key = "STAGGER_RED", label = "Stagger Heavy" },
    { key = "SOUL_FRAGMENTS_VENG", label = "Soul Fragments Vengeance" },
    { key = "INSANITY", label = "Insanity" },
    { key = "MAELSTROM_POWER", label = "Maelstrom Power" },
    { key = "WHIRLWIND", label = "Whirlwind" },
    { key = "TIP_OF_THE_SPEAR", label = "Tip of the Spear" },
    { key = "ICICLES", label = "Icicles" },
    { key = "EBON_MIGHT", label = "Ebon Might" },
    { key = "RESOURCE_TEXT", label = "Resource Text" },
}
A.ClassPowerColorTokens = COLOR_CP_TOKENS

local function AddUniqueAlias(out, seen, value)
    value = tostring(value or ""):lower():gsub("^%s+", ""):gsub("%s+$", "")
    if value ~= "" and not seen[value] then
        seen[value] = true
        out[#out + 1] = value
    end
end

local function ClassPowerColorExactAliases(label, background)
    local lower = tostring(label or ""):lower()
    local out, seen = {}, {}
    if background then
        AddUniqueAlias(out, seen, "set " .. lower .. " background color")
        AddUniqueAlias(out, seen, "set " .. lower .. " background")
        AddUniqueAlias(out, seen, "set " .. lower .. " resource background")
        AddUniqueAlias(out, seen, "make " .. lower .. " background color")
        AddUniqueAlias(out, seen, "make " .. lower .. " background")
    else
        AddUniqueAlias(out, seen, "set " .. lower .. " color")
        AddUniqueAlias(out, seen, "set " .. lower .. " class resource color")
        AddUniqueAlias(out, seen, "set " .. lower .. " resource color")
        AddUniqueAlias(out, seen, "make " .. lower .. " color")
        AddUniqueAlias(out, seen, "make " .. lower)
    end
    return out
end

local function ComboPointSlotColorExactAliases(slot)
    local out, seen = {}, {}
    local n = tostring(slot)
    AddUniqueAlias(out, seen, "set combo point slot " .. n)
    AddUniqueAlias(out, seen, "set combo point slot " .. n .. " color")
    AddUniqueAlias(out, seen, "set combo point " .. n)
    AddUniqueAlias(out, seen, "set combo point " .. n .. " color")
    AddUniqueAlias(out, seen, "set cp " .. n)
    AddUniqueAlias(out, seen, "make combo point slot " .. n)
    AddUniqueAlias(out, seen, "make combo point " .. n)
    AddUniqueAlias(out, seen, "make cp " .. n)
    return out
end

for i = 1, #COLOR_CP_TOKENS do
    local token = COLOR_CP_TOKENS[i].key
    local label = COLOR_CP_TOKENS[i].label
    local lower = label:lower()
    ColorSetting("general.classPowerColorOverrides." .. token, label .. " Color", {
        lower .. " color", lower .. " class power color", lower .. " class resource color", lower .. " resource color",
    }, function()
        return ClassPowerRGB(token)
    end, function(r, g, b)
        SetClassPowerRGB(token, r, g, b)
    end, {
        category = "Colors / Class Power",
        attribute = "classPowerColor",
        apply = ApplyClassPowerColors,
        exactAliases = ClassPowerColorExactAliases(label, false),
    })
    ColorSetting("general.classPowerBgColorOverrides." .. token, label .. " Background Color", {
        lower .. " background color", lower .. " class power background color", lower .. " resource background color",
    }, function()
        return ClassPowerBgRGB(token)
    end, function(r, g, b)
        SetClassPowerBgRGB(token, r, g, b)
    end, {
        category = "Colors / Class Power",
        attribute = "classPowerBackgroundColor",
        defaultR = 0,
        defaultG = 0,
        defaultB = 0,
        apply = ApplyClassPowerColors,
        exactAliases = ClassPowerColorExactAliases(label, true),
    })
end
for i = 1, 7 do
    local token = "COMBO_POINTS_" .. tostring(i)
    ColorSetting("general.classPowerColorOverrides." .. token, "Combo Point " .. tostring(i) .. " Color", {
        "combo point " .. tostring(i), "combo point " .. tostring(i) .. " color",
        "combo point slot " .. tostring(i), "combo point slot " .. tostring(i) .. " color",
        "cp " .. tostring(i), "cp " .. tostring(i) .. " color",
    }, function()
        return ClassPowerRGB(token)
    end, function(r, g, b)
        BarsDB().classPowerComboPointColorMode = "custom"
        SetClassPowerRGB(token, r, g, b)
    end, {
        category = "Colors / Class Power",
        attribute = "comboPointSlotColor",
        apply = ApplyClassPowerColors,
        exactAliases = ComboPointSlotColorExactAliases(i),
    })
end

local function KnownClassPowerColorToken(token)
    token = tostring(token or "")
    for i = 1, #COLOR_CP_TOKENS do
        if COLOR_CP_TOKENS[i].key == token then return token, COLOR_CP_TOKENS[i].label end
    end
    for i = 1, 7 do
        local slot = "COMBO_POINTS_" .. tostring(i)
        if token == slot then return token, "Combo Point " .. tostring(i) end
    end
    return nil, nil
end

Registry:RegisterAction({
    key = "reset_class_power_color_token",
    label = "Reset Class Resource Token Color",
    type = "color",
    combatSafe = false,
    captureSnapshot = true,
    run = function(args)
        local token, label = KnownClassPowerColorToken(args and args.token)
        if not token then return false, "I need a known Class Resource color token." end
        local g = EnsureClassPowerOverrides()
        if args and args.background then
            g.classPowerBgColorOverrides[token] = nil
            ApplyClassPowerColors("MSUF_ASSISTANT_RESET_CLASS_POWER_BG_COLOR")
            return true, "Done. Reset " .. tostring(label) .. " background color."
        end
        g.classPowerColorOverrides[token] = nil
        ApplyClassPowerColors("MSUF_ASSISTANT_RESET_CLASS_POWER_COLOR")
        return true, "Done. Reset " .. tostring(label) .. " color."
    end,
})

Registry:RegisterAction({
    key = "reset_class_power_combo_slot_colors",
    label = "Reset Combo Point Slot Colors",
    type = "color",
    combatSafe = false,
    captureSnapshot = true,
    run = function()
        local g = EnsureClassPowerOverrides()
        for i = 1, 7 do g.classPowerColorOverrides["COMBO_POINTS_" .. tostring(i)] = nil end
        ApplyClassPowerColors("MSUF_ASSISTANT_RESET_COMBO_POINT_SLOT_COLORS")
        return true, "Done. Reset combo point slot colors."
    end,
})

ColorSetting("general.aurasOwnBuffHighlightColor", "Own Buff Highlight Color", {
    "own buff highlight color", "my buff highlight color", "aura own buff color", "own buff aura highlight color", "buff aura highlight color",
}, function()
    return TableRGB(GeneralDB(), "aurasOwnBuffHighlightColor", 1, 0.85, 0.2)
end, function(r, g, b)
    SetTableRGB(GeneralDB(), "aurasOwnBuffHighlightColor", r, g, b)
end, { category = "Colors / Auras", attribute = "ownBuffHighlightColor", defaultR = 1, defaultG = 0.85, defaultB = 0.2, apply = ApplyAuraColors,
    exactAliases = { "own buff highlight color", "my buff highlight color", "aura own buff color", "own buff aura highlight color", "buff aura highlight color" } })
ColorSetting("general.aurasOwnDebuffHighlightColor", "Own Debuff Highlight Color", {
    "own debuff highlight color", "my debuff highlight color", "aura own debuff color", "own debuff aura highlight color", "debuff aura highlight color",
}, function()
    return TableRGB(GeneralDB(), "aurasOwnDebuffHighlightColor", 1, 0.30, 0.30)
end, function(r, g, b)
    SetTableRGB(GeneralDB(), "aurasOwnDebuffHighlightColor", r, g, b)
end, { category = "Colors / Auras", attribute = "ownDebuffHighlightColor", defaultR = 1, defaultG = 0.30, defaultB = 0.30, apply = ApplyAuraColors,
    exactAliases = { "own debuff highlight color", "my debuff highlight color", "aura own debuff color", "own debuff aura highlight color", "debuff aura highlight color" } })
ColorSetting("general.aurasStackCountColor", "Aura Stack Count Text Color", {
    "stack count text color", "aura stack color", "aura stack count color", "aura stacks color", "aura stack text color", "aura count color",
}, function()
    return TableRGB(GeneralDB(), "aurasStackCountColor", 1, 1, 1)
end, function(r, g, b)
    SetTableRGB(GeneralDB(), "aurasStackCountColor", r, g, b)
end, { category = "Colors / Auras", attribute = "auraStackColor", apply = ApplyAuraColors,
    exactAliases = { "stack count text color", "aura stack color", "aura stack count color", "aura stacks color", "aura stack text color", "aura count color" } })
ColorSetting("auras3.shared.pandemicColor", "Pandemic Window Color", {
    "pandemic window color", "pandemic color", "aura pandemic color",
}, function()
    local sh = AuraSharedDB()
    return tonumber(sh.pandemicR) or 0, tonumber(sh.pandemicG) or 0.4, tonumber(sh.pandemicB) or 1
end, function(r, g, b)
    local sh = AuraSharedDB()
    sh.pandemicR, sh.pandemicG, sh.pandemicB = r, g, b
end, { category = "Colors / Auras", attribute = "pandemicColor", defaultR = 0, defaultG = 0.4, defaultB = 1, apply = ApplyAuraColors })
RegisterGeneralBoolean("aurasCooldownTextUseBuckets", "auraCooldownBuckets", "Color Aura Timers By Remaining Time", false, {
    "color aura timers by remaining time", "aura timer bucket colors", "aura timer color buckets", "aura cooldown bucket colors", "aura cooldown color buckets", "aura cooldown buckets", "aura timer buckets",
}, { category = "Colors / Auras", frameType = "colors", apply = ApplyAuraColors, reason = "MSUF_ASSISTANT_AURA_TIMER_BUCKETS",
    exactAliases = { "color aura timers by remaining time", "aura timer bucket colors", "aura timer color buckets", "aura cooldown bucket colors", "aura cooldown color buckets", "aura cooldown buckets", "aura timer buckets" } })
for _, row in ipairs({
    { key = "aurasCooldownTextSafeColor", label = "Aura Cooldown Safe Text Color", dr = 1, dg = 1, db = 1, aliases = { "aura cooldown safe color", "aura cooldown safe text color", "cooldown text safe color", "aura timer safe color", "aura safe timer color", "safe aura timer color" } },
    { key = "aurasCooldownTextWarningColor", label = "Aura Cooldown Warning Text Color", dr = 1, dg = 0.85, db = 0.2, aliases = { "aura cooldown warning color", "aura cooldown warning text color", "cooldown text warning color", "aura timer warning color", "aura warning timer color", "warning aura timer color" } },
    { key = "aurasCooldownTextUrgentColor", label = "Aura Cooldown Urgent Text Color", dr = 1, dg = 0.55, db = 0.1, aliases = { "aura cooldown urgent color", "aura cooldown urgent text color", "cooldown text urgent color", "aura timer urgent color", "aura urgent timer color", "urgent aura timer color" } },
}) do
    ColorSetting("general." .. row.key, row.label, row.aliases, function()
        return TableRGB(GeneralDB(), row.key, row.dr, row.dg, row.db)
    end, function(r, g, b)
        SetTableRGB(GeneralDB(), row.key, r, g, b)
    end, { category = "Colors / Auras", attribute = row.key, defaultR = row.dr, defaultG = row.dg, defaultB = row.db, apply = ApplyAuraColors, exactAliases = row.aliases })
end
for _, row in ipairs({
    { key = "aurasCooldownTextSafeSeconds", attr = "auraCooldownTextSafeSeconds", label = "Aura Cooldown Safe Seconds", defaultValue = 60, minValue = 0, maxValue = 600, aliases = { "aura cooldown safe seconds", "aura timer safe seconds", "aura safe seconds", "safe aura seconds", "safe aura timer threshold", "aura safe timer threshold" } },
    { key = "aurasCooldownTextWarningSeconds", attr = "auraCooldownTextWarningSeconds", label = "Aura Cooldown Warning Seconds", defaultValue = 15, minValue = 0, maxValue = 30, aliases = { "aura cooldown warning seconds", "aura timer warning seconds", "aura warning seconds", "warning aura seconds", "warning aura timer threshold", "aura warning timer threshold" } },
    { key = "aurasCooldownTextUrgentSeconds", attr = "auraCooldownTextUrgentSeconds", label = "Aura Cooldown Urgent Seconds", defaultValue = 5, minValue = 0, maxValue = 15, aliases = { "aura cooldown urgent seconds", "aura timer urgent seconds", "aura urgent seconds", "urgent aura seconds", "urgent aura timer threshold", "aura urgent timer threshold" } },
}) do
    RegisterGeneralNumberSetting(row.key, row.attr, row.label, row.defaultValue, row.minValue, row.maxValue, row.aliases, {
        category = "Colors / Auras",
        frameType = "colors",
        apply = ApplyAuraColors,
        reason = "MSUF_ASSISTANT_AURA_TIMER_THRESHOLDS",
        description = "Aura cooldown text bucket threshold.",
        exactAliases = row.aliases,
    })
end

ColorSetting("general.portraitBorderColor", "Portrait Border Color", {
    "portrait border color", "portrait custom border color",
}, function()
    return GeneralRGB("portraitBorderColor", 1, 1, 1)
end, function(r, g, b)
    SetAllPortraitRGB("portraitBorderColor", r, g, b)
end, { category = "Colors / Portrait", attribute = "portraitBorderColor", apply = ApplyPortraitColors })
ColorSetting("general.portraitBgColor", "Portrait Background Color", {
    "portrait background color", "portrait bg color",
}, function()
    return GeneralRGB("portraitBgColor", 0.05, 0.05, 0.05)
end, function(r, g, b)
    SetAllPortraitRGB("portraitBgColor", r, g, b)
end, { category = "Colors / Portrait", attribute = "portraitBackgroundColor", defaultR = 0.05, defaultG = 0.05, defaultB = 0.05, apply = ApplyPortraitColors })
end

A.GlobalRegistry = A.GlobalRegistry or {}
A.GlobalRegistry.ColorResetActions = {
    Registry = Registry,
    GeneralDB = GeneralDB,
    GameplayDB = GameplayDB,
    ColorAPI = ColorAPI,
    ApplyColors = ApplyColors,
    ApplyCastbarColors = ApplyCastbarColors,
    ApplyGameplayColors = ApplyGameplayColors,
    ApplyAuraColors = ApplyAuraColors,
    ApplyPortraitColors = ApplyPortraitColors,
    ApplyClassPowerColors = ApplyClassPowerColors,
    AuraSharedDB = AuraSharedDB,
    SetAllPortraitRGB = SetAllPortraitRGB,
}
RegisterAssistantColorSettings()
end
