-- =========================================================================
-- FILE: Target_Inspect_Situational_Awareness_System.lua
-- =========================================================================
local addonName, NS = ...

-- =========================================================================
-- A.X.I.O.M. TARGET INSPECT - SYSTEM OVERRIDE
-- REPLACES BLIZZARD INSPECT UI
-- PATCH 11.2.7+ COMPLIANT
-- =========================================================================

-- Main Frame Constants
local FRAME_WIDTH = 1000 
local FRAME_HEIGHT = 500
local HEADER_HEIGHT = 30

-- Database Initialization
AXIOM_InspectDB = AXIOM_InspectDB or {}

-- System State Flag
local AXIOM_Inspect_System_Enabled = true
local RESTORE_QUEUE = {}

-- Color Tokens
local COLOR_GOLD = "|cffffd100"
local COLOR_BLUE = "|cff66ccff"
local COLOR_GREEN = "|cff00ff00"
local COLOR_RED = "|cffff0000"
local COLOR_GREY = "|cff888888"
local COLOR_WHITE = "|cffffffff"

-- Specialization Color Overrides
local SPEC_COLORS = {
    [62]  = "ff9999ff", -- Arcane
    [63]  = "ffff5500", -- Fire
    [64]  = "ff66ccff", -- Frost
    [265] = "ff00cc00", -- Affliction
    [266] = "ff6633cc", -- Demonology
    [267] = "ffff8000", -- Destruction
}

-- BASE MODEL DISPLAY IDS
local RACE_BASE_MODELS = {
    [1]  = { [2] = 49,    [3] = 50 },    -- Human
    [2]  = { [2] = 51,    [3] = 52 },    -- Orc
    [3]  = { [2] = 53,    [3] = 54 },    -- Dwarf
    [4]  = { [2] = 55,    [3] = 56 },    -- Night Elf
    [5]  = { [2] = 57,    [3] = 58 },    -- Undead
    [6]  = { [2] = 59,    [3] = 60 },    -- Tauren
    [7]  = { [2] = 1563,  [3] = 1564 },  -- Gnome
    [8]  = { [2] = 1478,  [3] = 1479 },  -- Troll
    [9]  = { [2] = 1146,  [3] = 1147 },  -- Goblin
    [10] = { [2] = 15426, [3] = 15427 }, -- Blood Elf
    [11] = { [2] = 16125, [3] = 16126 }, -- Draenei
    [22] = { [2] = 29242, [3] = 29244 }, -- Worgen
    [24] = { [2] = 38551, [3] = 38552 }, -- Pandaren
}

local RACE_IDS = {
    ["Human"] = 1, ["Orc"] = 2, ["Dwarf"] = 3, ["NightElf"] = 4, ["Night Elf"] = 4,
    ["Undead"] = 5, ["Tauren"] = 6, ["Gnome"] = 7, ["Troll"] = 8,
    ["Goblin"] = 9, ["BloodElf"] = 10, ["Blood Elf"] = 10, ["Draenei"] = 11, ["Worgen"] = 22,
    ["Pandaren"] = 24
}

local INV_SLOTS = {
    { id = 1, name = "Head" }, { id = 2, name = "Neck" }, { id = 3, name = "Shoulder" },
    { id = 15, name = "Back" }, { id = 5, name = "Chest" }, { id = 9, name = "Wrist" },
    { id = 10, name = "Hands" }, { id = 6, name = "Waist" }, { id = 7, name = "Legs" },
    { id = 8, name = "Feet" }, { id = 11, name = "Finger0" }, { id = 12, name = "Finger1" },
    { id = 13, name = "Trinket0" }, { id = 14, name = "Trinket1" }, { id = 16, name = "MainHand" },
    { id = 17, name = "SecondaryHand" }
}

-- Dungeon Rotation
local DUNGEONS = {
    { short = "GMBT", id = 0 }, { short = "EDA", id = 0 }, { short = "STRT", id = 0 }, { short = "ARAK", id = 0 },
    { short = "HOA", id = 0 }, { short = "DAWN", id = 0 }, { short = "FLOOD", id = 0 }, { short = "PSF", id = 0 }
}

local GEM_STATS_DB = {
    ["Culminating Blasphemite"] = "+181 Prim. Stat + 1% Crit. Eff.",
    ["Elusive Blasphemite"]     = "+181 Prim. Stat + 2% Speed",
    ["Insightful Blasphemite"]  = "+181 Prim. Stat + 1% Mana",
    ["Quick Emerald"]           = "+317 Haste",
    ["Deadly Emerald"]          = "+190 Haste / +127 Crit.",
    ["Masterful Emerald"]       = "+190 Haste / +127 Mast.",
    ["Versatile Emerald"]       = "+190 Haste / +127 Vers.",
    ["Deadly Ruby"]             = "+317 Crit.",
    ["Quick Ruby"]              = "+190 Crit. / +127 Haste",
    ["Masterful Ruby"]          = "+190 Crit. / +127 Mast.",
    ["Versatile Ruby"]          = "+190 Crit. / +127 Vers.",
    ["Masterful Onyx"]          = "+317 Mast.",
    ["Quick Onyx"]              = "+190 Mast. / +127 Haste",
    ["Deadly Onyx"]             = "+190 Mast. / +127 Crit.",
    ["Versatile Onyx"]          = "+190 Mast. / +127 Vers.",
    ["Versatile Sapphire"]      = "+317 Vers.",
    ["Quick Sapphire"]          = "+190 Vers. / +127 Haste",
    ["Deadly Sapphire"]         = "+190 Vers. / +127 Crit.",
    ["Masterful Sapphire"]      = "+190 Vers. / +127 Mast.",
    ["Solid Amber"]             = "+317 Stam.",
    ["Quick Amber"]             = "+190 Stam. / +127 Haste",
    ["Deadly Amber"]            = "+190 Stam. / +127 Crit.",
    ["Masterful Amber"]         = "+190 Stam. / +127 Mast.",
    ["Versatile Amber"]         = "+190 Stam. / +127 Vers."
}

-- =========================================================================
-- 1. HELPERS & RAIDER.IO ENGINE
-- =========================================================================

local function GetRegionName()
    local regionID = GetCurrentRegion()
    if regionID == 1 then return "us"
    elseif regionID == 2 then return "kr"
    elseif regionID == 3 then return "eu"
    elseif regionID == 4 then return "tw"
    elseif regionID == 5 then return "cn"
    else return "us" end
end

local function GetFactionID(unit)
    if not unit then return 1 end 
    local factionGroup = UnitFactionGroup(unit)
    if factionGroup == "Alliance" then return 1 else return 2 end
