-- S-Frames Core Initialize
SFrames = {}
DEFAULT_CHAT_FRAME:AddMessage("SF: Loading Core.lua...")

do
    local _orig_wipe = wipe
    if _orig_wipe then
        wipe = function(t)
            if t == nil then return end
            return _orig_wipe(t)
        end
    end
    local _orig_tinsert = tinsert
    if _orig_tinsert then
        tinsert = function(t, a2, a3)
            if type(t) ~= "table" then return end
            if a3 ~= nil then
                return _orig_tinsert(t, a2, a3)
            else
                return _orig_tinsert(t, a2)
            end
        end
    end
end

do
    local _orig_UIFrameFade = UIFrameFade
    if _orig_UIFrameFade then
        UIFrameFade = function(frame, fadeInfo)
            if not frame or not fadeInfo then return end
            return _orig_UIFrameFade(frame, fadeInfo)
        end
    end

    local origOnUpdate = UIParent and UIParent.GetScript and UIParent:GetScript("OnUpdate")
    if origOnUpdate then
        UIParent:SetScript("OnUpdate", function()
            pcall(origOnUpdate)
        end)
    end
end

BINDING_HEADER_NANAMI_UI = "Nanami-UI"
BINDING_NAME_NANAMI_TOGGLE_NAV = "切换导航地图"

SFrames.eventFrame = CreateFrame("Frame", "SFramesEventFrame", UIParent)
SFrames.events = {}

function SFrames:GetIncomingHeals(unit)
    -- Source 1: ShaguTweaks libpredict
    if ShaguTweaks and ShaguTweaks.libpredict and ShaguTweaks.libpredict.UnitGetIncomingHeals then
        local lp = ShaguTweaks.libpredict
        if lp.UnitGetIncomingHealsBreakdown then
            local ok, total, mine, others = pcall(function()
                return lp:UnitGetIncomingHealsBreakdown(unit, UnitName("player"))
            end)
            if ok then
                return math.max(0, tonumber(total) or 0),
                       math.max(0, tonumber(mine) or 0),
                       math.max(0, tonumber(others) or 0)
            end
        end
        local ok, amount = pcall(function() return lp:UnitGetIncomingHeals(unit) end)
        if ok then
            amount = math.max(0, tonumber(amount) or 0)
            return amount, 0, amount
        end
    end
    -- Source 2: HealComm-1.0 (AceLibrary)
    if AceLibrary and AceLibrary.HasInstance and AceLibrary:HasInstance("HealComm-1.0") then
        local ok, HC = pcall(function() return AceLibrary("HealComm-1.0") end)
        if ok and HC and HC.getHeal then
            local name = UnitName(unit)
            if name then
                local total = HC:getHeal(name) or 0
                total = math.max(0, tonumber(total) or 0)
                return total, 0, total
            end
        end
    end
    return 0, 0, 0
end

-- Event Dispatcher
SFrames.eventFrame:SetScript("OnEvent", function()
    if SFrames.events[event] then
        for i, func in ipairs(SFrames.events[event]) do
            func(event)
        end
    end
end)

function SFrames:RegisterEvent(event, func)
    if not self.events[event] then
        self.events[event] = {}
        self.eventFrame:RegisterEvent(event)
    end
    table.insert(self.events[event], func)
end

function SFrames:UnregisterEvent(event, func)
    if self.events[event] then
        for i, f in ipairs(self.events[event]) do
            if f == func then
                table.remove(self.events[event], i)
                break
            end
        end
        if table.getn(self.events[event]) == 0 then
            self.events[event] = nil
            self.eventFrame:UnregisterEvent(event)
        end
    end
end

-- Print Helper
function SFrames:Print(msg)
    local hex = SFrames.Theme and SFrames.Theme:GetAccentHex() or "ffffb3d9"
    DEFAULT_CHAT_FRAME:AddMessage("|c" .. hex .. "[Nanami-UI]|r " .. tostring(msg))
end

