local addonName, NS = ...

-- ============================================================================
-- VAULTSKINS: CORE AND SAVED VARIABLES
-- ============================================================================

local L = NS.L or {}
local ADDON_VERSION = "1.1.3"
local CURRENT_SETTINGS_VERSION = 50

NS.VERSION = ADDON_VERSION
NS.SETTINGS_VERSION = CURRENT_SETTINGS_VERSION

local rawTimerAfter = C_Timer and C_Timer.After
local function ScheduleTask(key, delay, callback)
    if NS.Stability and NS.Stability.Schedule then
        return NS.Stability:Schedule(key, delay, callback)
    end
    if rawTimerAfter then return rawTimerAfter(math.max(0, tonumber(delay) or 0), callback) end
    return callback()
end

-- ==================== DEFAULT SETTINGS AND VALID VALUES =====================
local defaults = {
    theme = "Midnight",
    scale = 1,
    autoFit = true,
    animations = true,
    sounds = true,
    soundStyle = "balanced",
    soundSync = true,
    openingSounds = true,
    frameDetailSounds = true,
    frameSounds = true,
    rewardSounds = true,
    finalSounds = true,
    rewardRarityEffects = true,
    rewardItemLevelGlow = true,
    rewardSpecialAnimations = true,
    rewardJackpotEffects = true,
    rewardImportanceSounds = true,
    revealSpeed = "normal",
    revealMode = "sequential",
    finalFlourish = true,
    compatibilityMode = "auto",
    skinEnabled = true,
    themeMode = "account",
    characterThemes = {},
    customThemeEnabled = false,
    customColors = {},
    animationPreset = "standard",
    soundIntensity = "normal",
    frameAnimationMode = "full",
    framePreset = "standard",
    frameOpeningAnimation = true,
    frameIdleAnimation = true,
    frameCrestEffects = true,
    frameBorderFlow = true,
    frameCornerEffects = true,
    frameParticles = false,
    frameIntensity = 1.00,
    frameEffectSpeed = "normal",
    backgroundSceneStyle = "animated",
    backgroundScenes = true,
    backgroundMotion = true,
    backgroundParticles = false,
    backgroundIntensity = 0.55,
    backgroundPerformance = "low",
    layoutStyle = "classic",
    optionsPosition = nil,
    settingsVersion = CURRENT_SETTINGS_VERSION,
}
NS.Defaults = defaults

local validSpeeds = { fast = true, normal = true, cinematic = true }
local validModes = { sequential = true, rows = true, rewardslast = true, random = true, click = true, jackpot = true }
local validCompatibility = { auto = true, native = true, minimal = true }
local validThemeModes = { account = true, character = true, class = true }
local validAnimationPresets = { fast = true, standard = true, pulse = true, spotlight = true, cinematic = true, off = true }
local validSoundIntensity = { quiet = true, normal = true, full = true }
local validSoundStyles = { off = true, subtle = true, balanced = true, cinematic = true, custom = true }
local validFrameAnimationModes = { off = true, subtle = true, full = true }
local validFramePresets = { off = true, subtle = true, standard = true, cinematic = true, custom = true }
local validFrameEffectSpeeds = { fast = true, normal = true, cinematic = true }
local validBackgroundPerformance = { low = true, balanced = true, full = true }
local validBackgroundSceneStyles = { off = true, subtle = true, animated = true, cinematic = true }
local validLayoutStyles = { wide = true, classic = true, cinematic = true }

local modeAliases = {
    ["rewards-last"] = "rewardslast",
    ["reward-last"] = "rewardslast",
    reward = "rewardslast",
    row = "rows",
    interactive = "click",
    slot = "jackpot",
    slots = "jackpot",
}

local function Clamp(value, minimum, maximum)
    value = tonumber(value) or minimum
    return math.max(minimum, math.min(maximum, value))
end

local function NormalizeMode(value)
    value = string.lower(strtrim(tostring(value or "")))
    value = modeAliases[value] or value
    return validModes[value] and value or nil
end

local function CopyDefaults()
    for key, value in pairs(defaults) do
        if VaultSkinsDB[key] == nil then
            VaultSkinsDB[key] = type(value) == "table" and {} or value
        end
    end
end

-- ======================== SAVED-VARIABLE MIGRATIONS =========================
-- Keep released migration steps in ascending version order.
local function MigrateLegacy_v17_to_v32(previousVersion)
    if previousVersion < 17 and VaultSkinsDB.animations == nil then
        VaultSkinsDB.animations = true
    end
    if previousVersion < 18 then
        VaultSkinsDB.autoFit = true
        VaultSkinsDB.compatibilityMode = "auto"
    end
    if previousVersion < 19 then
        VaultSkinsDB.optionsPosition = nil
    end
    if previousVersion < 20 and VaultSkinsDB.scale then
        VaultSkinsDB.scale = Clamp(VaultSkinsDB.scale, 0.75, 1.25)
    end
    if previousVersion < 21 then
        VaultSkinsDB.skinEnabled = true
    end
    if previousVersion < 22 then
        VaultSkinsDB.themeMode = "account"
        VaultSkinsDB.characterThemes = {}
    end
    if previousVersion < 23 then
        if VaultSkinsDB.animations == false then
            VaultSkinsDB.animationPreset = "off"
        elseif VaultSkinsDB.revealSpeed == "fast" then
            VaultSkinsDB.animationPreset = "fast"
        elseif VaultSkinsDB.revealSpeed == "cinematic" then
            VaultSkinsDB.animationPreset = "cinematic"
        else
            VaultSkinsDB.animationPreset = "standard"
        end
    end
    if previousVersion < 24 then
        VaultSkinsDB.soundIntensity = "normal"
    end
    if previousVersion < 25 and type(VaultSkinsDB.characterThemes) ~= "table" then
        VaultSkinsDB.characterThemes = {}
    end
    if previousVersion < 27 then
        VaultSkinsDB.frameAnimationMode = "full"
        VaultSkinsDB.frameIdleAnimation = true
        VaultSkinsDB.frameParticles = true
    end
    if previousVersion < 29 then
        local oldMode = VaultSkinsDB.frameAnimationMode or "full"
        VaultSkinsDB.framePreset = oldMode == "off" and "off" or (oldMode == "subtle" and "subtle" or "standard")
        VaultSkinsDB.frameOpeningAnimation = oldMode ~= "off"
        VaultSkinsDB.frameCrestEffects = oldMode ~= "off"
        VaultSkinsDB.frameBorderFlow = oldMode ~= "off"
        VaultSkinsDB.frameCornerEffects = oldMode == "full"
        VaultSkinsDB.frameIntensity = oldMode == "subtle" and 0.65 or 1.00
        VaultSkinsDB.frameEffectSpeed = "normal"
    end
    if previousVersion < 30 then
        VaultSkinsDB.soundSync = true
        VaultSkinsDB.frameSounds = true
        VaultSkinsDB.rewardSounds = true
        VaultSkinsDB.finalSounds = true
    end
    if previousVersion < 31 then
        VaultSkinsDB.backgroundScenes = true
        VaultSkinsDB.backgroundMotion = true
        VaultSkinsDB.backgroundParticles = true
        VaultSkinsDB.backgroundIntensity = 0.65
        VaultSkinsDB.backgroundPerformance = "balanced"
    end
    if previousVersion < 32 then
        VaultSkinsDB.layoutStyle = "classic"
    end