end

local function GetRioColor(s)
    if not s or s == 0 then return "|cffffffff" end
    if s >= 3000 then return "|cffff8000" 
    elseif s >= 2500 then return "|cffa335ee" 
    elseif s >= 2000 then return "|cff0070dd" 
    elseif s >= 1000 then return "|cff1eff00" 
    else return "|cffffffff" end
end

local function GetProgColor(str)
    if not str or str == "-" then return "|cff888888" end -- GREY
    local kills = tonumber(string.match(str, "^(%d+)")) or 0
    if kills == 8 then return "|cffff8000" -- ORANGE
    elseif kills >= 5 then return "|cffa335ee" -- PURPLE
    elseif kills > 0 then return "|cff00ff00" -- GREEN
    else return "|cff888888" end
end

local function GetIlvlColor(ilvl)
    local val = tonumber(ilvl) or 0
    local _, _, _, toc = GetBuildInfo()
    if toc >= 120000 then 
        if val > 160 then return "|cffff8000"
        elseif val >= 145 then return "|cffa335ee"
        else return "|cff00ff00" end
    else 
        if val > 727 then return "|cffff8000"
        elseif val >= 715 then return "|cffa335ee"
        else return "|cff00ff00" end
    end
end

-- =========================================================================
-- RAIDER.IO LOGIC
-- =========================================================================
-- Never touch
local function FetchRaiderIOData(unit, nameOverride, realmOverride, factionOverride)
    local results = {
        score = 0, raidN = "-", raidH = "-", raidM = "-", dungeons = {}
    }
    
    if not _G.RaiderIO or not _G.RaiderIO.GetProfile then return results end

    local name, realm, factionID
    
    if unit and UnitExists(unit) then
        name, realm = UnitFullName(unit)
        factionID = GetFactionID(unit)
    else
        name = nameOverride
        realm = realmOverride
        factionID = factionOverride or 1
    end
    
    if not realm then realm = GetRealmName() end 
    local region = GetRegionName()

    local p = _G.RaiderIO.GetProfile(name, realm, factionID)
    if not p then
        -- Try other faction
        local otherFaction = (factionID == 1) and 2 or 1
        p = _G.RaiderIO.GetProfile(name, realm, otherFaction)
    end
    if not p then 
        -- Try region wide fallbacks if supported
        p = _G.RaiderIO.GetProfile(name, realm, region) 
    end

    if p then
        if p.mythicKeystoneProfile then
            results.score = p.mythicKeystoneProfile.currentScore or 0
        end

        if p.raidProfile and p.raidProfile.progress then
            local currentTierPriority = 0
            for _, prog in ipairs(p.raidProfile.progress) do
                local rName = string.lower(prog.raid and prog.raid.name or "")
                local tier = 0
                if string.find(rName, "manaforge") or string.find(rName, "omega") then tier = 3
                elseif string.find(rName, "liberation") or string.find(rName, "undermine") then tier = 2
                elseif string.find(rName, "nerub") or string.find(rName, "palace") then tier = 1 end

                if tier > 0 and tier >= currentTierPriority then
                    if tier > currentTierPriority then
                        results.raidN, results.raidH, results.raidM = "-", "-", "-"
                        currentTierPriority = tier
                    end
                    local kills = prog.progressCount or 0
                    local total = prog.raid and prog.raid.bossCount or 8
                    local str = kills .. "/" .. total
                    if prog.difficulty == 1 then results.raidN = str
                    elseif prog.difficulty == 2 then results.raidH = str
                    elseif prog.difficulty == 3 then results.raidM = str end
                end
            end
        end

        if p.mythicKeystoneProfile and p.mythicKeystoneProfile.sortedDungeons then
            for _, run in ipairs(p.mythicKeystoneProfile.sortedDungeons) do
                if run.dungeon and run.dungeon.shortName then
                    results.dungeons[run.dungeon.shortName] = run.level
                end
            end
        end
    end
    return results
end
-- Never touch

local function GetSpecColor(specID, classFile)
    if SPEC_COLORS[specID] then
        return "|c" .. SPEC_COLORS[specID]
    else
        local c = C_ClassColor.GetClassColor(classFile or "PRIEST")
        return c and c:GenerateHexColorMarkup() or "|cffffffff"
    end
end

-- =========================================================================
-- 2. FRAME SETUP & STERILIZATION
-- =========================================================================

local AXIOM_Inspect = CreateFrame("Frame", "AXIOM_Target_Inspect_Frame", UIParent, "BackdropTemplate")
AXIOM_Inspect:Hide()
AXIOM_Inspect.unit = "target" 
AXIOM_Inspect.snapshot = nil 
AXIOM_Inspect.snapshotMeta = nil 
AXIOM_Inspect.currentGuid = nil 
AXIOM_Inspect.ShowExtras = false 

local AXIOM_InspectDump = CreateFrame("Frame", "AXIOM_InspectDump", UIParent)
AXIOM_InspectDump:SetSize(1,1); AXIOM_InspectDump:Hide()

local function SterilizeInspectUI()
    if InCombatLockdown() then return end
    if not AXIOM_Inspect_System_Enabled then return end

    if InspectFrame and InspectFrame:GetParent() ~= AXIOM_InspectDump then 
        if not RESTORE_QUEUE[InspectFrame] then
            RESTORE_QUEUE[InspectFrame] = InspectFrame:GetParent()
        end
        InspectFrame:SetParent(AXIOM_InspectDump)
        InspectFrame:Hide()
        InspectFrame:UnregisterAllEvents() 
    end
    
    if InspectPaperDollFrame and InspectPaperDollFrame:GetParent() ~= AXIOM_InspectDump then 
        if not RESTORE_QUEUE[InspectPaperDollFrame] then
            RESTORE_QUEUE[InspectPaperDollFrame] = InspectPaperDollFrame:GetParent()
        end
        InspectPaperDollFrame:SetParent(AXIOM_InspectDump)
        InspectPaperDollFrame:Hide()
    end
end

local function RestoreInspectUI()
    if InCombatLockdown() then return end
    
    if InspectFrame and RESTORE_QUEUE[InspectFrame] then
        InspectFrame:SetParent(RESTORE_QUEUE[InspectFrame] or UIParent)
        -- Don't necessarily Show() unless triggered by event, but we restore state
    end
    
    if InspectPaperDollFrame and RESTORE_QUEUE[InspectPaperDollFrame] then
        InspectPaperDollFrame:SetParent(RESTORE_QUEUE[InspectPaperDollFrame] or InspectFrame)
    end
    
    RESTORE_QUEUE = {}