-- Addon Loaded Initializer
SFrames:RegisterEvent("PLAYER_LOGIN", function()
    SFrames:Initialize()
end)

function SFrames:SafeInit(name, initFn)
    local ok, err = pcall(initFn)
    if not ok then
        DEFAULT_CHAT_FRAME:AddMessage("|cffff4444Nanami-UI: " .. name .. " init failed: " .. tostring(err) .. "|r")
    end
end

function SFrames:Initialize()
    if not SFramesDB then SFramesDB = {} end

    if not SFramesDB.setupComplete then
        if SFrames.SetupWizard and SFrames.SetupWizard.Show then
            SFrames.SetupWizard:Show(function()
                SFrames:DoFullInitialize()
            end, "firstrun")
        else
            SFramesDB.setupComplete = true
            self:DoFullInitialize()
        end
        return
    end

    self:DoFullInitialize()
end

function SFrames:DoFullInitialize()
    self:Print("Nanami-UI 正在加载，喵呜~ =^_^=")

    self:HideBlizzardFrames()

    SFrames.Tooltip = CreateFrame("GameTooltip", "SFramesScanTooltip", nil, "GameTooltipTemplate")
    SFrames.Tooltip:SetOwner(UIParent, "ANCHOR_NONE")
    SFrames.Tooltip:SetAlpha(0)
    SFrames.Tooltip:Hide()

    -- Phase 1: Critical modules (unit frames, action bars) — must load immediately
    if SFramesDB.enableUnitFrames ~= false then
        if SFramesDB.enablePlayerFrame ~= false then
            if SFrames.Player and SFrames.Player.Initialize then SFrames.Player:Initialize() end
            if SFrames.Pet and SFrames.Pet.Initialize then SFrames.Pet:Initialize() end
        end
        if SFramesDB.enableTargetFrame ~= false then
            if SFrames.Target and SFrames.Target.Initialize then SFrames.Target:Initialize() end
            if SFrames.ToT and SFrames.ToT.Initialize then SFrames.ToT:Initialize() end
        end
        if SFramesDB.enablePartyFrame ~= false then
            if SFrames.Party and SFrames.Party.Initialize then SFrames.Party:Initialize() end
        end
    end
    if SFrames.FloatingTooltip and SFrames.FloatingTooltip.Initialize then SFrames.FloatingTooltip:Initialize() end

    if SFrames.ActionBars and SFrames.ActionBars.Initialize then
        SFrames.ActionBars:Initialize()
    end

    self:InitSlashCommands()

    -- Phase 2: Deferred modules — spread across multiple frames to avoid memory spike
    local deferred = {
        { "Raid",        function() if SFramesDB.enableUnitFrames ~= false and SFrames.Raid and SFrames.Raid.Initialize then SFrames.Raid:Initialize() end end },
        { "Bags",        function() if SFrames.Bags and SFrames.Bags.Core and SFrames.Bags.Core.Initialize then SFrames.Bags.Core:Initialize() end end },
        { "Focus",       function() if SFrames.Focus and SFrames.Focus.Initialize then SFrames.Focus:Initialize() end end },
        { "TalentTree",  function() if SFrames.TalentTree and SFrames.TalentTree.Initialize then SFrames.TalentTree:Initialize() end end },
        { "Minimap",     function() if SFrames.Minimap and SFrames.Minimap.Initialize then SFrames.Minimap:Initialize() end end },
        { "MinimapBuffs",function() if SFrames.MinimapBuffs and SFrames.MinimapBuffs.Initialize then SFrames.MinimapBuffs:Initialize() end end },
        { "MinimapButton",function() if SFrames.MinimapButton and SFrames.MinimapButton.Initialize then SFrames.MinimapButton:Initialize() end end },
        { "Chat",        function() if SFramesDB.enableChat ~= false and SFrames.Chat and SFrames.Chat.Initialize then SFrames.Chat:Initialize() end end },
        { "MapReveal",   function() if SFrames.MapReveal and SFrames.MapReveal.Initialize then SFrames.MapReveal:Initialize() end end },
        { "WorldMap",    function() if SFrames.WorldMap and SFrames.WorldMap.Initialize then SFrames.WorldMap:Initialize() end end },
        { "MapIcons",    function() if SFrames.MapIcons and SFrames.MapIcons.Initialize then SFrames.MapIcons:Initialize() end end },
        { "Tweaks",      function() if SFrames.Tweaks and SFrames.Tweaks.Initialize then SFrames.Tweaks:Initialize() end end },
        { "AFKScreen",   function() if SFrames.AFKScreen and SFrames.AFKScreen.Initialize then SFrames.AFKScreen:Initialize() end end },
        { "LootDisplay", function() if SFrames.LootDisplay and SFrames.LootDisplay.Initialize then SFrames.LootDisplay:Initialize() end end },
    }

    local idx = 1
    local batchSize = 3
    local deferFrame = CreateFrame("Frame")
    deferFrame:SetScript("OnUpdate", function()
        if idx > table.getn(deferred) then
            this:SetScript("OnUpdate", nil)
            SFrames:Print("所有模块加载完成 =^_^=")
            return
        end
        local batchEnd = idx + batchSize - 1
        if batchEnd > table.getn(deferred) then batchEnd = table.getn(deferred) end
        for i = idx, batchEnd do
            SFrames:SafeInit(deferred[i][1], deferred[i][2])
        end
        idx = batchEnd + 1
    end)