end

local function MigrateRevealSettings_v33_to_v39(previousVersion)
    if previousVersion >= 33 and previousVersion < 35 then
        VaultSkinsDB.revealStyle = nil
        VaultSkinsDB.revealMode = "sequential"
        VaultSkinsDB.revealSpeed = "normal"
        VaultSkinsDB.animations = true
        VaultSkinsDB.animationPreset = "standard"
    end

    if previousVersion < 36 then
        VaultSkinsDB.revealStyle = nil
    end
    if previousVersion < 37 then
        VaultSkinsDB.rewardRarityEffects = true
        VaultSkinsDB.rewardItemLevelGlow = true
        VaultSkinsDB.rewardSpecialAnimations = true
        VaultSkinsDB.rewardJackpotEffects = true
        VaultSkinsDB.rewardImportanceSounds = true
    end
    if previousVersion < 39 then
        if VaultSkinsDB.layoutStyle == "compact" or VaultSkinsDB.layoutStyle == "minimal" then
            VaultSkinsDB.layoutStyle = "classic"
        end
        VaultSkinsDB.revealStyle = nil
        VaultSkinsDB.statusTab = nil
    end
end

local function MigrateRecent_v40_to_v50(previousVersion)
    if previousVersion < 40 then
        if VaultSkinsDB.backgroundPerformance == nil or VaultSkinsDB.backgroundPerformance == "balanced" then
            VaultSkinsDB.backgroundPerformance = "low"
        end
        if VaultSkinsDB.backgroundParticles == nil or VaultSkinsDB.backgroundParticles == true then
            VaultSkinsDB.backgroundParticles = false
        end
        if VaultSkinsDB.backgroundIntensity == nil or VaultSkinsDB.backgroundIntensity > 0.55 then
            VaultSkinsDB.backgroundIntensity = 0.55
        end
    end
    if previousVersion < 41 then
        VaultSkinsDB.customThemeEnabled = false
        VaultSkinsDB.customColors = {}
    end
    if previousVersion < 42 and type(VaultSkinsDB.customColors) == "table" then
        local colors = VaultSkinsDB.customColors
        colors.cardBorder = colors.cardBorder or colors.border
        colors.frameBorder = colors.frameBorder or colors.border
        colors.selectionAccent = colors.selectionAccent or colors.accent
        colors.frameAccent = colors.frameAccent or colors.accent
        colors.locked = colors.locked or colors.card
        colors.unlocked = colors.unlocked or colors.card
        colors.card = nil
        colors.border = nil
        colors.accent = nil
    end
    if previousVersion < 43 and type(VaultSkinsDB.customColors) == "table" then
        local colors = VaultSkinsDB.customColors
        colors.outerGlow = colors.outerGlow or colors.frameAccent or colors.glow
    end
    if previousVersion < 44 then
        if VaultSkinsDB.backgroundScenes == false then
            VaultSkinsDB.backgroundSceneStyle = "off"
        elseif VaultSkinsDB.backgroundMotion == false then
            VaultSkinsDB.backgroundSceneStyle = "subtle"
        elseif VaultSkinsDB.backgroundPerformance == "full" and VaultSkinsDB.backgroundParticles ~= false then
            VaultSkinsDB.backgroundSceneStyle = "cinematic"
        else
            VaultSkinsDB.backgroundSceneStyle = "animated"
        end
    end
    if previousVersion < 45 and VaultSkinsDB.framePreset == "custom" then
        if VaultSkinsDB.frameAnimationMode == "off" then
            VaultSkinsDB.framePreset = "off"
        elseif VaultSkinsDB.frameAnimationMode == "subtle" or (VaultSkinsDB.frameIntensity or 1) <= 0.75 then
            VaultSkinsDB.framePreset = "subtle"
        elseif (VaultSkinsDB.frameIntensity or 1) >= 1.15 and VaultSkinsDB.frameCornerEffects and VaultSkinsDB.frameParticles then
            VaultSkinsDB.framePreset = "cinematic"
        else
            VaultSkinsDB.framePreset = "standard"
        end
    end
    if previousVersion < 46 then
        VaultSkinsDB.soundPack = "theme"
        VaultSkinsDB.openingSounds = VaultSkinsDB.frameSounds ~= false
        VaultSkinsDB.frameDetailSounds = VaultSkinsDB.frameSounds ~= false
        if VaultSkinsDB.sounds == false then
            VaultSkinsDB.soundStyle = "off"
        elseif VaultSkinsDB.soundIntensity == "quiet" then
            VaultSkinsDB.soundStyle = "subtle"
        elseif VaultSkinsDB.soundIntensity == "full" then
            VaultSkinsDB.soundStyle = "cinematic"
        else
            VaultSkinsDB.soundStyle = "balanced"
        end
    end
    if previousVersion < 47 then
        VaultSkinsDB.revealStyle = nil
        VaultSkinsDB.statusTab = nil
        if VaultSkinsDB.framePreset == "standard" and VaultSkinsDB.frameParticles == nil then
            VaultSkinsDB.frameParticles = false
        end
    end
    if previousVersion < 50 then
        VaultSkinsDB.soundPack = nil
    end
end

local function MigrateDatabase(previousVersion)
    MigrateLegacy_v17_to_v32(previousVersion)
    MigrateRevealSettings_v33_to_v39(previousVersion)
    MigrateRecent_v40_to_v50(previousVersion)
end

-- ======================= THEME AND COLOR SANITIZATION =======================
-- Retired IDs remain as aliases so older saved profiles still load safely.
local THEME_MIGRATIONS = {
    ScarletCrusade = "Sunwell",
    BlackEmpire = "Void",
    Ardenweald = "Elune",
    AbyssalPurple = "ObsidianPurple",
}

local function NormalizeThemeID(themeID)
    themeID = type(themeID) == "string" and themeID or nil
    if not themeID then return defaults.theme end
    themeID = THEME_MIGRATIONS[themeID] or themeID
    if NS.ThemeEngine and NS.ThemeEngine:IsRegistered(themeID) then
        return themeID
    end
    return defaults.theme
end