end

-- PUBLIC API for Settings.lua
function AXIOM_Inspect:ToggleSystem(enabled)
    AXIOM_Inspect_System_Enabled = enabled
    
    if enabled then
        -- If we were looking at InspectFrame, switch immediately
        if InspectFrame and InspectFrame:IsShown() then
            local unit = InspectFrame.unit or "target"
            SterilizeInspectUI()
            AXIOM_Inspect.unit = unit
            AXIOM_Inspect.snapshot = nil
            AXIOM_Inspect:Show()
            AXIOM_Inspect:UpdateData()
        end
    else
        -- Restore native
        if AXIOM_Inspect:IsShown() then
            AXIOM_Inspect:Hide()
            RestoreInspectUI()
            if InspectFrame and UnitExists("target") then
                InspectUnit("target") -- Trigger native inspect
            end
        else
            RestoreInspectUI()
        end
    end
end

local function BuildFrame()
    AXIOM_Inspect:SetSize(FRAME_WIDTH, FRAME_HEIGHT)
    AXIOM_Inspect:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
    AXIOM_Inspect:SetMovable(true)
    
    -- [[ STRATA ELEVATION PROTOCOL ]]
    AXIOM_Inspect:SetFrameStrata("FULLSCREEN") 
    AXIOM_Inspect:SetFrameLevel(900)
    
    local bg = AXIOM_Inspect:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints(AXIOM_Inspect)
    bg:SetColorTexture(0.05, 0.05, 0.05, 0.98)

    local border = CreateFrame("Frame", nil, AXIOM_Inspect, "BackdropTemplate")
    border:SetAllPoints()
    border:SetBackdrop({ edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", edgeSize = 16 })
    border:SetBackdropBorderColor(0.2, 0.2, 0.2, 1)

    local header = CreateFrame("Frame", nil, AXIOM_Inspect)
    header:SetSize(FRAME_WIDTH, HEADER_HEIGHT)
    header:SetPoint("TOP", AXIOM_Inspect, "TOP", 0, 0)
    header:EnableMouse(true)
    header:RegisterForDrag("LeftButton")
    header:SetScript("OnDragStart", function() AXIOM_Inspect:StartMoving() end)
    header:SetScript("OnDragStop", function() AXIOM_Inspect:StopMovingOrSizing() end)
    
    local hbg = header:CreateTexture(nil, "BACKGROUND")
    hbg:SetAllPoints()
    hbg:SetColorTexture(0, 0, 0, 1)

    AXIOM_Inspect.Title = header:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    AXIOM_Inspect.Title:SetPoint("LEFT", 10, 0)
    AXIOM_Inspect.Title:SetText(COLOR_BLUE .. "A.X.I.O.M.|r | " .. COLOR_GOLD .. "TARGET INSPECTOR|r")

    local close = CreateFrame("Button", nil, header, "BackdropTemplate")
    close:SetSize(20, 20)
    close:SetPoint("TOPRIGHT", -5, -5)
    close:SetBackdrop({ bgFile = "Interface\\ChatFrame\\ChatFrameBackground" })
    close:SetBackdropColor(0.2, 0.1, 0.1, 1)
    
    local closeTxt = close:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    closeTxt:SetPoint("CENTER", 0, 0); closeTxt:SetText("X"); closeTxt:SetTextColor(1, 1, 1)
    close:SetScript("OnClick", function() AXIOM_Inspect:Hide() end)
end

-- =========================================================================
-- 3. INSPECT ARMORY (LEFT)
-- =========================================================================

local ScannerTooltip = CreateFrame("GameTooltip", "AXIOM_Target_ScannerTooltip", nil, "GameTooltipTemplate")
ScannerTooltip:SetOwner(UIParent, "ANCHOR_NONE")

local function AXIOM_GetGemStats(gemID)
    if not gemID then return nil end
    local name = GetItemInfo(gemID)
    if not name then return "Loading..." end 
    if GEM_STATS_DB[name] then return GEM_STATS_DB[name] end
    return name
end

local function GetItemExtras(unit, slotID, itemLinkOverride)
    local link = itemLinkOverride
    if not link and unit then link = GetInventoryItemLink(unit, slotID) end
    if not link then return nil end
    
    local info = { enchant = nil, gems = {}, embellish = nil }
    
    ScannerTooltip:ClearLines()
    ScannerTooltip:SetHyperlink(link)
    local lines = ScannerTooltip:NumLines()
    
    for i = 2, lines do
        local line = _G["AXIOM_Target_ScannerTooltipTextLeft"..i]
        if line then
            local text = line:GetText() or ""
            if string.find(text, "^Enchanted: ") then
                info.enchant = string.gsub(text, "^Enchanted: ", "")
            end
            if string.find(text, "Embellished") then
                info.embellish = "Embellished"
            elseif string.find(text, "Unique%-Equipped: .* %(%d%)") then
                info.embellish = "Crafted"
            end
        end
    end

    local itemString = string.match(link, "item[%-?%d:]+") or ""
    local parts = { strsplit(":", itemString) }
    
    for i = 4, 7 do
        if parts[i] and parts[i] ~= "" and parts[i] ~= "0" then
            local gemID = tonumber(parts[i])
            if gemID then
                local statStr = AXIOM_GetGemStats(gemID)
                table.insert(info.gems, statStr)
            end
        end
    end
    return info
end

local function BuildArmoryLeft()
    local left = CreateFrame("Frame", nil, AXIOM_Inspect)
    left:SetSize(400, FRAME_HEIGHT - HEADER_HEIGHT) 
    left:SetPoint("TOPLEFT", AXIOM_Inspect, "TOPLEFT", 10, -HEADER_HEIGHT - 10)
    AXIOM_Inspect.LeftPane = left

    left.Name = left:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    left.Name:SetPoint("TOP", 0, -10); left.Name:SetText("Scanning...")
    
    left.Guild = left:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    left.Guild:SetPoint("TOP", left.Name, "BOTTOM", 0, -5); left.Guild:SetText("")
    
    left.Details = left:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    left.Details:SetPoint("TOP", left.Guild, "BOTTOM", 0, -5); left.Details:SetText("...")

    local charFrame = CreateFrame("Frame", nil, left)
    charFrame:SetAllPoints()
    AXIOM_Inspect.CharFrame = charFrame

    local extraBtn = CreateFrame("Button", nil, charFrame, "GameMenuButtonTemplate")
    extraBtn:SetSize(100, 20)
    extraBtn:SetPoint("TOP", left.Details, "BOTTOM", 0, -5)
    extraBtn:SetText("Toggle Extra's")
    extraBtn:SetScript("OnClick", function()
        AXIOM_Inspect.ShowExtras = not AXIOM_Inspect.ShowExtras
        AXIOM_Inspect:UpdateItems() 
    end)

    -- [[ 3D MODEL FIX ]]
    -- Switched to DressUpModel to support Undress/TryOn methods for offline snapshots
    charFrame.Model = CreateFrame("DressUpModel", nil, charFrame)
    charFrame.Model:SetSize(250, 280)
    charFrame.Model:SetPoint("CENTER", 0, -30)
    charFrame.Model:SetKeepModelOnHide(true) 
    charFrame.Model:SetFrameLevel(950) -- Z-Depth Override
    
    -- Enable Mouse Rotation using SetFacing (Radians)
    charFrame.Model:EnableMouse(true)
    charFrame.Model:SetScript("OnMouseDown", function(self) self.lastX = GetCursorPosition() end)
    charFrame.Model:SetScript("OnMouseUp", function(self) self.lastX = nil end)
    charFrame.Model:SetScript("OnUpdate", function(self)
        if self.lastX then
            local x = GetCursorPosition()
            local diff = (x - self.lastX) * 0.02
            -- API COMPLIANCE: Use SetFacing (Radians) for 10.0+
            if self.GetFacing then
                self:SetFacing(self:GetFacing() + diff)
            else
                -- Fallback for legacy clients if needed
                if self.GetRotation then self:SetRotation(self:GetRotation() + diff) end
            end
            self.lastX = x
        end
    end)
    
    -- Error Text for Missing Visual Data
    charFrame.ErrorText = charFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    charFrame.ErrorText:SetPoint("CENTER", charFrame.Model, "CENTER", 0, 0)
    charFrame.ErrorText:SetText(COLOR_RED .. "VISUAL DATA MISSING\nTARGET ADDON OUTDATED|r")
    charFrame.ErrorText:Hide()

    AXIOM_Inspect.Slots = {}
    local startY = -70
    local slotSize = 40 
    
    for i, slotData in ipairs(INV_SLOTS) do
        local slot = CreateFrame("Button", nil, charFrame, "BackdropTemplate")
        slot:SetSize(slotSize, slotSize)
        slot:SetFrameLevel(950) 
        
        slot:SetBackdrop({ bgFile = "Interface\\ChatFrame\\ChatFrameBackground", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", edgeSize = 1 })
        slot:SetBackdropColor(0, 0, 0, 0.5)
        
        local isLeft = (i <= 8)
        if isLeft then 
            slot:SetPoint("TOPLEFT", 0, startY - ((i-1)*(slotSize + 5)))
        else 
            slot:SetPoint("TOPRIGHT", 0, startY - ((i-9)*(slotSize + 5))) 
        end
        
        slot.icon = slot:CreateTexture(nil, "ARTWORK"); slot.icon:SetAllPoints(); slot.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)

        local dimmer = slot:CreateTexture(nil, "OVERLAY")
        dimmer:SetAllPoints(); dimmer:SetColorTexture(0, 0, 0, 0.25)
        slot.Dimmer = dimmer

        local ilvlTxt = slot:CreateFontString(nil, "OVERLAY")
        ilvlTxt:SetFont("Fonts\\FRIZQT__.TTF", 14, "OUTLINE") 
        ilvlTxt:SetPoint("BOTTOM", slot, "BOTTOM", 0, 2)
        ilvlTxt:SetJustifyH("CENTER")
        slot.IlvlText = ilvlTxt
        
        local extraTxt = slot:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        if isLeft then extraTxt:SetPoint("LEFT", slot, "RIGHT", 5, 0); extraTxt:SetJustifyH("LEFT")
        else extraTxt:SetPoint("RIGHT", slot, "LEFT", -5, 0); extraTxt:SetJustifyH("RIGHT") end
        slot.ExtraText = extraTxt
        
        slot:SetScript("OnEnter", function(self)
            GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
            if AXIOM_Inspect.snapshot then
                if self.cachedLink then GameTooltip:SetHyperlink(self.cachedLink) end
            elseif AXIOM_Inspect.unit then
                local link = GetInventoryItemLink(AXIOM_Inspect.unit, slotData.id)
                if link then GameTooltip:SetHyperlink(link) else GameTooltip:SetText(slotData.name) end
            end
            GameTooltip:Show()
        end)
        slot:SetScript("OnLeave", function() GameTooltip:Hide() end)
        
        slot:RegisterForClicks("LeftButtonUp")
        slot:SetScript("OnClick", function(self)
            local link = nil
            if AXIOM_Inspect.snapshot then link = self.cachedLink 
            elseif AXIOM_Inspect.unit then link = GetInventoryItemLink(AXIOM_Inspect.unit, slotData.id) end
            if link and ChatEdit_InsertLink then ChatEdit_InsertLink(link) end
        end)

        AXIOM_Inspect.Slots[slotData.id] = slot
    end

    local pvpFrame = CreateFrame("Frame", nil, left)
    pvpFrame:SetAllPoints(); pvpFrame:Hide()
    AXIOM_Inspect.PvpFrame = pvpFrame

    pvpFrame.rows = {}
    local pvpLabels = { "Honor Level", "2v2 Rating", "3v3 Rating", "RBG Rating", "Solo Shuffle" }
    for i, label in ipairs(pvpLabels) do
        local r = CreateFrame("Frame", nil, pvpFrame, "BackdropTemplate")
        r:SetSize(300, 30)
        r:SetPoint("TOP", 0, -60 - ((i-1)*40))
        r:SetBackdrop({ bgFile = "Interface\\ChatFrame\\ChatFrameBackground", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", edgeSize = 10 })
        r:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
        r.lbl = r:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        r.lbl:SetPoint("LEFT", 10, 0); r.lbl:SetText(label)
        r.val = r:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
        r.val:SetPoint("RIGHT", -10, 0); r.val:SetText("-")
        pvpFrame.rows[i] = r
    end

    local guildFrame = CreateFrame("Frame", nil, left)
    guildFrame:SetAllPoints(); guildFrame:Hide()
    AXIOM_Inspect.GuildFrame = guildFrame

    local gName = guildFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalHuge")
    gName:SetPoint("CENTER", 0, 50); gName:SetText("-")
    AXIOM_Inspect.GuildName = gName
    local gRank = guildFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
    gRank:SetPoint("TOP", gName, "BOTTOM", 0, -10); gRank:SetText("Rank: -")
    AXIOM_Inspect.GuildRank = gRank
    local gRealm = guildFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    gRealm:SetPoint("TOP", gRank, "BOTTOM", 0, -10); gRealm:SetText("Realm: -")
    AXIOM_Inspect.GuildRealm = gRealm

    AXIOM_Inspect.Tabs = {}
    local tabNames = {"Character", "PVP", "Guild"}
    local function SetTab(id)
        AXIOM_Inspect.CharFrame:Hide()
        AXIOM_Inspect.PvpFrame:Hide()
        AXIOM_Inspect.GuildFrame:Hide()
        
        for k, t in pairs(AXIOM_Inspect.Tabs) do
            t.bg:SetColorTexture(0.1, 0.1, 0.1, 1) 
            t.text:SetTextColor(0.5, 0.41, 0)
        end
        AXIOM_Inspect.Tabs[id].bg:SetColorTexture(0.5, 0.5, 0.5, 1)
        AXIOM_Inspect.Tabs[id].text:SetTextColor(1, 0.82, 0)

        if id == 1 then AXIOM_Inspect.CharFrame:Show()
        elseif id == 2 then AXIOM_Inspect.PvpFrame:Show()
        elseif id == 3 then AXIOM_Inspect.GuildFrame:Show() end
    end

    for i, txt in ipairs(tabNames) do
        local btn = CreateFrame("Button", nil, left)
        btn:SetSize(90, 25)
        btn:SetPoint("BOTTOMLEFT", (i-1)*95 + 5, -10)
        btn.bg = btn:CreateTexture(nil, "BACKGROUND"); btn.bg:SetAllPoints()
        btn.text = btn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        btn.text:SetPoint("CENTER"); btn.text:SetText(txt)
        btn:SetScript("OnClick", function() SetTab(i) end)
        AXIOM_Inspect.Tabs[i] = btn
    end
    
    local talBtn = CreateFrame("Button", nil, left, "BackdropTemplate")
    talBtn:SetSize(80, 25)
    talBtn:SetPoint("BOTTOMRIGHT", -5, -10)
    talBtn:SetFrameLevel(950) 
    talBtn:SetBackdrop({ bgFile = "Interface\\ChatFrame\\ChatFrameBackground", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", edgeSize = 12 })
    talBtn:SetBackdropColor(0.2, 0.2, 0.2, 1)
    talBtn:SetBackdropBorderColor(0.4, 0.4, 0.4, 1)
    local talTxt = talBtn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    talTxt:SetPoint("CENTER"); talTxt:SetText("Talents"); talBtn:SetFontString(talTxt)
    talBtn:SetScript("OnEnter", function(self) self:SetBackdropBorderColor(1, 1, 1, 1) end)
    talBtn:SetScript("OnLeave", function(self) self:SetBackdropBorderColor(0.4, 0.4, 0.4, 1) end)
    talBtn:SetScript("OnClick", function()
        if AXIOM_Inspect.snapshot then print("AXIOM: Talents unavailable for offline members."); return end
        local unit = AXIOM_Inspect.unit
        if not unit or not UnitExists(unit) then print("AXIOM: No valid unit to inspect."); return end
        if not C_AddOns.IsAddOnLoaded("Blizzard_InspectUI") then C_AddOns.LoadAddOn("Blizzard_InspectUI"); SterilizeInspectUI() end
        if _G.InspectPaperDollItemsFrame and _G.InspectPaperDollItemsFrame.InspectTalents then
            if _G.InspectPaperDollFrame then _G.InspectPaperDollFrame.unit = unit end
            _G.InspectPaperDollItemsFrame.InspectTalents:Click()
        else print("|cffff0000AXIOM ERROR:|r Blizzard InspectTalents button not found.") end
    end)

    SetTab(1)
end

-- =========================================================================
-- 4. INSPECT STATS (MIDDLE)
-- =========================================================================

local function BuildStatsMiddle()
    local middle = CreateFrame("Frame", nil, AXIOM_Inspect)
    middle:SetSize(250, FRAME_HEIGHT - HEADER_HEIGHT)
    middle:SetPoint("TOPLEFT", AXIOM_Inspect, "TOPLEFT", 420, -HEADER_HEIGHT - 10) 

    local ilvlLabel = middle:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    ilvlLabel:SetPoint("TOP", 0, -20); ilvlLabel:SetText("Item Level")
    
    middle.ILVL = middle:CreateFontString("AXIOM_Target_ILVL", "OVERLAY", "GameFontNormalHuge")
    middle.ILVL:SetPoint("TOP", ilvlLabel, "BOTTOM", 0, -5); middle.ILVL:SetText("-")

    AXIOM_Inspect.StatsFrame = middle
end

local function GetWidget(parent, key, wType)
    if not parent.Widgets then parent.Widgets = {} end
    if not parent.Widgets[key] then
        local w
        if wType == "ROW" then
            w = CreateFrame("Frame", nil, parent)
            w:SetSize(200, 20)
            local t = w:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
            t:SetPoint("LEFT", 0, 0)
            local v = w:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
            v:SetPoint("RIGHT", 0, 0)
            w.Label = t; w.Value = v
        elseif wType == "HEADER" then
            w = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal"); w:SetJustifyH("CENTER")
        elseif wType == "SEPARATOR" then
            w = parent:CreateTexture(nil, "OVERLAY"); w:SetColorTexture(1, 0.82, 0, 0.5); w:SetSize(220, 1)
        end
        parent.Widgets[key] = w
    end
    return parent.Widgets[key]
end

function AXIOM_Inspect:RebuildStatRows()
    local middle = self.StatsFrame
    if not middle then return end
    if middle.Widgets then for _, w in pairs(middle.Widgets) do w:Hide() end end

    local unit = self.unit or "target"
    
    local layout = {
        { type = "HEADER", key = "HEAD_ATTR", text = "Attributes" },
        { type = "ROW", key = "ROW_STR", label="Str.", id=1 },
        { type = "ROW", key = "ROW_AGI", label="Agi.", id=2 },
        { type = "ROW", key = "ROW_INT", label="Int.", id=4 },
        { type = "ROW", key = "ROW_STAM", label="Stam.", id=3 },
        { type = "SEPARATOR", key = "SEP_1" },
        { type = "HEADER", key = "HEAD_SEC", text = "Enhancements" },
        { type = "ROW", key = "ROW_CRIT", label="Crit", statKey="crit", fmt="%.1f%%" },
        { type = "ROW", key = "ROW_HASTE", label="Haste", statKey="haste", fmt="%.1f%%" },
        { type = "ROW", key = "ROW_MAST", label="Mastery", statKey="mast", fmt="%.1f%%" },
        { type = "ROW", key = "ROW_VERS", label="Versatility", statKey="vers", fmt="%.1f%%" }
    }

    local currentY = -70 
    for _, elem in ipairs(layout) do
        local w = GetWidget(middle, elem.key, elem.type)
        if w then
            w:Show()
            if elem.type == "HEADER" then
                w:SetPoint("TOP", 0, currentY)
                w:SetText(COLOR_GOLD .. elem.text .. "|r")
                currentY = currentY - 20
            elseif elem.type == "SEPARATOR" then
                w:SetPoint("TOP", 0, currentY)
                currentY = currentY - 5
            elseif elem.type == "ROW" then
                w:SetPoint("TOP", 0, currentY)
                w.Label:SetText(elem.label)
                
                local valText = "-"
                
                if self.snapshot and self.snapshot.stats then
                    -- SNAPSHOT MODE: Read from DB packet
                    local s = self.snapshot.stats
                    if elem.id then
                        -- Primary Stats
                        local val = 0
                        if elem.id == 1 then val = s.str
                        elseif elem.id == 2 then val = s.agi
                        elseif elem.id == 3 then val = s.sta
                        elseif elem.id == 4 then val = s.int end
                        
                        -- Color logic for primaries (White if > 0)
                        if val and val > 0 then
                             valText = BreakUpLargeNumbers(val)
                             w.Value:SetTextColor(1, 1, 1, 1)
                        else
                             valText = "-"
                             w.Value:SetTextColor(0.5, 0.5, 0.5, 1)
                        end
                    elseif elem.statKey then
                        -- Secondary Stats
                        local val = s[elem.statKey]
                        if val and val > 0 then
                            valText = string.format(elem.fmt, val)
                            w.Value:SetTextColor(1, 1, 1, 1)
                        else
                            valText = "0.0%"
                            w.Value:SetTextColor(0.5, 0.5, 0.5, 1)
                        end
                    end
                elseif elem.id and UnitExists(unit) then
                    -- LIVE MODE: Scan Unit (Primaries Only available via API reliably)
                    -- Secondaries on remote targets are hard to get without LibStatLogic
                    local val = UnitStat(unit, elem.id) or 0
                    if val > 0 then
                        valText = BreakUpLargeNumbers(val)
                        w.Value:SetTextColor(1, 1, 1, 1)
                    else
                        w.Value:SetTextColor(0.5, 0.5, 0.5, 1)
                    end
                else
                    -- Fallback for Secondaries in Live Mode (Not Scannable easily)
                    if elem.statKey then
                        valText = "N/A" 
                        w.Value:SetTextColor(0.5, 0.5, 0.5, 1)
                    end
                end
                
                w.Value:SetText(valText)
                currentY = currentY - 20
            end
        end
    end
end

-- =========================================================================
-- 5. INSPECT INTEL (RIGHT)
-- =========================================================================

local function BuildIntelRight()
    local right = CreateFrame("Frame", nil, AXIOM_Inspect)
    right:SetSize(300, FRAME_HEIGHT - HEADER_HEIGHT)
    right:SetPoint("TOPLEFT", AXIOM_Inspect, "TOPLEFT", 680, -HEADER_HEIGHT - 10) 
    AXIOM_Inspect.Intel = right

    local scoreLabel = right:CreateFontString("AXIOM_Target_Score", "OVERLAY", "GameFontNormalLarge")
    scoreLabel:SetPoint("TOP", 0, -20); scoreLabel:SetText("M+ Score: -")
    scoreLabel:SetTextColor(1, 0.5, 0) -- Orange tint placeholder, updated dynamically

    local raidHeader = right:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    raidHeader:SetPoint("TOP", 0, -50); raidHeader:SetText(COLOR_GOLD .. "Raid Progress|r")

    -- Columns: Normal | Heroic | Mythic
    local lblN = right:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    lblN:SetPoint("TOPLEFT", 35, -75); lblN:SetText(COLOR_GOLD.."Normal|r")

    local lblH = right:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    lblH:SetPoint("TOPLEFT", 130, -75); lblH:SetText(COLOR_GOLD.."Heroic|r")

    local lblM = right:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    lblM:SetPoint("TOPLEFT", 225, -75); lblM:SetText(COLOR_GOLD.."Mythic|r")

    -- VALUES
    AXIOM_Inspect.Intel.RaidNorm = right:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
    AXIOM_Inspect.Intel.RaidNorm:SetPoint("TOPLEFT", 35, -90); AXIOM_Inspect.Intel.RaidNorm:SetText("-")

    AXIOM_Inspect.Intel.RaidHeroic = right:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
    AXIOM_Inspect.Intel.RaidHeroic:SetPoint("TOPLEFT", 130, -90); AXIOM_Inspect.Intel.RaidHeroic:SetText("-")

    AXIOM_Inspect.Intel.RaidMythic = right:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
    AXIOM_Inspect.Intel.RaidMythic:SetPoint("TOPLEFT", 225, -90); AXIOM_Inspect.Intel.RaidMythic:SetText("-")

    AXIOM_Inspect.Intel.DungeonStrings = {}
    -- Layout: 2 Columns. 4 Rows. Start Y -150.
    for i, d in ipairs(DUNGEONS) do
        local row = math.floor((i-1)/2)
        local col = (i-1)%2
        local dFrame = CreateFrame("Frame", nil, right)
        
        -- Panel Width 300.
        -- Col 1 X: ~40. Col 2 X: ~165.
        
        dFrame:SetSize(90, 40)
        dFrame:SetPoint("TOPLEFT", 40 + (col*125), -150 - (row*50))
        
        local lbl = dFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        lbl:SetPoint("TOPLEFT", 0, 0); lbl:SetText(d.short)
        
        local valStr = dFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
        valStr:SetPoint("TOPLEFT", 0, -15); valStr:SetText("-")
        
        AXIOM_Inspect.Intel.DungeonStrings[d.short] = valStr
    end
end

-- =========================================================================
-- 6. ENGINE & UPDATES
-- =========================================================================

function AXIOM_Inspect:ClearData()
    self.LeftPane.Name:SetText("Scanning...")
    self.LeftPane.Guild:SetText("")
    self.LeftPane.Details:SetText("...")
    self.CharFrame.Model:ClearModel()
    self.CharFrame.ErrorText:Hide() -- Hide error text on clear
    self.StatsFrame.ILVL:SetText("-")
    for _, btn in pairs(self.Slots) do
        btn.icon:SetTexture("Interface\\PaperDoll\\UI-Backpack-EmptySlot")
        btn.ExtraText:SetText("")
        btn.IlvlText:SetText("")
        btn.cachedLink = nil 
    end
    _G["AXIOM_Target_Score"]:SetText("M+ Score: ...")
    self.Intel.RaidNorm:SetText("...")
    self.Intel.RaidHeroic:SetText("...")
    self.Intel.RaidMythic:SetText("...")
    for i=1, #self.PvpFrame.rows do self.PvpFrame.rows[i].val:SetText("-") end
    self.GuildName:SetText("-"); self.GuildRank:SetText("-"); self.GuildRealm:SetText("-")
end

function AXIOM_Inspect:UpdateItems()
    local unit = self.unit
    for id, btn in pairs(self.Slots) do
        local texture = nil
        local link = nil
        
        if self.snapshot and self.snapshot.gear then
            for _, gString in ipairs(self.snapshot.gear) do
                local slotIDStr, itemString = strsplit("=", gString)
                if tonumber(slotIDStr) == id then
                    link = "item:"..itemString
                    btn.cachedLink = link 
                    local itemID = GetItemInfoInstant(link)
                    if itemID then texture = C_Item.GetItemIconByID(itemID) end
                    break
                end
            end
        else
            link = GetInventoryItemLink(unit, id)
            if link then
                texture = select(10, GetItemInfo(link))
                if not texture then
                    local itemID = GetItemInfoInstant(link)
                    if itemID then texture = C_Item.GetItemIconByID(itemID) end
                end
            end
            if not texture then texture = GetInventoryItemTexture(unit, id) end
        end

        if texture then btn.icon:SetTexture(texture)
        else btn.icon:SetTexture("Interface\\PaperDoll\\UI-Backpack-EmptySlot") end
        
        btn.IlvlText:SetText("")
        if link then
            local actualIlvl = GetDetailedItemLevelInfo(link)
            -- [FIX: Fallback if detailed info is missing from cache]
            if not actualIlvl or actualIlvl == 0 then
                actualIlvl = select(4, GetItemInfo(link)) or 0
            end

            local colorCode = "|cffffffff" 
            
            local currentUpgrade, maxUpgrade = 0, 0
            
            if unit and UnitExists(unit) then
                 local data = C_TooltipInfo.GetInventoryItem(unit, id)
                 if data and data.lines then
                     for _, line in ipairs(data.lines) do
                         local txt = line.leftText
                         if txt then
                             local cur, max = string.match(txt, "Upgrade Level: .+ (%d+)/(%d+)")
                             if not cur then cur, max = string.match(txt, "(%d+)/(%d+)") end
                             if cur and max then
                                 currentUpgrade = tonumber(cur)
                                 maxUpgrade = tonumber(max)
                                 break
                             end
                         end
                     end
                 end
            end

            if maxUpgrade > 0 then
                if currentUpgrade == 8 then colorCode = "|cffff8000" -- Orange
                elseif currentUpgrade >= 5 then colorCode = "|cffa335ee" -- Purple
                else colorCode = "|cff00ff00" -- Green
                end
            else
                local _, _, quality = GetItemInfo(link)
                if quality then
                    local _, _, _, hex = GetItemQualityColor(quality)
                    colorCode = "|c" .. hex
                end
            end
            btn.IlvlText:SetText(colorCode .. actualIlvl .. "|r")
        end
        
        btn.ExtraText:SetText("")
        if self.ShowExtras then
            local info = GetItemExtras(unit, id, link) 
            if info then
                local txt = ""
                if info.enchant then txt = txt .. COLOR_GREEN .. info.enchant .. "|r\n" end
                for _, statStr in ipairs(info.gems) do txt = txt .. COLOR_BLUE .. statStr .. "|r\n" end
                if info.embellish then txt = txt .. COLOR_GOLD .. info.embellish .. "|r" end
                btn.ExtraText:SetText(txt)
            end
        end
    end
end

function AXIOM_Inspect:ReconstructModel()
    if not self.snapshot or not self.snapshotMeta then return end
    
    local raceName = self.snapshotMeta.race
    local sexID = self.snapshotMeta.sex or 2 
    local sexKey = 2 
    if sexID == 3 or sexID == "Female" then sexKey = 3 end
    local raceID = 1 
    if raceName and RACE_IDS[raceName] then raceID = RACE_IDS[raceName] end
    
    local displayID = 49 -- Fallback human
    if RACE_BASE_MODELS[raceID] and RACE_BASE_MODELS[raceID][sexKey] then
            displayID = RACE_BASE_MODELS[raceID][sexKey]
    end
    
    -- CHECK FOR APPEARANCE DATA
    local hasVisuals = false
    if self.snapshot.appearance and self.snapshot.appearance.raceID then
        hasVisuals = true
    end

    if hasVisuals then
        self.CharFrame.ErrorText:Hide()
        self.CharFrame.Model:Show()
        self.CharFrame.Model:SetDisplayInfo(displayID)
        self.CharFrame.Model:Undress()
        
        -- Apply Gear
        if self.snapshot.gear then
            for _, gString in ipairs(self.snapshot.gear) do
                local slotIDStr, itemString = strsplit("=", gString)
                local itemLink = "item:" .. itemString
                self.CharFrame.Model:TryOn(itemLink)
            end
        end
        
        self.CharFrame.Model:SetPosition(0,0,0) 
        self.CharFrame.Model:SetPortraitZoom(0)
        
        if self.CharFrame.Model.SetFacing then
            self.CharFrame.Model:SetFacing(0)
        end
    else
        -- NO APPEARANCE DATA -> SHOW ERROR, HIDE MODEL
        self.CharFrame.Model:Hide()
        self.CharFrame.ErrorText:Show()
    end
end

function AXIOM_Inspect:UpdateFromSnapshot()
    local data = self.snapshot
    if not data then return end
    
    local namePart = strsplit("-", self.snapshotKey or "Unknown")
    self.LeftPane.Name:SetText(namePart)
    
    local classFile = data.class
    local cColor = C_ClassColor.GetClassColor(classFile or "PRIEST")
    local cColorStr = cColor and cColor:GenerateHexColorMarkup() or "|cffffffff"
    
    local detailText = string.format("%s%s|r - %s", cColorStr, classFile or "Unknown", data.spec or "Unknown")
    self.LeftPane.Details:SetText(detailText)
    
    local gName = GetGuildInfo("player")
    self.LeftPane.Guild:SetText(COLOR_GREEN .. "<" .. (gName or "Guild") .. ">|r")
    
    self:ReconstructModel()
    self:UpdateItems()
    
    local ilvlVal = data.ilvl or 0
    self.StatsFrame.ILVL:SetText(GetIlvlColor(ilvlVal) .. string.format("%.1f", ilvlVal) .. "|r")
    self:RebuildStatRows()
    
    -- Never touch
    -- RIO Update via Snapshot Key
    local n, r = strsplit("-", self.snapshotKey)
    if n then
        if not r then r = GetRealmName() end
        local rioData = FetchRaiderIOData(nil, n, r, 1) -- Guess faction 1, Fetcher tries both
        
        _G["AXIOM_Target_Score"]:SetText("M+ Score: " .. GetRioColor(rioData.score) .. rioData.score .. "|r")
        self.Intel.RaidNorm:SetText(GetProgColor(rioData.raidN) .. (rioData.raidN or "-") .. "|r")
        self.Intel.RaidHeroic:SetText(GetProgColor(rioData.raidH) .. (rioData.raidH or "-") .. "|r")
        self.Intel.RaidMythic:SetText(GetProgColor(rioData.raidM) .. (rioData.raidM or "-") .. "|r")
        
        for short, fontString in pairs(self.Intel.DungeonStrings) do
            local level = rioData.dungeons and rioData.dungeons[short] or 0
            local kColor = (level >= 12) and "|cffff8000" or (level >= 8 and "|cffa335ee" or "|cffffffff")
            fontString:SetText(kColor .. (level > 0 and "+"..level or "-") .. "|r")
        end
    end
    -- Never touch
end

function AXIOM_Inspect:UpdateData()
    if self.snapshot then return end
    local unit = self.unit
    if not UnitExists(unit) then return end
    
    local name, realm = UnitFullName(unit)
    self.LeftPane.Name:SetText(name)
    
    local guildName, guildRankName = GetGuildInfo(unit)
    self.LeftPane.Guild:SetText(COLOR_GREEN .. "<" .. (guildName or "No Guild") .. ">|r")
    self.GuildName:SetText(guildName or "No Guild")
    self.GuildRank:SetText("Rank: " .. (guildRankName or "-"))
    self.GuildRealm:SetText("Realm: " .. (realm or GetRealmName()))
    
    local localizedClass, englishClass = UnitClass(unit)
    local cColor = C_ClassColor.GetClassColor(englishClass)
    local cColorStr = cColor and cColor:GenerateHexColorMarkup() or "|cffffffff"
    
    local ilvlCalc = C_PaperDollInfo.GetInspectItemLevel(unit) or 0
    self.StatsFrame.ILVL:SetText(GetIlvlColor(ilvlCalc) .. string.format("%.1f", ilvlCalc) .. "|r")
    
    local specID = GetInspectSpecialization(unit)
    local specName = specID and select(2, GetSpecializationInfoByID(specID)) or ""
    self.LeftPane.Details:SetText(string.format("%s%s|r - %s", cColorStr, localizedClass, GetSpecColor(specID, englishClass) .. specName .. "|r"))
    
    -- [[ ONLINE VIEW ]]
    self.CharFrame.ErrorText:Hide()
    self.CharFrame.Model:Show()
    self.CharFrame.Model:SetUnit(unit)
    self.CharFrame.Model:RefreshUnit() -- Force Refresh
    self.CharFrame.Model:SetPortraitZoom(0) -- Standard View
    if self.CharFrame.Model.SetFacing then
         self.CharFrame.Model:SetFacing(0)
    end
    
    self:UpdateItems()
    self:RebuildStatRows()
    
    -- Never touch
    local rioData = FetchRaiderIOData(unit)
    _G["AXIOM_Target_Score"]:SetText("M+ Score: " .. GetRioColor(rioData.score) .. rioData.score .. "|r")
    self.Intel.RaidNorm:SetText(GetProgColor(rioData.raidN) .. (rioData.raidN or "-") .. "|r")
    self.Intel.RaidHeroic:SetText(GetProgColor(rioData.raidH) .. (rioData.raidH or "-") .. "|r")
    self.Intel.RaidMythic:SetText(GetProgColor(rioData.raidM) .. (rioData.raidM or "-") .. "|r")
    
    for short, fontString in pairs(self.Intel.DungeonStrings) do
        local level = rioData.dungeons and rioData.dungeons[short] or 0
        local kColor = (level >= 12) and "|cffff8000" or (level >= 8 and "|cffa335ee" or "|cffffffff")
        fontString:SetText(kColor .. (level > 0 and "+"..level or "-") .. "|r")
    end
    -- Never touch
end

function AXIOM_Inspect:SetSnapshot(data, key, meta)
    self.snapshot = data
    self.snapshotKey = key
    self.snapshotMeta = meta 
    self.unit = nil 
    self:ClearData()
    self:Show()
    self:UpdateFromSnapshot()
end

-- =========================================================================
-- 7. EVENT HANDLERS & HOOKS
-- =========================================================================

local function OnEvent(self, event, arg1, ...)
    if event == "PLAYER_LOGIN" then
        BuildFrame()
        BuildArmoryLeft()
        BuildStatsMiddle()
        BuildIntelRight()
        SterilizeInspectUI()
        
        hooksecurefunc("InspectUnit", function(unit)
            if not unit then return end
            -- Guard against showing custom frame if disabled
            if not AXIOM_Inspect_System_Enabled then return end
            
            SterilizeInspectUI()
            
            AXIOM_Inspect.unit = unit
            AXIOM_Inspect.snapshot = nil 
            AXIOM_Inspect.currentGuid = UnitGUID(unit) 
            AXIOM_Inspect:ClearData() 
            AXIOM_Inspect:Show()
            AXIOM_Inspect:UpdateData() 
        end)

    elseif event == "INSPECT_READY" then
        local guid = arg1
        if AXIOM_Inspect:IsVisible() and guid == AXIOM_Inspect.currentGuid then
            AXIOM_Inspect:UpdateData()
            C_Timer.After(1.0, function()
                if AXIOM_Inspect:IsVisible() and AXIOM_Inspect.currentGuid == guid then
                    AXIOM_Inspect:UpdateData()
                end
            end)
        end
    end
end

AXIOM_Inspect:RegisterEvent("PLAYER_LOGIN")
AXIOM_Inspect:RegisterEvent("INSPECT_READY")
AXIOM_Inspect:SetScript("OnEvent", OnEvent)