end

function SFrames:GetAuraTimeLeft(unit, index, isBuff)
    -- If the unit is the player (e.g. you target yourself), Vanilla API CAN give us exact times
    if UnitIsUnit(unit, "player") then
        local texture = isBuff and UnitBuff(unit, index) or UnitDebuff(unit, index)
        if texture then
            local filter = isBuff and "HELPFUL" or "HARMFUL"
            for i = 0, 31 do
                local buffIndex = GetPlayerBuff(i, filter)
                if buffIndex and buffIndex >= 0 then
                    if GetPlayerBuffTexture(buffIndex) == texture then
                        local t = GetPlayerBuffTimeLeft(buffIndex)
                        if t and t > 0 then return t end
                    end
                end
            end
        end
    end

    -- Nanami-Plates SpellDB: combat log + spell DB tracking (most accurate for debuffs)
    if not isBuff and NanamiPlates_SpellDB and NanamiPlates_SpellDB.UnitDebuff then
        local effect, rank, tex, stacks, dtype, duration, timeleft, isOwn = NanamiPlates_SpellDB:UnitDebuff(unit, index)
        if timeleft and timeleft > 0 then
            return timeleft, effect
        end
        if effect and effect ~= "" and duration and duration > 0
           and NanamiPlates_Auras and NanamiPlates_Auras.timers then
            local unitKey = (UnitGUID and UnitGUID(unit)) or UnitName(unit) or ""
            local cached = NanamiPlates_Auras.timers[unitKey .. "_" .. effect]
            if not cached and UnitName(unit) then
                cached = NanamiPlates_Auras.timers[UnitName(unit) .. "_" .. effect]
            end
            if cached and cached.startTime and cached.duration then
                local remaining = cached.duration - (GetTime() - cached.startTime)
                if remaining > 0 then
                    return remaining, effect
                end
            end
        end
    end
    
    -- Fallback to ShaguTweaks libdebuff if available (Debuffs only usually)
    if ShaguTweaks and ShaguTweaks.libdebuff then
        if not isBuff then
            local effect, rank, texture, stacks, dtype, duration, libTimeLeft = ShaguTweaks.libdebuff:UnitDebuff(unit, index)
            if libTimeLeft and libTimeLeft > 0 then
                return libTimeLeft
            end
        end
    end
    return 0
end

function SFrames:FormatTime(seconds)
    if not seconds then return "" end
    if seconds >= 3600 then
        return math.floor(seconds / 3600) .. "h"
    elseif seconds >= 60 then
        return math.floor(seconds / 60) .. "m"
    else
        return math.floor(seconds) .. "s"
    end