local function SanitizeCharacterThemes()
    if type(VaultSkinsDB.characterThemes) ~= "table" then
        VaultSkinsDB.characterThemes = {}
        return
    end
    for characterKey, themeID in pairs(VaultSkinsDB.characterThemes) do
        if type(characterKey) ~= "string" then
            VaultSkinsDB.characterThemes[characterKey] = nil
        else
            VaultSkinsDB.characterThemes[characterKey] = NormalizeThemeID(themeID)
        end
    end
end

local CUSTOM_COLOR_KEYS = {
    "background", "panel", "locked", "reward", "unlocked",
    "cardBorder", "selectionAccent", "frameBorder", "frameAccent",
    "outerGlow", "glow", "artTint", "scenePrimary", "sceneSecondary",
}

local function SanitizeCustomColor(value)
    if type(value) ~= "table" then return nil end
    local r, g, b = tonumber(value.r), tonumber(value.g), tonumber(value.b)
    if not r or not g or not b then return nil end
    return {
        r = Clamp(r, 0, 1),
        g = Clamp(g, 0, 1),
        b = Clamp(b, 0, 1),
        a = Clamp(tonumber(value.a) or 1, 0, 1),
    }
end

local function SanitizeCustomColors()
    VaultSkinsDB.customThemeEnabled = VaultSkinsDB.customThemeEnabled == true
    if type(VaultSkinsDB.customColors) ~= "table" then VaultSkinsDB.customColors = {} end
    local cleaned = {}
    for _, key in ipairs(CUSTOM_COLOR_KEYS) do
        local color = SanitizeCustomColor(VaultSkinsDB.customColors[key])
        if color then cleaned[key] = color end
    end
    VaultSkinsDB.customColors = cleaned
end

-- ========================= DATABASE INITIALIZATION ==========================
local function InitializeDatabase()
    if type(VaultSkinsDB) ~= "table" then
        VaultSkinsDB = {}
    end

    local previousVersion = tonumber(VaultSkinsDB.settingsVersion) or 0
    MigrateDatabase(previousVersion)
    CopyDefaults()

    VaultSkinsDB.theme = NormalizeThemeID(VaultSkinsDB.theme)

    VaultSkinsDB.scale = Clamp(VaultSkinsDB.scale, 0.75, 1.25)
    VaultSkinsDB.autoFit = VaultSkinsDB.autoFit ~= false
    VaultSkinsDB.animations = VaultSkinsDB.animations ~= false
    VaultSkinsDB.sounds = VaultSkinsDB.sounds ~= false
    VaultSkinsDB.soundStyle = validSoundStyles[VaultSkinsDB.soundStyle] and VaultSkinsDB.soundStyle or defaults.soundStyle
    VaultSkinsDB.soundSync = VaultSkinsDB.soundSync ~= false
    VaultSkinsDB.openingSounds = VaultSkinsDB.openingSounds ~= false
    VaultSkinsDB.frameDetailSounds = VaultSkinsDB.frameDetailSounds ~= false
    VaultSkinsDB.frameSounds = VaultSkinsDB.frameSounds ~= false
    VaultSkinsDB.rewardSounds = VaultSkinsDB.rewardSounds ~= false
    VaultSkinsDB.finalSounds = VaultSkinsDB.finalSounds ~= false
    VaultSkinsDB.rewardRarityEffects = VaultSkinsDB.rewardRarityEffects ~= false
    VaultSkinsDB.rewardItemLevelGlow = VaultSkinsDB.rewardItemLevelGlow ~= false
    VaultSkinsDB.rewardSpecialAnimations = VaultSkinsDB.rewardSpecialAnimations ~= false
    VaultSkinsDB.rewardJackpotEffects = VaultSkinsDB.rewardJackpotEffects ~= false
    VaultSkinsDB.rewardImportanceSounds = VaultSkinsDB.rewardImportanceSounds ~= false
    VaultSkinsDB.finalFlourish = VaultSkinsDB.finalFlourish ~= false
    VaultSkinsDB.revealSpeed = validSpeeds[VaultSkinsDB.revealSpeed] and VaultSkinsDB.revealSpeed or defaults.revealSpeed
    VaultSkinsDB.revealMode = NormalizeMode(VaultSkinsDB.revealMode) or defaults.revealMode
    VaultSkinsDB.compatibilityMode = validCompatibility[VaultSkinsDB.compatibilityMode] and VaultSkinsDB.compatibilityMode or defaults.compatibilityMode
    VaultSkinsDB.skinEnabled = VaultSkinsDB.skinEnabled ~= false
    VaultSkinsDB.themeMode = validThemeModes[VaultSkinsDB.themeMode] and VaultSkinsDB.themeMode or defaults.themeMode
    VaultSkinsDB.animationPreset = validAnimationPresets[VaultSkinsDB.animationPreset] and VaultSkinsDB.animationPreset or defaults.animationPreset
    VaultSkinsDB.soundIntensity = validSoundIntensity[VaultSkinsDB.soundIntensity] and VaultSkinsDB.soundIntensity or defaults.soundIntensity
    if VaultSkinsDB.soundStyle == "off" or VaultSkinsDB.sounds == false then
        VaultSkinsDB.soundStyle = "off"
        VaultSkinsDB.sounds = false
    else
        VaultSkinsDB.sounds = true
    end
    VaultSkinsDB.frameAnimationMode = validFrameAnimationModes[VaultSkinsDB.frameAnimationMode] and VaultSkinsDB.frameAnimationMode or defaults.frameAnimationMode
    VaultSkinsDB.framePreset = validFramePresets[VaultSkinsDB.framePreset] and VaultSkinsDB.framePreset or defaults.framePreset
    VaultSkinsDB.frameOpeningAnimation = VaultSkinsDB.frameOpeningAnimation ~= false
    VaultSkinsDB.frameIdleAnimation = VaultSkinsDB.frameIdleAnimation ~= false
    VaultSkinsDB.frameCrestEffects = VaultSkinsDB.frameCrestEffects ~= false
    VaultSkinsDB.frameBorderFlow = VaultSkinsDB.frameBorderFlow ~= false
    VaultSkinsDB.frameCornerEffects = VaultSkinsDB.frameCornerEffects ~= false
    VaultSkinsDB.frameParticles = VaultSkinsDB.frameParticles ~= false
    VaultSkinsDB.frameIntensity = Clamp(VaultSkinsDB.frameIntensity, 0.40, 1.40)
    VaultSkinsDB.frameEffectSpeed = validFrameEffectSpeeds[VaultSkinsDB.frameEffectSpeed] and VaultSkinsDB.frameEffectSpeed or defaults.frameEffectSpeed
    VaultSkinsDB.backgroundSceneStyle = validBackgroundSceneStyles[VaultSkinsDB.backgroundSceneStyle] and VaultSkinsDB.backgroundSceneStyle or defaults.backgroundSceneStyle
    VaultSkinsDB.backgroundScenes = VaultSkinsDB.backgroundScenes ~= false
    VaultSkinsDB.backgroundMotion = VaultSkinsDB.backgroundMotion ~= false
    VaultSkinsDB.backgroundParticles = VaultSkinsDB.backgroundParticles ~= false
    VaultSkinsDB.backgroundIntensity = Clamp(VaultSkinsDB.backgroundIntensity, 0.20, 1.00)
    VaultSkinsDB.backgroundPerformance = validBackgroundPerformance[VaultSkinsDB.backgroundPerformance] and VaultSkinsDB.backgroundPerformance or defaults.backgroundPerformance
    if VaultSkinsDB.backgroundSceneStyle == "off" then
        VaultSkinsDB.backgroundScenes = false
        VaultSkinsDB.backgroundMotion = false
        VaultSkinsDB.backgroundParticles = false
    elseif VaultSkinsDB.backgroundSceneStyle == "subtle" then
        VaultSkinsDB.backgroundScenes = true
        VaultSkinsDB.backgroundMotion = false
        VaultSkinsDB.backgroundParticles = false
    else
        VaultSkinsDB.backgroundScenes = true
        VaultSkinsDB.backgroundMotion = true
    end
    if VaultSkinsDB.rewardRarityEffects == false then
        VaultSkinsDB.rewardItemLevelGlow = false
        VaultSkinsDB.rewardSpecialAnimations = false
        VaultSkinsDB.rewardJackpotEffects = false
    end
    if VaultSkinsDB.layoutStyle == "compact" or VaultSkinsDB.layoutStyle == "minimal" then
        VaultSkinsDB.layoutStyle = "classic"
    end
    VaultSkinsDB.layoutStyle = validLayoutStyles[VaultSkinsDB.layoutStyle] and VaultSkinsDB.layoutStyle or defaults.layoutStyle
    if VaultSkinsDB.framePreset == "off" then
        VaultSkinsDB.frameAnimationMode = "off"
    elseif VaultSkinsDB.framePreset == "subtle" then
        VaultSkinsDB.frameAnimationMode = "subtle"
    elseif VaultSkinsDB.framePreset ~= "custom" then
        VaultSkinsDB.frameAnimationMode = "full"
    end
    SanitizeCharacterThemes()
    SanitizeCustomColors()
    if VaultSkinsDB.animationPreset == "off" then
        VaultSkinsDB.animations = false
    elseif VaultSkinsDB.animationPreset == "fast" then
        VaultSkinsDB.animations, VaultSkinsDB.revealSpeed = true, "fast"
    elseif VaultSkinsDB.animationPreset == "cinematic" then
        VaultSkinsDB.animations, VaultSkinsDB.revealSpeed = true, "cinematic"
    else
        VaultSkinsDB.animations, VaultSkinsDB.revealSpeed = true, "normal"
    end
    if type(VaultSkinsDB.optionsPosition) ~= "table" then
        VaultSkinsDB.optionsPosition = nil
    end
    VaultSkinsDB.settingsVersion = CURRENT_SETTINGS_VERSION