end

function SFrames:InitSlashCommands()
    DEFAULT_CHAT_FRAME:AddMessage("SF: InitSlashCommands called.")
    SLASH_SFRAMES1 = "/nanami"
    SLASH_SFRAMES2 = "/nui"
    SlashCmdList["SFRAMES"] = function(msg)
        local text = msg or ""
        text = string.gsub(text, "^%s+", "")
        text = string.gsub(text, "%s+$", "")
        local _, _, cmd, args = string.find(text, "^(%S+)%s*(.-)$")
        cmd = string.lower(cmd or "")
        args = args or ""

        if cmd == "unlock" or cmd == "move" then
            SFrames:UnlockFrames()
        elseif cmd == "lock" then
            SFrames:LockFrames()
        elseif cmd == "chatreset" then
            if SFrames.Chat and SFrames.Chat.ResetPosition then
                SFrames.Chat:ResetPosition()
            end
        elseif cmd == "test" then
            if SFrames.Party and SFrames.Party.TestMode then SFrames.Party:TestMode() end
        elseif cmd == "partyh" then
            if SFrames.Party and SFrames.Party.SetLayout then
                SFrames.Party:SetLayout("horizontal")
                SFrames:Print("Party layout set to horizontal.")
            end
        elseif cmd == "partyv" then
            if SFrames.Party and SFrames.Party.SetLayout then
                SFrames.Party:SetLayout("vertical")
                SFrames:Print("Party layout set to vertical.")
            end
        elseif cmd == "partylayout" or cmd == "playout" then
            local mode = string.lower(args or "")
            if mode == "h" or mode == "horizontal" then
                if SFrames.Party and SFrames.Party.SetLayout then
                    SFrames.Party:SetLayout("horizontal")
                    SFrames:Print("Party layout set to horizontal.")
                end
            elseif mode == "v" or mode == "vertical" then
                if SFrames.Party and SFrames.Party.SetLayout then
                    SFrames.Party:SetLayout("vertical")
                    SFrames:Print("Party layout set to vertical.")
                end
            else
                local current = (SFramesDB and SFramesDB.partyLayout) or "vertical"
                SFrames:Print("Usage: /nui partylayout horizontal|vertical (current: " .. current .. ")")
            end
        elseif cmd == "focus" then
            if not SFrames.Focus then
                SFrames:Print("Focus module unavailable.")
                return
            end
            local ok, name, usedNative = SFrames.Focus:SetFromTarget()
            if ok then
                if usedNative then
                    SFrames:Print("Focus set: " .. tostring(name) .. " (native)")
                else
                    SFrames:Print("Focus set: " .. tostring(name))
                end
            else
                SFrames:Print("No valid target to set focus.")
            end
        elseif cmd == "clearfocus" or cmd == "cf" then
            if not SFrames.Focus then
                SFrames:Print("Focus module unavailable.")
                return
            end
            SFrames.Focus:Clear()
            SFrames:Print("Focus cleared.")
        elseif cmd == "targetfocus" or cmd == "tf" then
            if not SFrames.Focus then
                SFrames:Print("Focus module unavailable.")
                return
            end
            local ok = SFrames.Focus:Target()
            if not ok then
                SFrames:Print("Focus target not found.")
            end
        elseif cmd == "fcast" or cmd == "focuscast" then
            if not SFrames.Focus then
                SFrames:Print("Focus module unavailable.")
                return
            end
            local ok, reason = SFrames.Focus:Cast(args)
            if not ok then
                if reason == "NO_SPELL" then
                    SFrames:Print("Usage: /nui fcast <spell name>")
                elseif reason == "NO_FOCUS" then
                    SFrames:Print("No focus set.")
                elseif reason == "FOCUS_NOT_FOUND" then
                    SFrames:Print("Focus not found in range/scene.")
                else
                    SFrames:Print("Focus cast failed.")
                end
            end
        elseif cmd == "focushelp" then
            SFrames:Print("/nui focus - set current target as focus")
            SFrames:Print("/nui clearfocus - clear focus")
            SFrames:Print("/nui targetfocus - target focus")
            SFrames:Print("/nui fcast <spell> - cast spell on focus")
            SFrames:Print("/nui partyh / partyv - switch party layout")
            SFrames:Print("/nui partylayout h|v - switch party layout")
            SFrames:Print("/nui ui - open UI settings")
            SFrames:Print("/nui bags - open bag settings")
            SFrames:Print("/nui chat - open chat settings panel")
            SFrames:Print("/nui chat help - chat command help")
            SFrames:Print("/nui chatreset - reset chat frame position")
            SFrames:Print("/nui afk - toggle AFK screen")
            SFrames:Print("/nui pin - 地图标记 (clear/share)")
            SFrames:Print("/nui nav - 切换导航地图")
            SFrames:Print("/nui mapscan - 扫描所有地图更新迷雾揭示数据")
            SFrames:Print("/nui mapstats - 查看地图覆盖层数据统计")
            SFrames:Print("/nui mapexport - 导出扫描到的地图数据")
            SFrames:Print("/nui mapclear - 清除已保存的扫描数据")
            SFrames:Print("/nui layout - 布局模式（拖拽调整所有框体位置）")
            SFrames:Print("/nui bind - 按键绑定模式（悬停按钮+按键）")
            SFrames:Print("/nui talentdb - 天赋默认数据库管理/导出")
        elseif cmd == "ui" or cmd == "uiconfig" then
            if SFrames.ConfigUI and SFrames.ConfigUI.Build then SFrames.ConfigUI:Build("ui") end
        elseif cmd == "chat" or cmd == "chatconfig" then
            if SFrames.Chat and SFrames.Chat.HandleSlash then
                SFrames.Chat:HandleSlash(args)
            end
        elseif cmd == "bags" or cmd == "bag" or cmd == "bagconfig" then
            if SFrames.ConfigUI and SFrames.ConfigUI.Build then SFrames.ConfigUI:Build("bags") end
        elseif cmd == "mapreveal" or cmd == "mr" then
            if SFrames.MapReveal and SFrames.MapReveal.Toggle then
                SFrames.MapReveal:Toggle()
            else
                SFrames:Print("MapReveal module unavailable.")
            end
        elseif cmd == "stats" or cmd == "stat" or cmd == "ss" then
            if SFrames.StatSummary and SFrames.StatSummary.Toggle then
                SFrames.StatSummary:Toggle()
            else
                SFrames:Print("StatSummary module unavailable.")
            end
        elseif cmd == "afk" then
            if SFrames.AFKScreen and SFrames.AFKScreen.Toggle then
                SFrames.AFKScreen:Toggle()
            else
                SFrames:Print("AFKScreen module unavailable.")
            end
        elseif cmd == "pin" or cmd == "wp" or cmd == "waypoint" then
            if not SFrames.WorldMap then
                SFrames:Print("WorldMap module unavailable.")
            elseif args == "clear" or args == "remove" then
                SFrames.WorldMap:ClearWaypoint()
                SFrames:Print("地图标记已清除")
            elseif args == "share" then
                SFrames.WorldMap:ShareWaypoint()
            else
                SFrames:Print("/nui pin clear - 清除地图标记")
                SFrames:Print("/nui pin share - 分享当前标记到聊天")
                SFrames:Print("在世界地图中 Ctrl+左键 可放置标记")
            end
        elseif cmd == "nav" or cmd == "navigation" then
            if SFrames.WorldMap and SFrames.WorldMap.ToggleNav then
                SFrames.WorldMap:ToggleNav()
            else
                SFrames:Print("WorldMap module unavailable.")
            end
        elseif cmd == "mapscan" or cmd == "scanmap" then
            if SFrames.MapReveal and SFrames.MapReveal.ScanAllMaps then
                SFrames.MapReveal:ScanAllMaps()
            else
                SFrames:Print("MapReveal module unavailable.")
            end
        elseif cmd == "mapexport" then
            if SFrames.MapReveal and SFrames.MapReveal.ExportScannedData then
                SFrames.MapReveal:ExportScannedData()
            else
                SFrames:Print("MapReveal module unavailable.")
            end
        elseif cmd == "mapstats" then
            if SFrames.MapReveal and SFrames.MapReveal.ShowStats then
                SFrames.MapReveal:ShowStats()
            else
                SFrames:Print("MapReveal module unavailable.")
            end
        elseif cmd == "mapclear" then
            if SFrames.MapReveal and SFrames.MapReveal.ClearSavedData then
                SFrames.MapReveal:ClearSavedData()
            else
                SFrames:Print("MapReveal module unavailable.")
            end
        elseif cmd == "layout" or cmd == "movers" then
            if SFrames.Movers and SFrames.Movers.ToggleLayoutMode then
                SFrames.Movers:ToggleLayoutMode()
            else
                SFrames:Print("Layout mode unavailable.")
            end
        elseif cmd == "bind" or cmd == "keybind" then
            if SFrames.ActionBars and SFrames.ActionBars.ToggleKeyBindMode then
                SFrames.ActionBars:ToggleKeyBindMode()
            else
                SFrames:Print("ActionBars module unavailable.")
            end
        elseif cmd == "keybinds" or cmd == "kb" then
            local KBM = SFrames.KeyBindManager
            if not KBM then
                SFrames:Print("KeyBindManager module unavailable.")
            elseif args == "" then
                if SFrames.ConfigUI and SFrames.ConfigUI.Build then
                    SFrames.ConfigUI:Build("keybinds")
                end
            elseif string.find(args, "^save ") then
                local name = string.gsub(args, "^save ", "")
                if name ~= "" then KBM:SaveProfile(name) end
            elseif string.find(args, "^load ") then
                local name = string.gsub(args, "^load ", "")
                if name ~= "" then KBM:LoadProfile(name) end
            elseif string.find(args, "^delete ") then
                local name = string.gsub(args, "^delete ", "")
                if name ~= "" then KBM:DeleteProfile(name) end
            elseif args == "list" then
                local list = KBM:GetProfileList()
                if table.getn(list) == 0 then
                    SFrames:Print("没有保存的按键绑定方案")
                else
                    SFrames:Print("按键绑定方案列表:")
                    for _, name in ipairs(list) do
                        local info = KBM:GetProfileInfo(name)
                        local desc = info and (info.charName .. ", " .. info.count .. " 条") or ""
                        SFrames:Print("  |cffffd100" .. name .. "|r  " .. desc)
                    end
                end
            elseif args == "export" then
                KBM:ShowExportDialog()
            elseif args == "import" then
                KBM:ShowImportDialog()
            else
                SFrames:Print("/nui keybinds - 打开设置面板")
                SFrames:Print("/nui keybinds save <名称> - 保存当前绑定为方案")
                SFrames:Print("/nui keybinds load <名称> - 加载方案")
                SFrames:Print("/nui keybinds delete <名称> - 删除方案")
                SFrames:Print("/nui keybinds list - 列出所有方案")
                SFrames:Print("/nui keybinds export - 导出当前绑定")
                SFrames:Print("/nui keybinds import - 导入绑定")
            end
        elseif cmd == "talentdb" or cmd == "tdb" then
            if SFrames.TalentTree and SFrames.TalentTree.HandleTalentDBCommand then
                SFrames.TalentTree:HandleTalentDBCommand(args)
            else
                SFrames:Print("TalentTree module unavailable.")
            end
        elseif cmd == "debugbuffs" or cmd == "db" then
            local hex = SFrames.Theme and SFrames.Theme:GetAccentHex() or "ffffb3d9"
            DEFAULT_CHAT_FRAME:AddMessage("|c" .. hex .. "[Nanami-UI]|r 当前所有 Buff：")
            for i = 0, 31 do
                local buffIndex = GetPlayerBuff(i, "HELPFUL")
                if buffIndex and buffIndex >= 0 then
                    local name = SFrames:GetBuffName(buffIndex)
                    local tex = GetPlayerBuffTexture(buffIndex) or "?"
                    local tl = GetPlayerBuffTimeLeft(buffIndex)
                    local timeStr = (tl and tl > 0 and tl < 99999) and string.format("%.1fs", tl) or "N/A"
                    local hidden = SFrames:IsBuffHidden(buffIndex) and "|cffff4444[隐藏]|r" or ""
                    DEFAULT_CHAT_FRAME:AddMessage(string.format("  #%d: |cffffd100%s|r  %s  %s", i, name or "(nil)", timeStr, hidden))
                end
            end
        elseif cmd == "hidebuff" or cmd == "hb" then
            if args == "" then
                SFrames:Print("用法: /nui hidebuff <buff名称>")
            else
                if not SFramesDB.hiddenBuffs then SFramesDB.hiddenBuffs = {} end
                SFramesDB.hiddenBuffs[args] = true
                SFrames:Print("已隐藏 Buff: |cffffd100" .. args .. "|r")
            end
        elseif cmd == "unhidebuff" or cmd == "uhb" then
            if args == "" then
                SFrames:Print("用法: /nui unhidebuff <buff名称>")
            else
                if SFramesDB.hiddenBuffs then SFramesDB.hiddenBuffs[args] = nil end
                SFrames:Print("已取消隐藏 Buff: |cffffd100" .. args .. "|r")
            end
        elseif cmd == "listhidden" or cmd == "lh" then
            local hex = SFrames.Theme and SFrames.Theme:GetAccentHex() or "ffffb3d9"
            DEFAULT_CHAT_FRAME:AddMessage("|c" .. hex .. "[Nanami-UI]|r 已隐藏的 Buff 列表：")
            if SFramesDB.hiddenBuffs then
                for name, _ in pairs(SFramesDB.hiddenBuffs) do
                    DEFAULT_CHAT_FRAME:AddMessage("  |cffffd100" .. name .. "|r (用户自定义)")
                end
            end
        elseif cmd == "config" or cmd == "" then
            if SFrames.ConfigUI and SFrames.ConfigUI.Build then SFrames.ConfigUI:Build("ui") end
        else
            local hex = SFrames.Theme and SFrames.Theme:GetAccentHex() or "ffffb3d9"
            DEFAULT_CHAT_FRAME:AddMessage("|c" .. hex .. "[Nanami-UI]|r Commands: /nui, /nui ui, /nui bags, /nui chat, /nui layout, /nui unlock, /nui lock, /nui test, /nui partyh, /nui partyv, /nui focushelp, /nui mapreveal, /nui mapscan, /nui stats, /nui afk, /nui pin, /nui bind, /nui keybinds")
        end
    end