end

-- ======================= ACTIVE THEME AND PRESET API ========================
local function GetCharacterKey()
    local name, realm
    if UnitFullName then name, realm = UnitFullName("player") end
    name = name or (UnitName and UnitName("player")) or "Unknown"
    realm = realm or (GetNormalizedRealmName and GetNormalizedRealmName()) or (GetRealmName and GetRealmName()) or "Unknown"
    return tostring(name) .. "-" .. tostring(realm)
end

function NS:GetCharacterKey()
    return GetCharacterKey()
end

function NS:GetActiveThemeID()
    if not VaultSkinsDB then return "Midnight" end
    if VaultSkinsDB.themeMode == "class" and NS.ThemeEngine and NS.ThemeEngine:IsRegistered("Class") then
        return "Class"
    end
    if VaultSkinsDB.themeMode == "character" then
        local selected = VaultSkinsDB.characterThemes and VaultSkinsDB.characterThemes[GetCharacterKey()]
        if selected and NS.ThemeEngine and NS.ThemeEngine:IsRegistered(selected) then return selected end
    end
    return VaultSkinsDB.theme or "Midnight"
end

function NS:SetActiveThemeID(themeID)
    if not (VaultSkinsDB and NS.ThemeEngine and NS.ThemeEngine:IsRegistered(themeID)) then return false end
    if VaultSkinsDB.themeMode == "character" then
        VaultSkinsDB.characterThemes = type(VaultSkinsDB.characterThemes) == "table" and VaultSkinsDB.characterThemes or {}
        VaultSkinsDB.characterThemes[GetCharacterKey()] = themeID
    elseif VaultSkinsDB.themeMode == "class" then
        VaultSkinsDB.themeMode = "account"
        VaultSkinsDB.theme = themeID
    else
        VaultSkinsDB.theme = themeID
    end
    return true
end

function NS:SetAnimationPreset(preset)
    if not (VaultSkinsDB and validAnimationPresets[preset]) then return false end
    VaultSkinsDB.animationPreset = preset
    if preset == "off" then
        VaultSkinsDB.animations = false
    elseif preset == "fast" then
        VaultSkinsDB.animations, VaultSkinsDB.revealSpeed, VaultSkinsDB.finalFlourish = true, "fast", false
    elseif preset == "cinematic" then
        VaultSkinsDB.animations, VaultSkinsDB.revealSpeed, VaultSkinsDB.finalFlourish = true, "cinematic", true
    else
        VaultSkinsDB.animations, VaultSkinsDB.revealSpeed, VaultSkinsDB.finalFlourish = true, "normal", true
    end
    return true
end

function NS:SetFramePreset(preset)
    if not (VaultSkinsDB and validFramePresets[preset] and preset ~= "custom") then return false end
    VaultSkinsDB.framePreset = preset
    if preset == "off" then
        VaultSkinsDB.frameAnimationMode = "off"
        VaultSkinsDB.frameOpeningAnimation = false
        VaultSkinsDB.frameIdleAnimation = false
        VaultSkinsDB.frameCrestEffects = false
        VaultSkinsDB.frameBorderFlow = false
        VaultSkinsDB.frameCornerEffects = false
        VaultSkinsDB.frameParticles = false
        VaultSkinsDB.frameIntensity = 0.60
        VaultSkinsDB.frameEffectSpeed = "normal"
    elseif preset == "subtle" then
        VaultSkinsDB.frameAnimationMode = "subtle"
        VaultSkinsDB.frameOpeningAnimation = true
        VaultSkinsDB.frameIdleAnimation = true
        VaultSkinsDB.frameCrestEffects = true
        VaultSkinsDB.frameBorderFlow = true
        VaultSkinsDB.frameCornerEffects = false
        VaultSkinsDB.frameParticles = false
        VaultSkinsDB.frameIntensity = 0.65
        VaultSkinsDB.frameEffectSpeed = "normal"
    elseif preset == "cinematic" then
        VaultSkinsDB.frameAnimationMode = "full"
        VaultSkinsDB.frameOpeningAnimation = true
        VaultSkinsDB.frameIdleAnimation = true
        VaultSkinsDB.frameCrestEffects = true
        VaultSkinsDB.frameBorderFlow = true
        VaultSkinsDB.frameCornerEffects = true
        VaultSkinsDB.frameParticles = true
        VaultSkinsDB.frameIntensity = 1.25
        VaultSkinsDB.frameEffectSpeed = "cinematic"
    else
        VaultSkinsDB.frameAnimationMode = "full"
        VaultSkinsDB.frameOpeningAnimation = true
        VaultSkinsDB.frameIdleAnimation = true
        VaultSkinsDB.frameCrestEffects = true
        VaultSkinsDB.frameBorderFlow = true
        VaultSkinsDB.frameCornerEffects = true
        VaultSkinsDB.frameParticles = false
        VaultSkinsDB.frameIntensity = 1.00
        VaultSkinsDB.frameEffectSpeed = "normal"
    end
    return true
end

function NS:MarkFramePresetCustom()
    if not VaultSkinsDB then return end
    VaultSkinsDB.framePreset = "custom"
    if VaultSkinsDB.frameAnimationMode == "off" then
        VaultSkinsDB.frameAnimationMode = "full"
    end
end

function NS:ResetDatabase()
    if type(VaultSkinsDB) ~= "table" then
        VaultSkinsDB = {}
    end
    for key in pairs(VaultSkinsDB) do
        VaultSkinsDB[key] = nil
    end
    CopyDefaults()
    VaultSkinsDB.settingsVersion = CURRENT_SETTINGS_VERSION
end

-- ==================== VAULT LOADING AND COMMAND HELPERS =====================
local function IsBlizzardVaultLoaded()
    if C_AddOns and C_AddOns.IsAddOnLoaded then
        return C_AddOns.IsAddOnLoaded("Blizzard_WeeklyRewards")
    end
    return IsAddOnLoaded and IsAddOnLoaded("Blizzard_WeeklyRewards") or false
end

local function LoadBlizzardVault()
    if IsBlizzardVaultLoaded() then
        return true
    end
    if C_AddOns and C_AddOns.LoadAddOn then
        return C_AddOns.LoadAddOn("Blizzard_WeeklyRewards")
    end
    if LoadAddOn then
        return LoadAddOn("Blizzard_WeeklyRewards")
    end
    return false
end

local function PrintHelp()
    print("|cff9f78ffVaultSkins|r commands:")
    print("  |cffffffff/vskin|r or |cffffffff/vskins|r - open settings")
    print("  |cffffffff/vskin open|preview|skip|r - open or control the reveal")
    print("  |cffffffff/vskin speed fast|normal|cinematic|r")
    print("  |cffffffff/vskin mode sequential|rows|rewardslast|random|click|jackpot|r")
    print("  |cffffffff/vskin preset fast|standard|cinematic|off|r")
    print("  |cffffffff/vskin sound quiet|normal|full|off|r")
    print("  |cffffffff/vskin soundsync|framesound|rewardsound|finalsound on|off|r")
    print("  |cffffffff/vskin soundpreview|r - preview the synchronized sound sequence")
    print("  |cffffffff/vskin profile account|character|class|r")
    print("  |cffffffff/vskin skin on|off|r - switch VaultSkins or original UI")
    print("  |cffffffff/vskin final|skipbutton|autofit on|off|r")
    print("  |cffffffff/vskin framepreset off|subtle|standard|cinematic|r")
    print("  |cffffffff/vskin frameopening|frameidle|framecrest|frameborder|framecorners on|off|r")
    print("  |cffffffff/vskin particles on|off · frameintensity 40-140 · framespeed fast|normal|cinematic|r")
    print("  |cffffffff/vskin framepreview|r - preview only the animated frame")
    print("  |cffffffff/vskin scene on|off · scenemotion on|off · sceneparticles on|off|r")
    print("  |cffffffff/vskin sceneintensity 20-100 · sceneperformance low|balanced|full · scenepreview|r")
    print("  |cffffffff/vskin layout wide|classic|cinematic|r")
    print("  |cffffffff/vskin compat auto|native|minimal|r")
    print("  |cffffffff/vskin status|memory|debug|errors|repair|themes|r")
    print("  |cffffffff/vskin debug reset|r - clear performance and error counters")
    print("  |cffffffff/vskin theme <name>|r - change theme")
    print("  |cffffffff/vskin reset|r - reset all settings")
end

local function ReplayAnimation()
    LoadBlizzardVault()
    if not WeeklyRewardsFrame then
        print("|cffff5555VaultSkins:|r The Great Vault frame is not available yet.")
        return
    end

    if not WeeklyRewardsFrame:IsShown() then
        if WeeklyRewards_ShowUI then
            WeeklyRewards_ShowUI()
        else
            WeeklyRewardsFrame:Show()
        end
        ScheduleTask("slash-replay-open", 0.35, function()
            if NS.Skin then
                NS.Skin:PlayOpeningAnimation(true)
            end
        end)
    elseif NS.Skin then
        NS.Skin:PlayOpeningAnimation(true)
    end
end

local function SetBooleanSetting(key, requested, label)
    requested = string.lower(strtrim(requested or ""))
    if requested == "on" then
        VaultSkinsDB[key] = true
    elseif requested == "off" then
        VaultSkinsDB[key] = false
    else
        VaultSkinsDB[key] = not VaultSkinsDB[key]
    end
    if NS.Options then
        NS.Options:Refresh()
    end
    print("|cff9f78ffVaultSkins:|r " .. label .. " " .. (VaultSkinsDB[key] and "enabled." or "disabled."))
end