end

function SFrames:UnlockFrames()
    self.isUnlocked = true
    self:Print("Frames Unlocked. Drag to move.")
    -- Show overlays or just let them be dragged if they are always movable
    if SFramesPlayerFrame then SFramesPlayerFrame:EnableMouse(true) end
    if SFramesPetFrame then SFramesPetFrame:EnableMouse(true) end
    if SFramesTargetFrame then SFramesTargetFrame:EnableMouse(true) end
    if SFrames.Chat and SFrames.Chat.SetUnlocked then
        SFrames.Chat:SetUnlocked(true)
    end
end

function SFrames:LockFrames()
    self.isUnlocked = false
    self:Print("Frames Locked.")
    if SFrames.Chat and SFrames.Chat.SetUnlocked then
        SFrames.Chat:SetUnlocked(false)
    end
end

function SFrames:HideBlizzardFrames()
    -- Hide Character Frame (replaced by CharacterPanel.lua)
    -- Only suppress if the custom character panel is enabled
    if (not SFramesDB) or (SFramesDB.charPanelEnable ~= false) then
        if CharacterFrame then
            CharacterFrame:UnregisterAllEvents()
            CharacterFrame:Hide()
            CharacterFrame.Show = function() end
        end
        if PaperDollFrame then PaperDollFrame:Hide() end
        if ReputationFrame then ReputationFrame:Hide() end
        if SkillFrame then SkillFrame:Hide() end
        if HonorFrame then HonorFrame:Hide() end
    end

    if SFramesDB and SFramesDB.enableUnitFrames == false then
        -- Keep Blizzard unit frames when Nanami frames are disabled
    else
        if not SFramesDB or SFramesDB.enablePlayerFrame ~= false then
            if PlayerFrame then
                PlayerFrame:UnregisterAllEvents()
                PlayerFrame:Hide()
                PlayerFrame.Show = function() end
            end
            if PetFrame then
                PetFrame:UnregisterAllEvents()
                PetFrame:Hide()
                PetFrame.Show = function() end
            end
        end

        if not SFramesDB or SFramesDB.enableTargetFrame ~= false then
            if TargetFrame then
                TargetFrame:UnregisterAllEvents()
                TargetFrame:Hide()
                TargetFrame.Show = function() end
            end
            if ComboFrame then
                ComboFrame:UnregisterAllEvents()
                ComboFrame:Hide()
                ComboFrame.Show = function() end
                ComboFrame.fadeInfo = ComboFrame.fadeInfo or {}
                if ComboFrame_Update then
                    ComboFrame_Update = function() end
                end
            end
        end

        if not SFramesDB or SFramesDB.enablePartyFrame ~= false then
            for i = 1, 4 do
                local pf = _G["PartyMemberFrame"..i]
                if pf then
                    pf:UnregisterAllEvents()
                    pf:Hide()
                    pf.Show = function() end
                end
            end
        end
    end
    
    -- Hide Native Raid Frames if SFrames raid is enabled
    if (not SFramesDB) or (SFramesDB.enableRaidFrames ~= false) then
        
        local function NeuterBlizzardRaidUI()
            if RaidFrame then
                RaidFrame:UnregisterAllEvents()
                RaidFrame:SetScript("OnEvent", nil)
                RaidFrame:SetScript("OnUpdate", nil)
            end
            
            for i = 1, NUM_RAID_GROUPS or 8 do
                local rgf = _G["RaidGroupButton"..i]
                if rgf then
                    rgf:UnregisterAllEvents()
                end
            end
            
            RaidPullout_Update = function() return {} end
            RaidPullout_OnEvent = function() return {} end
            RaidGroupFrame_OnEvent = function() return {} end
            RaidGroupFrame_Update = RaidGroupFrame_Update or function() end

            if not RAID_SUBGROUP_LISTS then RAID_SUBGROUP_LISTS = {} end
            for i = 1, NUM_RAID_GROUPS or 8 do
                if not RAID_SUBGROUP_LISTS[i] then
                    RAID_SUBGROUP_LISTS[i] = {}
                end
            end
            
            for i = 1, 40 do
                local pf = _G["RaidPullout"..i]
                if pf then
                    pf:UnregisterAllEvents()
                    pf:Hide()
                    pf.Show = function() end
                end
            end

            if CompactRaidFrameManager then
                CompactRaidFrameManager:UnregisterAllEvents()
                CompactRaidFrameManager:Hide()
                CompactRaidFrameManager.Show = function() end
            end
            if CompactRaidFrameContainer then
                CompactRaidFrameContainer:UnregisterAllEvents()
                CompactRaidFrameContainer:Hide()
                CompactRaidFrameContainer.Show = function() end
            end
        end

        NeuterBlizzardRaidUI()

        local raidHook = CreateFrame("Frame")
        raidHook:RegisterEvent("ADDON_LOADED")
        raidHook:SetScript("OnEvent", function()
            if arg1 == "Blizzard_RaidUI" then
                NeuterBlizzardRaidUI()
            end
        end)
    end

end