local function PrintStatus()
    local diagnostics = NS.ThemeEngine and NS.ThemeEngine:GetDiagnostics()
    local engineText = diagnostics and (diagnostics.visible .. " themes / " .. diagnostics.packs .. " packs") or "unavailable"
    local compatibility = NS.Compatibility and NS.Compatibility:GetStatusText() or "unknown UI"
    local effectiveScale = NS.Skin and NS.Skin.effectiveScale or VaultSkinsDB.scale
    local activeTheme = NS.GetTheme and NS:GetTheme(NS:GetActiveThemeID()) or nil
    local effectProfile = activeTheme and activeTheme.frameEffectProfile and activeTheme.frameEffectProfile.id or "default"
    local sceneText = VaultSkinsDB.backgroundScenes and string.format("ON/%s/%d%% motion:%s particles:%s", tostring(VaultSkinsDB.backgroundPerformance), math.floor((VaultSkinsDB.backgroundIntensity or 0.65) * 100 + 0.5), VaultSkinsDB.backgroundMotion and "ON" or "OFF", VaultSkinsDB.backgroundParticles and "ON" or "OFF") or "OFF"
    print(string.format(
        "|cff9f78ffVaultSkins %s|r - theme: %s, layout: %s, effect: %s, reveal: %s/%s, frame: %s/%s/%d%%, scene: %s, sounds: %s, scale: %d%%, engine: %s",
        ADDON_VERSION,
        tostring(NS:GetActiveThemeID()),
        tostring(VaultSkinsDB.layoutStyle),
        tostring(effectProfile),
        tostring(VaultSkinsDB.revealMode),
        tostring(VaultSkinsDB.revealSpeed),
        tostring(VaultSkinsDB.framePreset),
        tostring(VaultSkinsDB.frameEffectSpeed),
        math.floor((VaultSkinsDB.frameIntensity or 1) * 100 + 0.5),
        sceneText,
        VaultSkinsDB.sounds and string.format("ON/%s sync:%s F:%s R:%s X:%s", tostring(VaultSkinsDB.soundIntensity), VaultSkinsDB.soundSync and "ON" or "OFF", VaultSkinsDB.frameSounds and "ON" or "OFF", VaultSkinsDB.rewardSounds and "ON" or "OFF", VaultSkinsDB.finalSounds and "ON" or "OFF") or "OFF",
        math.floor((effectiveScale or 1) * 100 + 0.5),
        engineText
    ))
    print("|cffaaaaaaCompatibility: " .. compatibility .. " · mode " .. tostring(VaultSkinsDB.compatibilityMode) .. " · skin " .. (VaultSkinsDB.skinEnabled and "ON" or "ORIGINAL") .. " · profile " .. tostring(VaultSkinsDB.themeMode) .. "|r")
end

local function PrintMemoryReport()
    if type(UpdateAddOnMemoryUsage) == "function" then pcall(UpdateAddOnMemoryUsage) end

    local addonKB
    if type(GetAddOnMemoryUsage) == "function" then
        local ok, value = pcall(GetAddOnMemoryUsage, addonName)
        if ok and type(value) == "number" then addonKB = value end
    end
    local luaMB = collectgarbage and (collectgarbage("count") / 1024) or nil

    if addonKB then
        print(string.format("|cff9f78ffVaultSkins:|r addon Lua memory %.2f MB.", addonKB / 1024))
    else
        print("|cff9f78ffVaultSkins:|r Per-addon Lua memory is unavailable on this client build.")
    end
    if luaMB then
        print(string.format("|cffaaaaaaTotal UI Lua memory: %.2f MB. Texture memory is tracked separately by the client and may remain cached after switching themes.|r", luaMB))
    end
    print("|cffaaaaaaLow scene mode is now the recommended memory setting.|r")
end

-- =========================== SLASH COMMAND ROUTER ===========================
local function HandleSlash(message)
    message = strtrim(message or "")
    local command, rest = message:match("^(%S*)%s*(.-)$")
    command = string.lower(command or "")

    if command == "" or command == "settings" or command == "config" then
        NS.Options:Toggle()
    elseif command == "open" then
        LoadBlizzardVault()
        if WeeklyRewards_ShowUI then WeeklyRewards_ShowUI() elseif WeeklyRewardsFrame then WeeklyRewardsFrame:Show() end
    elseif command == "preview" or command == "animation" then
        ReplayAnimation()
    elseif command == "skip" then
        if NS.Skin then NS.Skin:SkipOpeningAnimation() end
    elseif command == "framepreview" or command == "frame-preview" then
        LoadBlizzardVault()
        if not WeeklyRewardsFrame then
            print("|cffff5555VaultSkins:|r The Great Vault frame is not available yet.")
        elseif not WeeklyRewardsFrame:IsShown() then
            if WeeklyRewards_ShowUI then WeeklyRewards_ShowUI() else WeeklyRewardsFrame:Show() end
            ScheduleTask("slash-frame-preview", 0.30, function() if NS.Skin then NS.Skin:PreviewFrameAnimation() end end)
        elseif NS.Skin then
            NS.Skin:PreviewFrameAnimation()
        end
    elseif command == "status" then
        PrintStatus()
    elseif command == "memory" or command == "mem" then
        PrintMemoryReport()
    elseif command == "debug" then
        local requested = string.lower(strtrim(rest or ""))
        if NS.Skin and NS.Skin.PrintDebugDiagnostics then
            NS.Skin:PrintDebugDiagnostics(requested == "reset")
        else
            PrintStatus()
        end
    elseif command == "errors" then
        if NS.Skin then NS.Skin:PrintErrorDiagnostics() end
    elseif command == "repair" then
        if NS.Skin then NS.Skin:Repair() end
    elseif command == "preset" then
        local requested = string.lower(strtrim(rest or ""))
        if NS:SetAnimationPreset(requested) then
            if NS.Options then NS.Options:Refresh() end
            if NS.Skin and requested == "off" then NS.Skin:SkipOpeningAnimation() end
            print("|cff9f78ffVaultSkins:|r Animation preset changed to " .. requested .. ".")
        else
            print("|cffff5555VaultSkins:|r Choose fast, standard, cinematic, or off.")
        end
    elseif command == "profile" or command == "thememode" then
        local requested = string.lower(strtrim(rest or ""))
        if validThemeModes[requested] then
            VaultSkinsDB.themeMode = requested
            if NS.Options then NS.Options:Refresh() end
            if NS.Skin then NS.Skin:RequestThemeApply("theme profile", 0) end
            print("|cff9f78ffVaultSkins:|r Theme profile changed to " .. requested .. ".")
        else
            print("|cffff5555VaultSkins:|r Choose account, character, or class.")
        end
    elseif command == "skin" or command == "original" then
        local requested = string.lower(strtrim(rest or ""))
        if command == "original" and requested == "" then requested = "off" end
        if requested == "on" then VaultSkinsDB.skinEnabled = true
        elseif requested == "off" then VaultSkinsDB.skinEnabled = false
        else VaultSkinsDB.skinEnabled = not VaultSkinsDB.skinEnabled end
        if NS.Skin then NS.Skin:SetSkinEnabled(VaultSkinsDB.skinEnabled) end
        if NS.Options then NS.Options:Refresh() end
        print("|cff9f78ffVaultSkins:|r " .. (VaultSkinsDB.skinEnabled and "VaultSkins enabled." or "Original Great Vault restored."))
    elseif command == "speed" then
        local requested = string.lower(strtrim(rest or ""))
        if validSpeeds[requested] then
            VaultSkinsDB.revealSpeed = requested
            VaultSkinsDB.animations = true
            VaultSkinsDB.animationPreset = requested == "normal" and "standard" or requested
            NS.Options:Refresh()
            print("|cff9f78ffVaultSkins:|r Reveal speed changed to " .. requested .. ".")
        else
            print("|cffff5555VaultSkins:|r Choose fast, normal, or cinematic.")
        end
    elseif command == "mode" or command == "order" then
        local requested = NormalizeMode(rest)
        if requested then
            VaultSkinsDB.revealMode = requested
            NS.Options:Refresh()
            print("|cff9f78ffVaultSkins:|r Reveal mode changed to " .. requested .. ".")
        else
            print("|cffff5555VaultSkins:|r Choose sequential, rows, rewardslast, random, click, or jackpot.")
        end
    elseif command == "sound" or command == "sounds" then
        local requested = string.lower(strtrim(rest or ""))
        if requested == "off" then
            VaultSkinsDB.sounds = false
        elseif validSoundIntensity[requested] then
            VaultSkinsDB.sounds = true
            VaultSkinsDB.soundIntensity = requested
        elseif requested == "on" then
            VaultSkinsDB.sounds = true
        else
            VaultSkinsDB.sounds = not VaultSkinsDB.sounds
        end
        if NS.Options then NS.Options:Refresh() end
        print("|cff9f78ffVaultSkins:|r Reveal sounds " .. (VaultSkinsDB.sounds and ("enabled (" .. VaultSkinsDB.soundIntensity .. ").") or "disabled."))
    elseif command == "soundsync" or command == "sound-sync" then
        SetBooleanSetting("soundSync", rest, "Synchronized sound timing")
    elseif command == "framesound" or command == "frame-sound" then
        SetBooleanSetting("frameSounds", rest, "Frame sounds")
    elseif command == "rewardsound" or command == "reward-sound" then
        SetBooleanSetting("rewardSounds", rest, "Reward sounds")
    elseif command == "finalsound" or command == "final-sound" then
        SetBooleanSetting("finalSounds", rest, "Final flourish sounds")
    elseif command == "soundpreview" or command == "sound-preview" then
        if NS.Skin and NS.Skin.PreviewSoundSequence then
            if not NS.Skin:PreviewSoundSequence() then
                print("|cffff5555VaultSkins:|r Enable sounds before previewing the sound sequence.")
            end
        end
    elseif command == "framepreset" or command == "frame-preset" then
        local requested = string.lower(strtrim(rest or ""))
        if NS:SetFramePreset(requested) then
            if NS.Options then NS.Options:Refresh() end
            if NS.Skin then NS.Skin:RefreshFrameAnimation() end
            print("|cff9f78ffVaultSkins:|r Frame preset changed to " .. requested .. ".")
        else
            print("|cffff5555VaultSkins:|r Choose off, subtle, standard, or cinematic.")
        end
    elseif command == "frame" or command == "frameanimation" then
        local requested = string.lower(strtrim(rest or ""))
        local preset = requested == "full" and "standard" or requested
        if NS:SetFramePreset(preset) then
            if NS.Options then NS.Options:Refresh() end
            if NS.Skin then NS.Skin:RefreshFrameAnimation() end
            print("|cff9f78ffVaultSkins:|r Frame animation changed to " .. requested .. ".")
        else
            print("|cffff5555VaultSkins:|r Choose off, subtle, full, standard, or cinematic.")
        end
    elseif command == "frameopening" or command == "openingframe" then
        SetBooleanSetting("frameOpeningAnimation", rest, "Opening frame effects")
        NS:MarkFramePresetCustom()
        if NS.Options then NS.Options:Refresh() end
        if NS.Skin then NS.Skin:RefreshFrameAnimation() end
    elseif command == "frameidle" or command == "idleframe" then
        SetBooleanSetting("frameIdleAnimation", rest, "Idle frame animation")
        NS:MarkFramePresetCustom()
        if NS.Options then NS.Options:Refresh() end
        if NS.Skin then NS.Skin:RefreshFrameAnimation() end
    elseif command == "framecrest" or command == "crestframe" then
        SetBooleanSetting("frameCrestEffects", rest, "Crest and divider effects")
        NS:MarkFramePresetCustom()
        if NS.Options then NS.Options:Refresh() end
        if NS.Skin then NS.Skin:RefreshFrameAnimation() end
    elseif command == "frameborder" or command == "borderflow" then
        SetBooleanSetting("frameBorderFlow", rest, "Border-flow effects")
        NS:MarkFramePresetCustom()
        if NS.Options then NS.Options:Refresh() end
        if NS.Skin then NS.Skin:RefreshFrameAnimation() end
    elseif command == "framecorners" or command == "cornereffects" then
        SetBooleanSetting("frameCornerEffects", rest, "Corner effects")
        NS:MarkFramePresetCustom()
        if NS.Options then NS.Options:Refresh() end
        if NS.Skin then NS.Skin:RefreshFrameAnimation() end
    elseif command == "particles" or command == "frameparticles" then
        SetBooleanSetting("frameParticles", rest, "Frame particles")
        NS:MarkFramePresetCustom()
        if NS.Options then NS.Options:Refresh() end
        if NS.Skin then NS.Skin:RefreshFrameAnimation() end
    elseif command == "framespeed" or command == "frame-speed" then
        local requested = string.lower(strtrim(rest or ""))
        if validFrameEffectSpeeds[requested] then
            VaultSkinsDB.frameEffectSpeed = requested
            NS:MarkFramePresetCustom()
            if NS.Options then NS.Options:Refresh() end
            if NS.Skin then NS.Skin:RefreshFrameAnimation() end
            print("|cff9f78ffVaultSkins:|r Frame-effect speed changed to " .. requested .. ".")
        else
            print("|cffff5555VaultSkins:|r Choose fast, normal, or cinematic.")
        end
    elseif command == "frameintensity" or command == "frame-intensity" then
        local value = tonumber(strtrim(rest or ""))
        if value then
            if value > 2 then value = value / 100 end
            value = Clamp(value, 0.40, 1.40)
            VaultSkinsDB.frameIntensity = math.floor(value * 20 + 0.5) / 20
            NS:MarkFramePresetCustom()
            if NS.Options then NS.Options:Refresh() end
            if NS.Skin then NS.Skin:RefreshFrameAnimation() end
            print(string.format("|cff9f78ffVaultSkins:|r Frame intensity changed to %d%%.", VaultSkinsDB.frameIntensity * 100))
        else
            print("|cffff5555VaultSkins:|r Use a value from 40 to 140.")
        end
    elseif command == "scene" or command == "backgroundscene" or command == "background" then
        SetBooleanSetting("backgroundScenes", rest, "Animated background scenes")
        if NS.Skin and NS.Skin.RefreshBackgroundScene then NS.Skin:RefreshBackgroundScene() end
    elseif command == "scenemotion" or command == "scene-motion" then
        SetBooleanSetting("backgroundMotion", rest, "Background scene motion")
        if NS.Skin and NS.Skin.RefreshBackgroundScene then NS.Skin:RefreshBackgroundScene() end
    elseif command == "sceneparticles" or command == "scene-particles" then
        SetBooleanSetting("backgroundParticles", rest, "Background scene particles")
        if NS.Skin and NS.Skin.RefreshBackgroundScene then NS.Skin:RefreshBackgroundScene() end
    elseif command == "sceneperformance" or command == "scene-performance" then
        local requested = string.lower(strtrim(rest or ""))
        if validBackgroundPerformance[requested] then
            VaultSkinsDB.backgroundPerformance = requested
            if NS.Options then NS.Options:Refresh() end
            if NS.Skin and NS.Skin.RefreshBackgroundScene then NS.Skin:RefreshBackgroundScene() end
            print("|cff9f78ffVaultSkins:|r Background performance changed to " .. requested .. ".")
        else
            print("|cffff5555VaultSkins:|r Choose low, balanced, or full.")
        end
    elseif command == "sceneintensity" or command == "scene-intensity" then
        local value = tonumber(strtrim(rest or ""))
        if value then
            if value > 2 then value = value / 100 end
            value = Clamp(value, 0.20, 1.00)
            VaultSkinsDB.backgroundIntensity = math.floor(value * 20 + 0.5) / 20
            if NS.Options then NS.Options:Refresh() end
            if NS.Skin and NS.Skin.RefreshBackgroundScene then NS.Skin:RefreshBackgroundScene() end
            print(string.format("|cff9f78ffVaultSkins:|r Background intensity changed to %d%%.", VaultSkinsDB.backgroundIntensity * 100))
        else
            print("|cffff5555VaultSkins:|r Use a value from 20 to 100.")
        end
    elseif command == "scenepreview" or command == "scene-preview" then
        LoadBlizzardVault()
        if not WeeklyRewardsFrame then
            print("|cffff5555VaultSkins:|r The Great Vault frame is not available yet.")
        elseif not WeeklyRewardsFrame:IsShown() then
            if WeeklyRewards_ShowUI then WeeklyRewards_ShowUI() else WeeklyRewardsFrame:Show() end
            ScheduleTask("slash-scene-preview", 0.30, function() if NS.Skin and NS.Skin.PreviewBackgroundScene then NS.Skin:PreviewBackgroundScene() end end)
        elseif NS.Skin and NS.Skin.PreviewBackgroundScene then
            NS.Skin:PreviewBackgroundScene()
        end
    elseif command == "layout" or command == "layoutstyle" or command == "layout-style" then
        local requested = string.lower(strtrim(rest or ""))
        if validLayoutStyles[requested] and NS.Layout and NS.Layout:SetStyle(requested) then
            print("|cff9f78ffVaultSkins:|r Layout changed to " .. requested .. ".")
        else
            print("|cffff5555VaultSkins:|r Choose wide, classic, or cinematic.")
        end
    elseif command == "final" or command == "flourish" then
        SetBooleanSetting("finalFlourish", rest, "Final flourish")
    elseif command == "autofit" or command == "fit" then
        SetBooleanSetting("autoFit", rest, "Automatic screen fitting")
        if NS.Skin then NS.Skin:ApplyScale() end
    elseif command == "compat" or command == "compatibility" then
        local requested = string.lower(strtrim(rest or ""))
        if validCompatibility[requested] then
            VaultSkinsDB.compatibilityMode = requested
            if NS.Compatibility then NS.Compatibility:Refresh() end
            if NS.Skin then NS.Skin:RequestThemeApply("compatibility", 0) end
            if NS.Options then NS.Options:Refresh() end
            print("|cff9f78ffVaultSkins:|r Compatibility mode changed to " .. requested .. ".")
        else
            print("|cffff5555VaultSkins:|r Choose auto, native, or minimal.")
        end
    elseif command == "themes" or command == "packs" then
        local themeOrder = NS.GetThemeOrder and NS:GetThemeOrder() or { "Midnight" }
        print("|cff9f78ffVaultSkins:|r Installed themes: " .. table.concat(themeOrder, ", "))
    elseif command == "theme" then
        local requested = string.lower(strtrim(rest or ""))
        local found
        for _, themeName in ipairs(NS:GetThemeOrder()) do
            local metadata = NS.ThemeEngine:GetThemeMetadata(themeName)
            if string.lower(themeName) == requested or (metadata and string.lower(metadata.displayName or "") == requested) then
                found = themeName
                break
            end
        end
        if found then
            NS:SetActiveThemeID(found)
            NS.Options:Refresh()
            if NS.Skin then NS.Skin:RequestThemeApply("theme change", 0) end
            print("|cff9f78ffVaultSkins:|r Theme changed to " .. found .. ".")
        else
            print("|cffff5555VaultSkins:|r Unknown theme. Use /vskin themes.")
        end
    elseif command == "reset" then
        NS:ResetDatabase()
        if NS.Options then NS.Options:ResetPosition(); NS.Options:Refresh() end
        if NS.Skin then NS.Skin:Repair() end
        print("|cff9f78ffVaultSkins:|r " .. (L.SETTINGS_RESET or "Settings reset."))
    else
        PrintHelp()
    end
end

-- ========================== ADDON EVENT LIFECYCLE ===========================
local eventFrame = CreateFrame("Frame")
eventFrame:RegisterEvent("ADDON_LOADED")
eventFrame:RegisterEvent("PLAYER_LOGIN")
eventFrame:RegisterEvent("UI_SCALE_CHANGED")
eventFrame:RegisterEvent("DISPLAY_SIZE_CHANGED")
eventFrame:SetScript("OnEvent", function(_, event, loadedAddon)
    if event == "ADDON_LOADED" then
        if loadedAddon == addonName then
            InitializeDatabase()
            if NS.Compatibility then NS.Compatibility:Refresh() end
            SLASH_VAULTSKINS1 = "/vskin"
            SLASH_VAULTSKINS2 = "/vskins"
            SLASH_VAULTSKINS3 = "/vaultskins"
            SlashCmdList.VAULTSKINS = HandleSlash
        elseif loadedAddon == "Blizzard_WeeklyRewards" then
            if NS.Skin then NS.Skin:Initialize() end
        elseif NS.Compatibility then
            NS.Compatibility:Refresh()
        end
    elseif event == "PLAYER_LOGIN" then
        if NS.Compatibility then NS.Compatibility:Refresh() end
        if IsBlizzardVaultLoaded() and NS.Skin then NS.Skin:Initialize() end
    elseif event == "UI_SCALE_CHANGED" or event == "DISPLAY_SIZE_CHANGED" then
        if NS.Skin then NS.Skin:ApplyScale() end
        if NS.Options then NS.Options:ClampToScreen() end
    end
end)
