-- ============================================================================
-- ArenaCore DR System - Midnight API PvP Only (4 Categories)
-- ============================================================================
-- PvP DR categories only: Stun, Incapacitate, Silence, Disorient
-- ============================================================================

local AC = _G.ArenaCore or {}

local function GetAC()
    if _G.ArenaCore and AC ~= _G.ArenaCore then
        AC = _G.ArenaCore
    end
    return AC
end

-- ============================================================================
-- PVP DR CATEGORIES (the 4 that actually matter in arena)
-- ============================================================================

local DR_PvP = {}

do
    local function EarlyBlockCoreDRTray()
        local ac = _G.ArenaCore
        if not ac then
            if C_Timer and C_Timer.After then
                C_Timer.After(0.2, EarlyBlockCoreDRTray)
            end
            return
        end

        if ac._drPvPFileLoaded == nil then
            ac._drPvPFileLoaded = true
        end

        if ac._midnightDRTrayItemHooksInitialized == nil then
            ac._midnightDRTrayItemHooksInitialized = true
        end

        local frames
        if ac.MasterFrameManager and ac.MasterFrameManager.GetFrames then
            frames = ac.MasterFrameManager:GetFrames()
        elseif ac.FrameManager and ac.FrameManager.GetFrames then
            frames = ac.FrameManager:GetFrames()
        elseif ac.MasterFrameManager and ac.MasterFrameManager.frames then
            frames = ac.MasterFrameManager.frames
        end

        if not frames then
            if C_Timer and C_Timer.After then
                C_Timer.After(0.2, EarlyBlockCoreDRTray)
            end
            return
        end

        local dummyTray = {
            Hide = function() end,
            SetParent = function() end,
            SetMouseClickEnabled = function() end,
        }

        for i = 1, 3 do
            local frame = frames[i]
            if frame and frame.drTray == nil then
                frame.drTray = dummyTray
            end
        end
    end

    if C_Timer and C_Timer.After then
        C_Timer.After(0, EarlyBlockCoreDRTray)
    end

    EarlyBlockCoreDRTray()
end

-- Grab enums early so we don't trip over weird combat lockdown / taint nonsense later.
local ENUM_STUN = Enum.SpellDiminishCategory.Stun
local ENUM_INCAPACITATE = Enum.SpellDiminishCategory.Incapacitate
local ENUM_SILENCE = Enum.SpellDiminishCategory.Silence
local ENUM_DISORIENT = Enum.SpellDiminishCategory.Disorient

-- The 4 DR categories we care about.
local PVP_DR_CATEGORIES = {
    [ENUM_STUN] = { name = "Stun", icon = 132092, arenacore = "stun" },
    [ENUM_INCAPACITATE] = { name = "Incapacitate", icon = 136100, arenacore = "incapacitate" },
    [ENUM_SILENCE] = { name = "Silence", icon = 136100, arenacore = "silence" },
    [ENUM_DISORIENT] = { name = "Disorient", icon = 136183, arenacore = "disorient" },
}

-- ArenaCore to Midnight enum mapping (PvP only)
local ARENACORE_TO_MIDNIGHT = {
    stun = ENUM_STUN,
    incapacitate = ENUM_INCAPACITATE,
    silence = ENUM_SILENCE,
    disorient = ENUM_DISORIENT,
}

-- Midnight to ArenaCore reverse mapping
local MIDNIGHT_TO_ARENACORE = {}
for arenacore, enum in pairs(ARENACORE_TO_MIDNIGHT) do
    MIDNIGHT_TO_ARENACORE[enum] = arenacore
end

local MAX_ARENA_ENEMIES = 3

local DR_DEBUG = false
local function DebugPrint(...)
    if not DR_DEBUG then return end
    print(...)
end

local GetBlizzardArenaTray

-- ============================================================================
-- CORE PVP DR SYSTEM FUNCTIONS
-- ============================================================================

function DR_PvP:InitializeDRSystem()
    local ac = GetAC()
    if not ac then return end
    
    -- Make sure the client actually supports the Midnight DR API.
    if not C_SpellDiminish or not C_SpellDiminish.IsSystemSupported() then
        print("|cffFF0000ArenaCore DR:|r Midnight DR system not supported on this client")
        return false
    end
    
    if not C_SpellDiminish.IsSystemSupported() then
        print("|cffFF0000ArenaCore DR:|r Midnight DR system not available")
        return false
    end
    
    -- Tell Blizzard to turn on the PvP DR tracker.
    if C_CVar and C_CVar.SetCVar then
        C_CVar.SetCVar("spellDiminishPVPEnemiesEnabled", "1")
    end
    
    -- Wire it into ArenaCore.
    ac.DR_PvP = self
    ac.MasterFrameManager = ac.MasterFrameManager or {}
    ac.MasterFrameManager.DR_PvP = self
    ac.FrameManager = ac.FrameManager or ac.MasterFrameManager
    ac.FrameManager.DR_PvP = self

    if ac._midnightDRTrayItemHooksInitialized == nil then
        ac._midnightDRTrayItemHooksInitialized = true
    end

    if not self._coreDRTrayBlocked then
        self._coreDRTrayBlocked = true

        local dummyTray = {
            Hide = function() end,
            SetParent = function() end,
            SetMouseClickEnabled = function() end,
        }

        local function TryBlockCoreDRTray()
            local frames

            local manager = ac.MasterFrameManager or ac.FrameManager
            if manager and manager.GetFrames then
                frames = manager:GetFrames()
                if frames and not next(frames) then
                    frames = nil
                end
            end

            if not frames and ac.arenaFrames then
                frames = ac.arenaFrames
            end

            if not frames then
                if C_Timer and C_Timer.After then
                    C_Timer.After(0.2, TryBlockCoreDRTray)
                end
                return
            end

            for i = 1, MAX_ARENA_ENEMIES do
                local frame = frames[i]
                if frame and frame.drTray == nil then
                    frame.drTray = dummyTray
                end
            end
        end

        TryBlockCoreDRTray()
    end
    
    return true
end

local function GetFrames()
    local ac = GetAC()
    if not ac then return nil end

    local manager = ac.MasterFrameManager or ac.FrameManager
    if manager and manager.GetFrames then
        local frames = manager:GetFrames()
        if frames and next(frames) then
            return frames
        end
    end

    if ac.arenaFrames then
        return ac.arenaFrames
    end

    return nil
end

local function GetDB()
    local currentDB = _G.ArenaCoreDB
    if currentDB and type(currentDB.profile) == "table" then
        return currentDB.profile.diminishingReturns
    end

    local ac = GetAC()
    return ac and ac.DB and ac.DB.profile and ac.DB.profile.diminishingReturns
end

local function GetSettings()
    return GetDB()
end

local function IsSpiralGlowLineEnabled()
    local db = GetDB()
    if not db then return true end
    return db.spiralGlowLine ~= false
end

local function ApplyCooldownEdgeStyle(cooldown)
    if not cooldown then return end
    local enabled = IsSpiralGlowLineEnabled()
    if cooldown.SetDrawEdge then
        cooldown:SetDrawEdge(enabled)
    end
    if cooldown.SetEdgeColor then
        cooldown:SetEdgeColor(1, 1, 1, enabled and 1 or 0)
    end
    if cooldown.SetDrawBling then
        cooldown:SetDrawBling(false)
    end
    if cooldown.SetReverse then
        cooldown:SetReverse(false)
    end
    if cooldown.SetUseCircularEdge then
        cooldown:SetUseCircularEdge(true)
    end
end

local function NormalizeNumberSafe(v)
    local ok, s = pcall(tostring, v)
    if not ok then
        return nil
    end
    return tonumber(s)
end

local function NormalizeBooleanSafe(v)
    if type(v) == "boolean" then
        return v
    end
    return nil
end

local function SyncCooldownEdgeFromCooldown(edgeCooldown, sourceCooldown)
    if not (edgeCooldown and sourceCooldown and sourceCooldown.GetCooldownTimes) then
        return
    end

    local ok, startMs, durationMs = pcall(sourceCooldown.GetCooldownTimes, sourceCooldown)
    if not ok then
        return
    end

    startMs = NormalizeNumberSafe(startMs)
    durationMs = NormalizeNumberSafe(durationMs)
    if not (startMs and durationMs) then
        return
    end

    if startMs <= 0 or durationMs <= 0 then
        if edgeCooldown.Clear then
            edgeCooldown:Clear()
        end
        if edgeCooldown.Hide then
            edgeCooldown:Hide()
        end
        return
    end

    edgeCooldown:SetCooldown((startMs / 1000), (durationMs / 1000))
    if edgeCooldown.Show then
        edgeCooldown:Show()
    end
end

local function HasActiveCooldown(sourceCooldown)
    if not (sourceCooldown and sourceCooldown.GetCooldownTimes) then
        return false
    end

    local ok, startMs, durationMs = pcall(sourceCooldown.GetCooldownTimes, sourceCooldown)
    if not ok then
        return false
    end

    startMs = NormalizeNumberSafe(startMs)
    durationMs = NormalizeNumberSafe(durationMs)
    return startMs and durationMs and startMs > 0 and durationMs > 0
end

local function IsPrepRoom()
    local _, instanceType = IsInInstance()
    if instanceType ~= "arena" then
        return false
    end

    local numSpecs = GetNumArenaOpponentSpecs and GetNumArenaOpponentSpecs() or 0
    local numOpponents = GetNumArenaOpponents and GetNumArenaOpponents() or 0
    return numSpecs > 0 and numOpponents == 0
end

local function FilterPrepRoomTrayItems(tray)
    if not (tray and tray.GetChildren) then
        return 0
    end

    local activeCount = 0
    local children = { tray:GetChildren() }
    for i = 1, #children do
        local item = children[i]
        if item and item.Icon and item.Cooldown then
            if HasActiveCooldown(item.Cooldown) then
                activeCount = activeCount + 1
                if item.Show then
                    item:Show()
                end
            elseif item.Hide then
                item:Hide()
            end
        end
    end

    if activeCount > 0 then
        if tray.Show then
            tray:Show()
        end
    elseif tray.Hide then
        tray:Hide()
    end

    return activeCount
end

local function GetPixelBorderColor(db)
    if not db then
        return 0, 0, 0, 1
    end

    local c = db.borderColor
    if type(c) == "table" then
        local r = c.r or c[1] or 0
        local g = c.g or c[2] or 0
        local b = c.b or c[3] or 0
        local a = c.a or c[4] or 1
        return r, g, b, a
    end

    return 0, 0, 0, 1
end

local function PixelSetPoint(region, point, relativeTo, relativePoint, offsetX, offsetY)
    if not region then return end
    if PixelUtil and PixelUtil.SetPoint then
        PixelUtil.SetPoint(region, point, relativeTo, relativePoint, offsetX or 0, offsetY or 0)
    else
        region:SetPoint(point, relativeTo, relativePoint, offsetX or 0, offsetY or 0)
    end
end

local function PixelSetSize(region, width, height)
    if not region then return end
    if PixelUtil and PixelUtil.SetSize then
        PixelUtil.SetSize(region, width or 0, height or 0, 1, 1)
    else
        region:SetSize(width or 0, height or 0)
    end
end

local function PixelSetWidth(region, width)
    if not region then return end
    if PixelUtil and PixelUtil.SetWidth then
        PixelUtil.SetWidth(region, width or 0, 1)
    else
        region:SetWidth(width or 0)
    end
end

local function PixelSetHeight(region, height)
    if not region then return end
    if PixelUtil and PixelUtil.SetHeight then
        PixelUtil.SetHeight(region, height or 0, 1)
    else
        region:SetHeight(height or 0)
    end
end

local function PixelSetAllPoints(region, anchor)
    if not region or not anchor then return end
    region:ClearAllPoints()
    PixelSetPoint(region, "TOPLEFT", anchor, "TOPLEFT", 0, 0)
    PixelSetPoint(region, "BOTTOMRIGHT", anchor, "BOTTOMRIGHT", 0, 0)
end

local function EnsurePixelBorder(drItem)
    if not drItem then return nil end

    if drItem._acPixelBorder and drItem._acPixelBorder.edges then
        return drItem._acPixelBorder
    end

    local anchor = drItem.Icon or drItem

    local holder = CreateFrame("Frame", nil, drItem)
    holder:SetFrameLevel(drItem:GetFrameLevel() + 1)
    PixelSetAllPoints(holder, anchor)

    local edges = {}
    for i = 1, 4 do
        local t = holder:CreateTexture(nil, "BORDER", nil, 0)
        t:SetColorTexture(0, 0, 0, 1)
        edges[i] = t
    end
    holder.edges = edges

    -- Top
    PixelSetPoint(edges[1], "TOPLEFT", anchor, "TOPLEFT", 0, 0)
    PixelSetPoint(edges[1], "TOPRIGHT", anchor, "TOPRIGHT", 0, 0)
    PixelSetHeight(edges[1], 1)

    -- Right
    PixelSetPoint(edges[2], "TOPRIGHT", anchor, "TOPRIGHT", 0, 0)
    PixelSetPoint(edges[2], "BOTTOMRIGHT", anchor, "BOTTOMRIGHT", 0, 0)
    PixelSetWidth(edges[2], 1)

    -- Bottom
    PixelSetPoint(edges[3], "BOTTOMLEFT", anchor, "BOTTOMLEFT", 0, 0)
    PixelSetPoint(edges[3], "BOTTOMRIGHT", anchor, "BOTTOMRIGHT", 0, 0)
    PixelSetHeight(edges[3], 1)

    -- Left
    PixelSetPoint(edges[4], "TOPLEFT", anchor, "TOPLEFT", 0, 0)
    PixelSetPoint(edges[4], "BOTTOMLEFT", anchor, "BOTTOMLEFT", 0, 0)
    PixelSetWidth(edges[4], 1)

    drItem._acPixelBorder = holder
    return holder
end

local function ApplyPixelBorderThickness(drItem, thickness)
    if not drItem then return end

    local holder = EnsurePixelBorder(drItem)
    if not holder or not holder.edges then
        return
    end

    local anchor = drItem.Icon or drItem
    thickness = tonumber(thickness) or 1
    if thickness < 1 then thickness = 1 end
    if thickness > 5 then thickness = 5 end

    if holder.SetFrameStrata and drItem.GetFrameStrata then
        pcall(holder.SetFrameStrata, holder, drItem:GetFrameStrata())
    end
    if holder.SetFrameLevel and drItem.GetFrameLevel then
        pcall(holder.SetFrameLevel, holder, (drItem:GetFrameLevel() or 0) + 25)
    end

    -- Top
    PixelSetHeight(holder.edges[1], thickness)
    -- Right
    PixelSetWidth(holder.edges[2], thickness)
    -- Bottom
    PixelSetHeight(holder.edges[3], thickness)
    -- Left
    PixelSetWidth(holder.edges[4], thickness)

    -- Re-anchor in case icon points changed.
    PixelSetAllPoints(holder, anchor)
end

local function SetPixelBorderColor(drItem, thickness, r, g, b, a)
    local holder = EnsurePixelBorder(drItem)
    if not holder or not holder.edges then
        return
    end

    ApplyPixelBorderThickness(drItem, thickness)

    for i = 1, 4 do
        local t = holder.edges[i]
        if t and t.SetColorTexture then
            t:SetColorTexture(r or 0, g or 0, b or 0, a or 1)
        end
    end
    holder:Show()
end

local PVP_TRAY_ORDER = {
    ENUM_STUN,
    ENUM_INCAPACITATE,
    ENUM_SILENCE,
    ENUM_DISORIENT,
}

local PVP_TRAY_ORDER_INDEX = {
    [ENUM_STUN] = 1,
    [ENUM_INCAPACITATE] = 2,
    [ENUM_SILENCE] = 3,
    [ENUM_DISORIENT] = 4,
}

local function IsTestPreviewImmune(categoryEnum)
    local idx = PVP_TRAY_ORDER_INDEX and PVP_TRAY_ORDER_INDEX[categoryEnum]
    return idx ~= nil and idx >= 3
end

local function EnsureSpellDiminishUI()
    if _G.SpellDiminishStatusTrayMixin and _G.SpellDiminishStatusTrayItemMixin then
        return true
    end

    if InCombatLockdown and InCombatLockdown() then
        return false
    end

    -- Pull in Blizzard's tray templates if they're not loaded yet.
    if UIParentLoadAddOn then
        pcall(UIParentLoadAddOn, "Blizzard_SpellDiminishUI")
    end

    return _G.SpellDiminishStatusTrayMixin ~= nil and _G.SpellDiminishStatusTrayItemMixin ~= nil
end

local trayItemHookInstalled = false
local styledTrayItems = setmetatable({}, { __mode = "k" })

local function ApplyFont(fontString, size)
    if not fontString or not fontString.SetFont or not size then
        return
    end

    local ac = GetAC()
    if ac and ac.SafeSetFont then
        pcall(ac.SafeSetFont, fontString, "Interface/AddOns/ArenaCore/Media/Fonts/arenacore.ttf", size, "OUTLINE")
    else
        pcall(fontString.SetFont, fontString, "Interface/AddOns/ArenaCore/Media/Fonts/arenacore.ttf", size, "OUTLINE")
    end
end

local function SetAlphaFromBooleanSafe(obj, flag, alphaTrue, alphaFalse)
    if not obj then return end
    if obj.SetAlphaFromBoolean then
        pcall(obj.SetAlphaFromBoolean, obj, flag, alphaTrue, alphaFalse)
        return
    end

    if not obj.SetAlpha then
        return
    end

    local b
    if type(flag) == "boolean" then
        local s = tostring(flag)
        if s == "true" or s == "1" then
            b = true
        elseif s == "false" or s == "0" then
            b = false
        end
    elseif flag ~= nil then
        local s = tostring(flag)
        if s == "true" or s == "1" then
            b = true
        elseif s == "false" or s == "0" then
            b = false
        end
    end

    if b ~= nil then
        pcall(obj.SetAlpha, obj, b and alphaTrue or alphaFalse)
    end
end

local function HookImmunitySetShown(drItem)
    if not drItem or not drItem.ImmunityIndicator then
        return
    end

    if drItem._acImmuneHooked == true then
        return
    end

    drItem._acImmuneHooked = true

    local indicator = drItem.ImmunityIndicator
    if hooksecurefunc and indicator and indicator.SetShown then

        -- Midnight-safe pattern: call SetAlphaFromBoolean directly, no pcall wrapping.
        -- pcall breaks the secret boolean chain in Midnight and kills the alpha flip.
        pcall(hooksecurefunc, indicator, "SetShown", function(_, isShown)
            -- Stage text: SetAlphaFromBoolean handles secret booleans natively
            if drItem.ACStageText1 and drItem.ACStageText1.SetAlphaFromBoolean then
                drItem.ACStageText1:SetAlphaFromBoolean(isShown, 0, 1)
            end
            if drItem.ACStageText2 and drItem.ACStageText2.SetAlphaFromBoolean then
                drItem.ACStageText2:SetAlphaFromBoolean(isShown, 1, 0)
            end
            -- Borders: only for Arena Core theme (pixel_black stays disabled)
            local db = GetSettings()
            local ccb = db and db.colorCodedBorders and db.borderStyle ~= "pixel_black"
            if ccb then
                if drItem.ACBorderGreen and drItem.ACBorderGreen.SetAlphaFromBoolean then
                    drItem.ACBorderGreen:SetAlphaFromBoolean(isShown, 0, 1)
                end
                if drItem.ACBorderRed and drItem.ACBorderRed.SetAlphaFromBoolean then
                    drItem.ACBorderRed:SetAlphaFromBoolean(isShown, 1, 0)
                end
            end
        end)

        -- Show/Hide hooks: known plain booleans, safe to SetAlpha directly
        if indicator.Show then
            pcall(hooksecurefunc, indicator, "Show", function()
                if drItem.ACStageText1 then pcall(drItem.ACStageText1.SetAlpha, drItem.ACStageText1, 0) end
                if drItem.ACStageText2 then pcall(drItem.ACStageText2.SetAlpha, drItem.ACStageText2, 1) end
                local db = GetSettings()
                local ccb = db and db.colorCodedBorders and db.borderStyle ~= "pixel_black"
                if ccb then
                    if drItem.ACBorderGreen then pcall(drItem.ACBorderGreen.SetAlpha, drItem.ACBorderGreen, 0) end
                    if drItem.ACBorderRed then pcall(drItem.ACBorderRed.SetAlpha, drItem.ACBorderRed, 1) end
                end
            end)
        end

        if indicator.Hide then
            pcall(hooksecurefunc, indicator, "Hide", function()
                if drItem.ACStageText1 then pcall(drItem.ACStageText1.SetAlpha, drItem.ACStageText1, 1) end
                if drItem.ACStageText2 then pcall(drItem.ACStageText2.SetAlpha, drItem.ACStageText2, 0) end
                local db = GetSettings()
                local ccb = db and db.colorCodedBorders and db.borderStyle ~= "pixel_black"
                if ccb then
                    if drItem.ACBorderGreen then pcall(drItem.ACBorderGreen.SetAlpha, drItem.ACBorderGreen, 1) end
                    if drItem.ACBorderRed then pcall(drItem.ACBorderRed.SetAlpha, drItem.ACBorderRed, 0) end
                end
            end)
        end
    end
end

local function ResolveImmunityShownSafe(drItem)
    if not drItem or not drItem.ImmunityIndicator then
        return false
    end

    -- Check explicit preview immune flag first
    if drItem._acPreviewImmune ~= nil then
        return drItem._acPreviewImmune
    end

    -- Prefer stage alpha when available (safe in Midnight when normalized).
    if drItem.ACStageText2 and drItem.ACStageText2.GetAlpha then
        local okA, a = pcall(drItem.ACStageText2.GetAlpha, drItem.ACStageText2)
        if okA then
            local alpha = NormalizeNumberSafe(a)
            if alpha then
                return alpha > 0.5
            end
        end
    end

    -- Fallback to last cached plain boolean state from immunity hook.
    if type(drItem._acImmune) == "boolean" then
        return drItem._acImmune
    end

    return false
end

function DR_PvP:EnsureThemedElements(drItem, stageFontSize)
    if not drItem then return end
    if not drItem.ImmunityIndicator then return end

    local resolvedStageFontSize = stageFontSize or 10

    if not drItem.ACTextHolder then
        local parent = drItem.Cooldown or drItem
        drItem.ACTextHolder = CreateFrame("Frame", nil, parent)
        drItem.ACTextHolder:SetAllPoints(drItem)

        local baseLevel = (parent and parent.GetFrameLevel and parent:GetFrameLevel()) or 0
        drItem.ACTextHolder:SetFrameLevel(baseLevel + 10)
    end

    if drItem.ACTextHolder and drItem.Cooldown and drItem.Cooldown.GetFrameLevel then
        local cdLevel = drItem.Cooldown:GetFrameLevel() or 0
        if drItem.ACTextHolder:GetFrameLevel() <= cdLevel then
            drItem.ACTextHolder:SetFrameLevel(cdLevel + 10)
        end
    end

    if not drItem.ACStageText1 then
        local holder = drItem.ACTextHolder or drItem
        drItem.ACStageText1 = holder:CreateFontString(nil, "OVERLAY")
        drItem.ACStageText1:SetPoint("BOTTOMRIGHT", drItem, "BOTTOMRIGHT", -2, 2)
        ApplyFont(drItem.ACStageText1, resolvedStageFontSize)
        if drItem.ACStageText1.GetFont and not drItem.ACStageText1:GetFont() then
            pcall(drItem.ACStageText1.SetFont, drItem.ACStageText1, "Fonts\\FRIZQT__.TTF", resolvedStageFontSize, "OUTLINE")
        end
        if drItem.ACStageText1.SetDrawLayer then
            drItem.ACStageText1:SetDrawLayer("OVERLAY", 7)
        end
        drItem.ACStageText1:SetText("1/2")
        drItem.ACStageText1:SetTextColor(0, 1, 0, 1)
        drItem.ACStageText1:SetIgnoreParentAlpha(true)
        if drItem.ACStageText1.SetAlpha then
            pcall(drItem.ACStageText1.SetAlpha, drItem.ACStageText1, 1)
        end
    end

    if not drItem.ACStageText2 then
        local holder = drItem.ACTextHolder or drItem.ImmunityIndicator
        drItem.ACStageText2 = holder:CreateFontString(nil, "OVERLAY")
        drItem.ACStageText2:SetPoint("BOTTOMRIGHT", drItem, "BOTTOMRIGHT", -2, 2)
        ApplyFont(drItem.ACStageText2, resolvedStageFontSize)
        if drItem.ACStageText2.GetFont and not drItem.ACStageText2:GetFont() then
            pcall(drItem.ACStageText2.SetFont, drItem.ACStageText2, "Fonts\\FRIZQT__.TTF", resolvedStageFontSize, "OUTLINE")
        end
        if drItem.ACStageText2.SetDrawLayer then
            drItem.ACStageText2:SetDrawLayer("OVERLAY", 7)
        end
        drItem.ACStageText2:SetText("2/2")
        drItem.ACStageText2:SetTextColor(1, 0, 0, 1)
        drItem.ACStageText2:SetIgnoreParentAlpha(true)
        if drItem.ACStageText2.SetAlpha then
            pcall(drItem.ACStageText2.SetAlpha, drItem.ACStageText2, 0)
        end
    end

    ApplyFont(drItem.ACStageText1, resolvedStageFontSize)
    ApplyFont(drItem.ACStageText2, resolvedStageFontSize)

    -- Border holder frame: sits between drItem and ImmunityIndicator in frame level
    -- so OVERLAY textures on it render above the icon but below the shield
    if not drItem._acBorderHolder then
        drItem._acBorderHolder = CreateFrame("Frame", nil, drItem)
        drItem._acBorderHolder:SetAllPoints(drItem)
    end

    local bh = drItem._acBorderHolder

    if not drItem.ACBorderOrange then
        drItem.ACBorderOrange = bh:CreateTexture(nil, "OVERLAY", nil, 6)
        drItem.ACBorderOrange:SetAllPoints(drItem)
        drItem.ACBorderOrange:SetTexture("Interface/AddOns/ArenaCore/Media/Classicons/Overlays/orangeoverlay.tga")
        drItem.ACBorderOrange:SetTexCoord(0, 1, 0, 1)
        -- Match trinket/racial borders: use the baked-in orange from the texture (no tint)
        drItem.ACBorderOrange:SetVertexColor(1, 1, 1, 1)
    end

    if not drItem.ACBorderGreen then
        drItem.ACBorderGreen = bh:CreateTexture(nil, "OVERLAY", nil, 6)
        drItem.ACBorderGreen:SetAllPoints(drItem)
        drItem.ACBorderGreen:SetTexture("Interface/AddOns/ArenaCore/Media/Classicons/Overlays/orangeoverlay.tga")
        drItem.ACBorderGreen:SetTexCoord(0, 1, 0, 1)
        drItem.ACBorderGreen:SetVertexColor(0, 1, 0, 1)
        if drItem.ACBorderGreen.SetAlpha then
            pcall(drItem.ACBorderGreen.SetAlpha, drItem.ACBorderGreen, 1)
        end
    end

    if not drItem.ACBorderRed then
        drItem.ACBorderRed = bh:CreateTexture(nil, "OVERLAY", nil, 7)
        drItem.ACBorderRed:SetAllPoints(drItem)
        drItem.ACBorderRed:SetTexture("Interface/AddOns/ArenaCore/Media/Classicons/Overlays/orangeoverlay.tga")
        drItem.ACBorderRed:SetTexCoord(0, 1, 0, 1)
        drItem.ACBorderRed:SetVertexColor(1, 0, 0, 1)
        if drItem.ACBorderRed.SetAlpha then
            pcall(drItem.ACBorderRed.SetAlpha, drItem.ACBorderRed, 0)
        end
    end

    HookImmunitySetShown(drItem)

end

function DR_PvP:StyleTrayItem(drItem)
    if not drItem then return end

    styledTrayItems[drItem] = true

    local db = GetSettings()
    if not db then return end

    local size = (db.sizing and db.sizing.size) or 22
    local fontSize = (db.sizing and db.sizing.fontSize) or 12
    local stageFontSize = (db.sizing and db.sizing.stageFontSize) or 10
    PixelSetSize(drItem, size, size)

    if drItem.Icon then
        local pad = math.max(1, math.floor((size * 0.04) + 0.5) - 4)
        drItem.Icon:ClearAllPoints()
        PixelSetPoint(drItem.Icon, "TOPLEFT", drItem, "TOPLEFT", pad, -pad)
        PixelSetPoint(drItem.Icon, "BOTTOMRIGHT", drItem, "BOTTOMRIGHT", -pad, pad)
        drItem.Icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
    end

    if drItem.Cooldown then
        drItem.Cooldown:ClearAllPoints()
        if db.borderStyle == "pixel_black" then
            if drItem.Icon then
                PixelSetPoint(drItem.Cooldown, "TOPLEFT", drItem.Icon, "TOPLEFT", 0, 0)
                PixelSetPoint(drItem.Cooldown, "BOTTOMRIGHT", drItem.Icon, "BOTTOMRIGHT", 0, 0)
            else
                PixelSetPoint(drItem.Cooldown, "TOPLEFT", drItem, "TOPLEFT", 0, 0)
                PixelSetPoint(drItem.Cooldown, "BOTTOMRIGHT", drItem, "BOTTOMRIGHT", 0, 0)
            end
        else
            PixelSetPoint(drItem.Cooldown, "TOPLEFT", drItem, "TOPLEFT", 3, -3)
            PixelSetPoint(drItem.Cooldown, "BOTTOMRIGHT", drItem, "BOTTOMRIGHT", -3, 3)
        end
        drItem.Cooldown:SetHideCountdownNumbers(false)
        ApplyCooldownEdgeStyle(drItem.Cooldown)
        drItem.Cooldown.noCooldownCount = true
        drItem.Cooldown.noOCC = true
        if drItem.Cooldown.omnicc then
            drItem.Cooldown.omnicc.enabled = false
        end

        -- Keep Blizzard's tray cooldown swipe enabled in real arena.
        -- Midnight can protect UpdateState payload fields, so source Cooldown is the reliable swipe owner.

        -- NOTE: Blizzard's DR tray item cooldown is not a CooldownFrameTemplate, so the edge line can be missing.
        -- We overlay a CooldownFrameTemplate to guarantee the same "spiral glow line" behavior as class icon auras.
        if not drItem.ACCooldownEdge then
            local edge = CreateFrame("Cooldown", nil, drItem, "CooldownFrameTemplate")
            edge:ClearAllPoints()
            local anchor = drItem.Icon or drItem.Cooldown
            if db.borderStyle == "pixel_black" then
                PixelSetPoint(edge, "TOPLEFT", anchor, "TOPLEFT", 0, 0)
                PixelSetPoint(edge, "BOTTOMRIGHT", anchor, "BOTTOMRIGHT", 0, 0)
            else
                PixelSetPoint(edge, "TOPLEFT", anchor, "TOPLEFT", 3, -3)
                PixelSetPoint(edge, "BOTTOMRIGHT", anchor, "BOTTOMRIGHT", -3, 3)
            end
            if edge.SetHideCountdownNumbers then
                edge:SetHideCountdownNumbers(true)
            end
            if edge.SetSwipeColor then
                edge:SetSwipeColor(0, 0, 0, 0)
            end
            if edge.SetDrawSwipe then
                edge:SetDrawSwipe(false)
            end
            if edge.SetFrameStrata and drItem.GetFrameStrata then
                edge:SetFrameStrata(drItem:GetFrameStrata())
            end
            if edge.SetFrameLevel and drItem.GetFrameLevel then
                edge:SetFrameLevel(drItem:GetFrameLevel() + 5)
            end
            drItem.ACCooldownEdge = edge
        end

        do
            local edge = drItem.ACCooldownEdge
            if edge then
                local anchor = drItem.Icon or drItem.Cooldown
                edge:ClearAllPoints()
                if db.borderStyle == "pixel_black" then
                    PixelSetPoint(edge, "TOPLEFT", anchor, "TOPLEFT", 0, 0)
                    PixelSetPoint(edge, "BOTTOMRIGHT", anchor, "BOTTOMRIGHT", 0, 0)
                else
                    PixelSetPoint(edge, "TOPLEFT", anchor, "TOPLEFT", 3, -3)
                    PixelSetPoint(edge, "BOTTOMRIGHT", anchor, "BOTTOMRIGHT", -3, 3)
                end
            end
        end

        do
            local baseLevel = (drItem.GetFrameLevel and drItem:GetFrameLevel()) or 0

            local cd = drItem.Cooldown
            if cd and cd.SetFrameLevel then
                cd:SetFrameLevel(baseLevel + 10)
            end

            local edge = drItem.ACCooldownEdge
            if edge and edge.SetFrameLevel then
                edge:SetFrameLevel(baseLevel + 5)
            end

            local borderHolder = drItem._acBorderHolder
            if borderHolder and borderHolder.SetFrameLevel then
                borderHolder:SetFrameLevel(baseLevel + 20)
            end

            local shield = drItem.ImmunityIndicator
            if shield and shield.SetFrameLevel then
                shield:SetFrameLevel(baseLevel + 40)
            end

            local holder = drItem.ACTextHolder
            if holder and holder.SetFrameLevel then
                holder:SetFrameLevel(baseLevel + 50)
            end
        end

        ApplyCooldownEdgeStyle(drItem.ACCooldownEdge)

        local ac = GetAC()
        if ac and ac.DRSpiralAnimation and ac.DRSpiralAnimation.ApplySettings then
            ac.DRSpiralAnimation:ApplySettings(drItem.Cooldown)
        end
        SyncCooldownEdgeFromCooldown(drItem.ACCooldownEdge, drItem.Cooldown)

        local okRegions, region1, region2, region3, region4, region5, region6 = pcall(drItem.Cooldown.GetRegions, drItem.Cooldown)
        if okRegions then
            local regions = { region1, region2, region3, region4, region5, region6 }
            for i = 1, #regions do
                local region = regions[i]
                if region and region.GetObjectType and region:GetObjectType() == "FontString" then
                    ApplyFont(region, fontSize)
                end
            end
        end
    end

    self:EnsureThemedElements(drItem, stageFontSize)

    -- Check if we should apply static styling (test mode, edit mode, preview)
    -- For real arena, SetShown hook handles styling dynamically
    -- SAFETY FIX: Never apply test mode styling in real arena matches
    local _, instanceType = IsInInstance()
    local isTestMode = _G.ArenaCore and _G.ArenaCore.testModeEnabled == true and instanceType ~= "arena"
    local shouldApplyStaticStyling = drItem.isEditModePreview or isTestMode
    local useColorCodedBorders = db.colorCodedBorders and db.borderStyle ~= "pixel_black"
    
    if shouldApplyStaticStyling then
        local immuneShown = ResolveImmunityShownSafe(drItem)

        local showStage = db.showStageIndicators
        if showStage == nil then showStage = true end

        if drItem.ACStageText1 then
            drItem.ACStageText1:SetShown(showStage)
            SetAlphaFromBooleanSafe(drItem.ACStageText1, immuneShown, 0, 1)
        end
        if drItem.ACStageText2 then
            drItem.ACStageText2:SetShown(showStage)
            SetAlphaFromBooleanSafe(drItem.ACStageText2, immuneShown, 1, 0)
        end

        if useColorCodedBorders then
            if drItem._acPixelBorder then
                drItem._acPixelBorder:Hide()
            end

            if drItem.ACBorderOrange then drItem.ACBorderOrange:Hide() end
            if drItem.ACBorderGreen then drItem.ACBorderGreen:Show() end
            if drItem.ACBorderRed then drItem.ACBorderRed:Show() end

            if drItem.ACBorderGreen then
                SetAlphaFromBooleanSafe(drItem.ACBorderGreen, immuneShown, 0, 1)
            end
            if drItem.ACBorderRed then
                SetAlphaFromBooleanSafe(drItem.ACBorderRed, immuneShown, 1, 0)
            end
        end
    else
        -- For real arena, just show stage text and borders
        -- Styling will be applied by SetShown hook when immunity changes
        local showStage = db.showStageIndicators
        if showStage == nil then showStage = true end

        if drItem.ACStageText1 then
            drItem.ACStageText1:SetShown(showStage)
        end
        if drItem.ACStageText2 then
            drItem.ACStageText2:SetShown(showStage)
        end

        if useColorCodedBorders then
            if drItem._acPixelBorder then
                drItem._acPixelBorder:Hide()
            end

            if drItem.ACBorderOrange then drItem.ACBorderOrange:Hide() end
            if drItem.ACBorderGreen then drItem.ACBorderGreen:Show() end
            if drItem.ACBorderRed then drItem.ACBorderRed:Show() end

            -- Don't touch border alphas here -- the SetShown/Show/Hide hooks
            -- are the sole authority for real arena border flips.
        end
    end

    if not useColorCodedBorders then
        if db.borderStyle == "pixel_black" then
            if drItem.ACBorderOrange then drItem.ACBorderOrange:Hide() end
            if drItem.ACBorderGreen then drItem.ACBorderGreen:Hide() end
            if drItem.ACBorderRed then drItem.ACBorderRed:Hide() end

            local thickness = db.borderThickness or 1
            local r, g, b, a = GetPixelBorderColor(db)
            SetPixelBorderColor(drItem, thickness, r, g, b, a)
        else
            if drItem._acPixelBorder then
                drItem._acPixelBorder:Hide()
            end

            -- Default mode: keep the normal ArenaCore orange border.
            if drItem.ACBorderOrange then
                drItem.ACBorderOrange:Show()
                -- Match trinket/racial borders: use the baked-in orange from the texture (no tint)
                drItem.ACBorderOrange:SetVertexColor(1, 1, 1, 1)
                if drItem.ACBorderOrange.SetAlpha then
                    drItem.ACBorderOrange:SetAlpha(1)
                end
            end
            if drItem.ACBorderGreen then drItem.ACBorderGreen:Hide() end
            if drItem.ACBorderRed then drItem.ACBorderRed:Hide() end
        end
    end
end

function DR_PvP:InstallTrayItemHook()
    if trayItemHookInstalled then return end
    if not _G.SpellDiminishStatusTrayItemMixin then return end

    trayItemHookInstalled = true

    if not hooksecurefunc then
        return
    end

    -- No need to reset _acIsImmune since we don't store it anymore

    hooksecurefunc(_G.SpellDiminishStatusTrayItemMixin, "SetCategoryInfo", function(trayItem)
        pcall(function()
            DR_PvP:StyleTrayItem(trayItem)
        end)
    end)

    hooksecurefunc(_G.SpellDiminishStatusTrayItemMixin, "UpdateState", function(trayItem, spellDiminishCategoryState)
        -- Midnight can pass secret payloads here; never hard-index directly.
        pcall(function()
            DR_PvP:StyleTrayItem(trayItem)

            if not trayItem or type(spellDiminishCategoryState) ~= "table" then
                return
            end

            local edge = trayItem.ACCooldownEdge
            if not edge then
                return
            end

            -- Never touch spellDiminishCategoryState fields directly in Midnight.
            -- Read cooldown state from Blizzard's tray cooldown instead.
            SyncCooldownEdgeFromCooldown(edge, trayItem.Cooldown)
        end)
    end)

    -- Hook Reset to ensure our edge cooldown overlay is properly cleared
    -- when the tray item is released back to the pool. This prevents the edge
    -- from persisting after the DR icon should be hidden.
    hooksecurefunc(_G.SpellDiminishStatusTrayItemMixin, "Reset", function(trayItem)
        pcall(function()
            if trayItem and trayItem.ACCooldownEdge then
                local edge = trayItem.ACCooldownEdge
                if edge.Clear then
                    edge:Clear()
                end
                if edge.Hide then
                    edge:Hide()
                end
            end
        end)
    end)
end

local arenaStyleTicker

local GetGrowthDirection

function DR_PvP:StartArenaStyleTicker()
    if arenaStyleTicker then
        return
    end

    if not C_Timer or not C_Timer.NewTicker then
        return
    end

    if not EnsureSpellDiminishUI() then
        return
    end

    self:InstallTrayItemHook()

    local wasInArena = false

    local function SnapOffsetToPixel(offset, scale)
        if type(offset) ~= "number" then
            return offset
        end
        if type(scale) ~= "number" or scale <= 0 then
            return offset
        end
        local v = offset * scale
        if v >= 0 then
            return math.floor(v + 0.5) / scale
        end
        return math.ceil(v - 0.5) / scale
    end

    arenaStyleTicker = C_Timer.NewTicker(0.25, function()
        local _, instanceType = IsInInstance()
        if instanceType ~= "arena" then
            wasInArena = false

            local frames = GetFrames()
            if frames then
                for i = 1, 3 do
                    local frame = frames[i]
                    local tray = frame and frame.acDrTray
                    if tray and tray._acDebugFirstActiveLogged then
                        tray._acDebugFirstActiveLogged = nil
                    end
                    if tray and tray._acFirstActiveLayoutForced then
                        tray._acFirstActiveLayoutForced = nil
                    end
                end
            end
            return
        end

        if not wasInArena then
            local frames = GetFrames()
            if not frames then
                return
            end
            for i = 1, 3 do
                local frame = frames[i]
                local tray = frame and frame.acDrTray
                if tray and tray._acDebugFirstActiveLogged then
                    tray._acDebugFirstActiveLogged = nil
                end
                if tray and tray._acFirstActiveLayoutForced then
                    tray._acFirstActiveLayoutForced = nil
                end
            end
            wasInArena = true
        end

        local db = GetSettings()
        local baseX = (db and db.positioning and db.positioning.horizontal) or 0
        local baseY = (db and db.positioning and db.positioning.vertical) or 0
        local iconSize = (db and db.sizing and db.sizing.size) or 22
        local anchorOffset = (iconSize / 2)
        local inPrepRoom = IsPrepRoom()

        local growthDir = GetGrowthDirection()

        local frames = GetFrames()
        if not frames then return end

        for i = 1, 3 do
            local frame = frames[i]
            local tray = frame and frame.acDrTray

            -- Real arena can enter without our RefreshLayout being called.
            -- Always grab Blizzard's live tray when we're in an arena so styling + anchoring work.
            if frame then
                local blizzTray = GetBlizzardArenaTray(i)
                if blizzTray and tray ~= blizzTray then
                    frame.acDrTray = blizzTray
                    tray = blizzTray
                    tray._acChildrenPrestyled = nil
                end

                if tray and not tray._acChildrenPrestyled then
                    tray._acChildrenPrestyled = true
                    if tray.GetChildren then
                        local children = { tray:GetChildren() }
                        for j = 1, #children do
                            local item = children[j]
                            if item and item.Icon and item.Cooldown then
                                DR_PvP:StyleTrayItem(item)
                            end
                        end
                    end
                end
            end

            if tray and tray.ClearAllPoints and tray.SetPoint then
                if tray.SetParent and tray.GetParent and tray:GetParent() ~= frame then
                    pcall(tray.SetParent, tray, frame)
                end

                -- Blizzard's OnHide unregisters events and wipes items when
                -- BlizzFrameHider hides CompactArenaFrame.  Re-show after
                -- reparenting so OnShow re-registers the DR event.
                if tray.IsShown and not tray:IsShown() then
                    if tray.UpdateShownState then
                        pcall(tray.UpdateShownState, tray)
                    else
                        pcall(tray.Show, tray)
                    end
                end
            end
            if tray and tray.GetChildren then
                local children = { tray:GetChildren() }
                for j = 1, #children do
                    local item = children[j]
                    if item and item.Icon and item.Cooldown then
                        DR_PvP:StyleTrayItem(item)
                    end
                end

                local sc = 0
                for j = 1, #children do
                    local item = children[j]
                    if item and item.IsShown and item:IsShown() then
                        sc = sc + 1
                    end
                end
                local overflow = 0
                if sc > 0 then
                    local pad = tonumber(tostring(tray.widthPadding or 2)) or 2
                    local expectedW = (iconSize + pad) * sc
                    local actualWRaw = tray.GetWidth and tray:GetWidth() or nil
                    local actualW = tonumber(tostring(actualWRaw)) or expectedW
                    overflow = math.max(0, expectedW - actualW)
                end

                if tray.ClearAllPoints and tray.SetPoint then
                    pcall(tray.ClearAllPoints, tray)
                    if growthDir == 4 then
                        pcall(tray.SetPoint, tray, "RIGHT", frame, "CENTER", baseX + anchorOffset - overflow, baseY)
                    else
                        pcall(tray.SetPoint, tray, "LEFT", frame, "CENTER", baseX - anchorOffset + overflow, baseY)
                    end
                end

                if not tray._acDebugFirstActiveLogged then
                    local shownCount = 0
                    local firstShownItemWidth
                    for j = 1, #children do
                        local item = children[j]
                        if item and item.IsShown and item:IsShown() then
                            shownCount = shownCount + 1
                            if not firstShownItemWidth and item.GetWidth then
                                firstShownItemWidth = item:GetWidth()
                            end
                            tray._acDebugFirstActiveLogged = true

                            if not tray._acFirstActiveLayoutForced then
                                tray._acFirstActiveLayoutForced = true
                                if tray.RefreshTrayLayout then
                                    pcall(tray.RefreshTrayLayout, tray)
                                end
                                local ofl = 0
                                if sc > 0 then
                                    local pad = tonumber(tostring(tray.widthPadding or 2)) or 2
                                    local ew = (iconSize + pad) * sc
                                    local aw = tonumber(tostring(tray.GetWidth and tray:GetWidth() or nil)) or ew
                                    ofl = math.max(0, ew - aw)
                                end
                                if tray.ClearAllPoints and tray.SetPoint then
                                    pcall(tray.ClearAllPoints, tray)
                                    if growthDir == 4 then
                                        pcall(tray.SetPoint, tray, "RIGHT", frame, "CENTER", baseX + anchorOffset - ofl, baseY)
                                    else
                                        pcall(tray.SetPoint, tray, "LEFT", frame, "CENTER", baseX - anchorOffset + ofl, baseY)
                                    end
                                end
                            end

                            if DR_DEBUG then
                                local numPoints = 0
                                if tray.GetNumPoints then
                                    local okNP, np = pcall(tray.GetNumPoints, tray)
                                    if okNP then
                                        numPoints = NormalizeNumberSafe(np) or 0
                                    end
                                end

                                local p1, relTo1, relPoint1, x1, y1
                                if tray.GetPoint and numPoints > 0 then
                                    pcall(function()
                                        p1, relTo1, relPoint1, x1, y1 = tray:GetPoint(1)
                                    end)
                                end

                                local relToName = (relTo1 and relTo1.GetName and relTo1:GetName()) or tostring(relTo1)

                                local parent = tray.GetParent and tray:GetParent() or nil
                                local parentName = (parent and parent.GetName and parent:GetName()) or tostring(parent)
                                local frameName = (frame and frame.GetName and frame:GetName()) or tostring(frame)

                                local tLeft = tray.GetLeft and tray:GetLeft() or nil
                                local tTop = tray.GetTop and tray:GetTop() or nil
                                local tRight = tray.GetRight and tray:GetRight() or nil
                                local tW = tray.GetWidth and tray:GetWidth() or nil
                                local tH = tray.GetHeight and tray:GetHeight() or nil

                                local tCenterX
                                if tray.GetCenter then
                                    local cx = tray:GetCenter()
                                    tCenterX = cx
                                end

                                local fCenterX
                                if frame and frame.GetCenter then
                                    local cx = frame:GetCenter()
                                    fCenterX = cx
                                end

                                local fLeft = frame and frame.GetLeft and frame:GetLeft() or nil
                                local fRight = frame and frame.GetRight and frame:GetRight() or nil
                                local fTop = frame and frame.GetTop and frame:GetTop() or nil
                                local dRight = "tR=" .. tostring(tRight) .. " fR=" .. tostring(fRight)

                                local eScale = tray.GetEffectiveScale and tray:GetEffectiveScale() or nil
                                local fScale = frame and frame.GetEffectiveScale and frame:GetEffectiveScale() or nil

                                local effScale = frame and frame.GetEffectiveScale and frame:GetEffectiveScale() or (tray.GetEffectiveScale and tray:GetEffectiveScale()) or 1
                                local rawX = growthDir == 4 and (baseX + 2) or (baseX - 2)
                                local rawY = baseY
                                local snapX = SnapOffsetToPixel(rawX, effScale)
                                local snapY = SnapOffsetToPixel(rawY, effScale)

                                local itemLeft = item.GetLeft and item:GetLeft() or nil
                                local itemRight = item.GetRight and item:GetRight() or nil
                                local itemW = item.GetWidth and item:GetWidth() or nil

                                local iconLeft
                                local iconRight
                                local iconW
                                if item.Icon then
                                    iconLeft = item.Icon.GetLeft and item.Icon:GetLeft() or nil
                                    iconRight = item.Icon.GetRight and item.Icon:GetRight() or nil
                                    iconW = item.Icon.GetWidth and item.Icon:GetWidth() or nil
                                end

                                DebugPrint("|cff00FF00[AC DR DEBUG]|r First DR shown arena" .. i
                                    .. " parent=" .. tostring(parentName)
                                    .. " frame=" .. tostring(frameName)
                                    .. " points=" .. tostring(numPoints)
                                    .. " shown=" .. tostring(shownCount)
                                    .. " fiw=" .. tostring(firstShownItemWidth)
                                    .. " p1=" .. tostring(p1) .. "," .. tostring(relPoint1) .. " relTo=" .. tostring(relToName)
                                    .. " x=" .. tostring(x1) .. " y=" .. tostring(y1)
                                    .. " es=" .. tostring(effScale) .. " rx=" .. tostring(rawX) .. " ry=" .. tostring(rawY)
                                    .. " sx=" .. tostring(snapX) .. " sy=" .. tostring(snapY)
                                    .. " left=" .. tostring(tLeft) .. " right=" .. tostring(tRight) .. " top=" .. tostring(tTop)
                                    .. " tcx=" .. tostring(tCenterX) .. " fcx=" .. tostring(fCenterX)
                                    .. " tw=" .. tostring(tW) .. " th=" .. tostring(tH)
                                    .. " itemL=" .. tostring(itemLeft) .. " itemR=" .. tostring(itemRight) .. " itemW=" .. tostring(itemW)
                                    .. " iconL=" .. tostring(iconLeft) .. " iconR=" .. tostring(iconRight) .. " iconW=" .. tostring(iconW)
                                    .. " fLeft=" .. tostring(fLeft) .. " fRight=" .. tostring(fRight) .. " fTop=" .. tostring(fTop)
                                    .. " " .. dRight
                                    .. " eS=" .. tostring(eScale) .. " fS=" .. tostring(fScale))
                            end
                            break
                        end
                    end
                end

                do
                    if inPrepRoom then
                        FilterPrepRoomTrayItems(tray)
                    end

                    local shownCount = 0
                    for j = 1, #children do
                        local item = children[j]
                        if item and item.IsShown and item:IsShown() then
                            shownCount = shownCount + 1
                        end
                    end

                    if tray._acDebugLastShownCount == nil then
                        tray._acDebugLastShownCount = shownCount
                    elseif tray._acDebugLastShownCount ~= shownCount then
                        local prevShown = tray._acDebugLastShownCount
                        tray._acDebugLastShownCount = shownCount

                        do
                            if shownCount == 0 then
                                tray._acCount1WidthFixApplied = nil
                                tray._acCountNWidthFixApplied = nil
                            end

                            if shownCount > 0 and tray.RefreshTrayLayout then
                                pcall(tray.RefreshTrayLayout, tray)
                            end
                        end

                        local tLeft = tray.GetLeft and tray:GetLeft() or nil
                        local tTop = tray.GetTop and tray:GetTop() or nil
                        local tRight = tray.GetRight and tray:GetRight() or nil
                        local tW = tray.GetWidth and tray:GetWidth() or nil
                        local tH = tray.GetHeight and tray:GetHeight() or nil
                        local tCenterX
                        if tray.GetCenter then
                            local cx = tray:GetCenter()
                            tCenterX = cx
                        end
                        local fCenterX
                        if frame and frame.GetCenter then
                            local cx = frame:GetCenter()
                            fCenterX = cx
                        end

                        local fLeft = frame and frame.GetLeft and frame:GetLeft() or nil
                        local fRight = frame and frame.GetRight and frame:GetRight() or nil
                        local fTop = frame and frame.GetTop and frame:GetTop() or nil
                        local dRight = "tR=" .. tostring(tRight) .. " fR=" .. tostring(fRight)

                        local effScale = frame and frame.GetEffectiveScale and frame:GetEffectiveScale() or (tray.GetEffectiveScale and tray:GetEffectiveScale()) or 1
                        local rawX = growthDir == 4 and (baseX + 2) or (baseX - 2)
                        local rawY = baseY
                        local snapX = SnapOffsetToPixel(rawX, effScale)
                        local snapY = SnapOffsetToPixel(rawY, effScale)

                        local itemLeft
                        local itemRight
                        local itemW
                        local iconLeft
                        local iconRight
                        local iconW
                        if shownCount > 0 then
                            for j = 1, #children do
                                local item = children[j]
                                if item and item.IsShown and item:IsShown() then
                                    itemLeft = item.GetLeft and item:GetLeft() or nil
                                    itemRight = item.GetRight and item:GetRight() or nil
                                    itemW = item.GetWidth and item:GetWidth() or nil

                                    if item.Icon then
                                        iconLeft = item.Icon.GetLeft and item.Icon:GetLeft() or nil
                                        iconRight = item.Icon.GetRight and item.Icon:GetRight() or nil
                                        iconW = item.Icon.GetWidth and item.Icon:GetWidth() or nil
                                    end
                                    break
                                end
                            end
                        end
                        DebugPrint("|cff00FF00[AC DR DEBUG]|r Tray count change arena" .. i
                            .. " shown=" .. tostring(shownCount)
                            .. " es=" .. tostring(effScale) .. " rx=" .. tostring(rawX) .. " ry=" .. tostring(rawY)
                            .. " sx=" .. tostring(snapX) .. " sy=" .. tostring(snapY)
                            .. " left=" .. tostring(tLeft) .. " right=" .. tostring(tRight) .. " top=" .. tostring(tTop)
                            .. " tcx=" .. tostring(tCenterX) .. " fcx=" .. tostring(fCenterX)
                            .. " fl=" .. tostring(fLeft) .. " fr=" .. tostring(fRight) .. " ft=" .. tostring(fTop) .. " dr=" .. tostring(dRight)
                            .. " il=" .. tostring(itemLeft) .. " ir=" .. tostring(itemRight) .. " iw=" .. tostring(itemW)
                            .. " xl=" .. tostring(iconLeft) .. " xr=" .. tostring(iconRight) .. " xw=" .. tostring(iconW)
                            .. " w=" .. tostring(tW) .. " h=" .. tostring(tH))
                    end
                end
            end
        end
    end)
end

GetGrowthDirection = function()
    local db = GetSettings()
    local rows = db and db.rows
    return rows and rows.growthDirection or 4
end

function DR_PvP:EnsureTray(frame, unitToken)
    if not frame then return nil end

    if not EnsureSpellDiminishUI() then
        return nil
    end

    self:InstallTrayItemHook()

    local tray = frame.acDrTray
    if tray and not tray.__acLocalTray then
        tray = nil
    end

    if not tray then
        tray = CreateFrame("Frame", nil, frame, "SpellDiminishStatusTrayTemplate")
        tray.__acLocalTray = true
        frame.acDrTray = tray
    end

    if tray.__acLocalTray and not tray.__acScriptsCleared then
        tray.__acScriptsCleared = true
        if tray.SetScript then
            tray:SetScript("OnShow", nil)
            tray:SetScript("OnHide", nil)
            tray:SetScript("OnEvent", nil)
        end
        if tray.UnregisterAllEvents then
            tray:UnregisterAllEvents()
        end
    end

    tray:SetParent(frame)
    tray:SetFrameStrata("HIGH")
    tray:SetFrameLevel((frame:GetFrameLevel() or 10) + 30)
    tray:EnableMouse(false)
    if tray.SetMouseClickEnabled then
        tray:SetMouseClickEnabled(false)
    end

    if tray.SetUnit and unitToken then
        tray:SetUnit(unitToken)
    end

    return tray
end

-- ============================================================================
-- CUSTOM ARENACORE DR ICON CREATION (old-style fallback stuff)
-- ============================================================================

function DR_PvP:CreateCustomDRIcon(frame, category)
    local parent = frame.drContainer
    if not parent then return nil end
    
    local dr = CreateFrame("Frame", nil, parent)
    dr:SetSize(22, 22)
    dr.category = category
    dr.severity = 0
    dr.diminished = 1.0
    dr.reset = 0
    dr.active = false
    dr.lastApplicationTime = 0
    dr:Hide()

    -- ArenaCore borders (because plain Blizzard icons are boring).
    local bg1 = dr:CreateTexture(nil, "BACKGROUND")
    bg1:SetAllPoints()
    bg1:SetTexture("Interface/AddOns/ArenaCore/Media/Classicons/Overlays/orangeoverlay.tga")
    bg1:SetTexCoord(0, 1, 0, 1)
    bg1:SetVertexColor(1, 0.4, 0, 1)
    dr.background = bg1

    local bg2 = dr:CreateTexture(nil, "BACKGROUND", nil, 1)
    bg2:SetAllPoints()
    bg2:SetTexture("Interface/AddOns/ArenaCore/Media/Classicons/Overlays/orangeoverlay.tga")
    bg2:SetTexCoord(0, 1, 0, 1)
    bg2:SetVertexColor(1, 0.3, 0, 0.8)
    dr.background2 = bg2

    local icon = dr:CreateTexture(nil, "ARTWORK")
    icon:SetSize(14, 14)  -- Slightly smaller for better border fit
    icon:SetPoint("CENTER")
    icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)  -- Slight cropping for nice border margin
    dr.Icon = icon

    local overlay = dr:CreateTexture(nil, "OVERLAY")
    overlay:SetAllPoints()
    overlay:SetTexture("Interface/AddOns/ArenaCore/Media/Classicons/Overlays/orangeoverlay.tga")
    overlay:SetTexCoord(0, 1, 0, 1)
    overlay:SetVertexColor(1, 1, 1, 1)
    dr.overlay = overlay

    -- Cooldown frame (timers + swipe).
    local cooldown = CreateFrame("Cooldown", nil, dr, "CooldownFrameTemplate")
    cooldown:SetSize(16, 16)  -- Match icon size
    cooldown:SetPoint("CENTER")
    cooldown:SetHideCountdownNumbers(false)  -- SHOW timers
    ApplyCooldownEdgeStyle(cooldown)
    -- cooldown:SetSwipeTexture(nil)  -- Keep swipe animation
    dr.Cooldown = cooldown
    
    cooldown.noCooldownCount = true
    cooldown.noOCC = true
    if cooldown.omnicc then
        cooldown.omnicc.enabled = false
    end
    
    -- Apply spiral animation settings if available
    local ac = GetAC()
    if ac and ac.DRSpiralAnimation and ac.DRSpiralAnimation.ApplySettings then
        ac.DRSpiralAnimation:ApplySettings(cooldown)
    end
    
    -- Stage text.
    local stageText = cooldown:CreateFontString(nil, "OVERLAY")
    stageText:SetPoint("CENTER", dr, "CENTER", 0, 0)
    stageText:SetFont("Interface\\AddOns\\ArenaCore\\Media\\Fonts\\arenacore.ttf", 10, "OUTLINE")
    stageText:SetTextColor(1, 1, 0, 1)
    dr.stageText = stageText
    
    -- UpdateStage controls stage text + border colors.
    function dr:UpdateStage(stage)
        -- Midnight is a 2-stage DR world (half -> immune). Classic is 3.
        local ac = GetAC()
        local isMidnight = ac and ac.Midnight and ac.Midnight.isMidnight
        
        -- Set diminished multiplier based on stage.
        if isMidnight then
            -- Midnight: Only 2 stages (1=half, 2=immune)
            self.diminished = (stage or 1) >= 2 and 0 or 0.5
        else
            -- Pre-Midnight: 3 stages (1=1.0, 2=0.5, 3=0.25)
            if stage == 1 then
                self.diminished = 1.0
            elseif stage == 2 then
                self.diminished = 0.5
            elseif stage == 3 then
                self.diminished = 0.25
            else
                self.diminished = 1.0
            end
        end
        
        if not stageText then return end
        
        local db = GetSettings()
        local showStage = db and db.showStageIndicators
        if showStage == nil then showStage = true end
        
        if showStage then
            if isMidnight then
                -- Midnight: Only show 1/2 (green) or 2/2 (red)
                local isImmune = (stage or 1) >= 2
                if isImmune then
                    stageText:SetText("2/2")
                    stageText:SetTextColor(1, 0, 0, 1)  -- Red
                else
                    stageText:SetText("1/2")
                    stageText:SetTextColor(0, 1, 0, 1)  -- Green
                end
            else
                -- Pre-Midnight: 3 stages with 1/3, 2/3, 3/3
                local capped = math.min(stage or 1, 3)
                stageText:SetText(capped .. "/3")
                if capped == 1 then
                    stageText:SetTextColor(0, 1, 0, 1)  -- Green
                elseif capped == 2 then
                    stageText:SetTextColor(1, 1, 0, 1)  -- Yellow
                else
                    stageText:SetTextColor(1, 0, 0, 1)  -- Red
                end
            end
            stageText:Show()
        else
            stageText:Hide()
        end
        
        -- Border colors if the user wants the color-coded vibe.
        local colorBorders = db and db.colorCodedBorders
        if colorBorders and self.overlay and self.background and self.background2 then
            if isMidnight then
                -- Midnight: Green or Red only
                local isImmune = (stage or 1) >= 2
                if isImmune then
                    self.overlay:SetVertexColor(1, 0, 0, 1)
                    self.background:SetVertexColor(0.8, 0, 0, 1)
                    self.background2:SetVertexColor(0.6, 0, 0, 0.8)
                else
                    self.overlay:SetVertexColor(0, 1, 0, 1)
                    self.background:SetVertexColor(0, 0.8, 0, 1)
                    self.background2:SetVertexColor(0, 0.6, 0, 0.8)
                end
            else
                -- Pre-Midnight: Green/Yellow/Red
                local capped = math.min(stage or 1, 3)
                if capped == 1 then
                    self.overlay:SetVertexColor(0, 1, 0, 1)
                    self.background:SetVertexColor(0, 0.8, 0, 1)
                    self.background2:SetVertexColor(0, 0.6, 0, 0.8)
                elseif capped == 2 then
                    self.overlay:SetVertexColor(1, 1, 0, 1)
                    self.background:SetVertexColor(1, 0.8, 0, 1)
                    self.background2:SetVertexColor(1, 0.6, 0, 0.8)
                else
                    self.overlay:SetVertexColor(1, 0, 0, 1)
                    self.background:SetVertexColor(0.8, 0, 0, 1)
                    self.background2:SetVertexColor(0.6, 0, 0, 0.8)
                end
            end
        else
            -- If color borders are off, put it back to default orange-ish behavior.
            if self.Icon and self.Icon.SetVertexColor then
                self.Icon:SetVertexColor(1, 1, 1, 1)
            end
            if self.Cooldown and self.Cooldown.SetBorderColor then
                -- Match trinket/racial borders: use the baked-in orange from the texture (no tint)
                self.Cooldown:SetBorderColor(1, 1, 1, 1)
            end
        end
    end
    
    return dr
end

-- ============================================================================
-- BLIZZARD DR TRAY INTEGRATION (PvP ONLY)
-- ============================================================================

function DR_PvP:IntegrateBlizzardDRTrays()
    local frames = GetFrames()
    if not frames then return end

    local ac = GetAC()
    local inTestMode = ac and ac.testModeEnabled
    local _, instanceType = IsInInstance()
    local inArena = instanceType == "arena"

    if inArena then
        self:RefreshLayout()
        return
    end

    if not inTestMode then
        return
    end
    
    for i = 1, MAX_ARENA_ENEMIES do
        local frame = frames[i]
        if not frame then break end

        local tray = self:EnsureTray(frame, "arena" .. i)
        if tray then
            tray:Show()
        end
    end

    self:RefreshLayout()
end

function DR_PvP:CreateDRIcon(parent, category)
    return nil
end

function DR_PvP:CreateDRIcons(frame)
    return nil
end

function DR_PvP:StyleBlizzardDRTray(tray, frameIndex)
    if not tray then return end
    
    local db = GetSettings()
    if not db then return end
    
    local baseX = (db.positioning and db.positioning.horizontal) or 0
    local baseY = (db.positioning and db.positioning.vertical) or 0
    
    local parent = tray.GetParent and tray:GetParent() or nil
    if not parent then return end

    tray:ClearAllPoints()
    if GetGrowthDirection() == 4 then
        tray:SetPoint("RIGHT", parent, "CENTER", baseX + 2, baseY)
    else
        tray:SetPoint("LEFT", parent, "CENTER", baseX - 2, baseY)
    end
end

function DR_PvP:GetItemCategory(drItem)
    if not drItem or not drItem.GetCategory then return nil end
    return drItem:GetCategory()
end

function DR_PvP:StyleDRItem(drItem, frameIndex)
    if not drItem or not drItem.Icon then return end
    
    local db = GetSettings()
    if not db then return end
    
    -- Size.
    local size = db.sizing and db.sizing.size or 22
    drItem:SetSize(size, size)
    
    -- Optional custom styling.
    if db.useCustomStyling then
        if drItem.Cooldown then
            drItem.Cooldown:SetSize(size * 0.9, size * 0.9)
            drItem.Cooldown:SetPoint("CENTER", drItem, "CENTER")
            
            -- Apply custom cooldown colors if specified
            if db.cooldownColor then
                local r, g, b, a = unpack(db.cooldownColor)
                if drItem.Cooldown.SetSwipeColor then
                    drItem.Cooldown:SetSwipeColor(r, g, b, a)
                end
            end
        end
        
        -- Style immunity indicator
        if drItem.ImmunityIndicator then
            local shieldSize = size
            if db.borderStyle == "pixel_black" then
                local thickness = tonumber(db.borderThickness) or 1
                if thickness < 1 then thickness = 1 end
                if thickness > 5 then thickness = 5 end
                shieldSize = math.max(8, size - (thickness * 2))
            end
            drItem.ImmunityIndicator:SetSize(shieldSize, shieldSize)
            if db.immunityIcon then
                drItem.ImmunityIndicator.Icon:SetAtlas(db.immunityIcon)
            end
        end
    end
    
    -- This is kind of important I guess: some callsites expect UpdateStage to exist.
    if not drItem.UpdateStage then
        self:AddUpdateStageMethod(drItem)
    end
end

-- ============================================================================
-- CUSTOM STYLING FUNCTIONS (ArenaCore Features)
-- ============================================================================

function DR_PvP:AddUpdateStageMethod(drItem)
    -- Teach Blizzard's tray items a couple ArenaCore tricks.
    function drItem:UpdateStage(stage)
        local ac = GetAC()
        if not ac then return end
        
        local db = ac.DB and ac.DB.profile and ac.DB.profile.diminishingReturns
        if not db then return end
        
        -- Midnight is 2 stages. Old world is 3.
        local isMidnight = ac.Midnight and ac.Midnight.isMidnight
        
        -- Stage text.
        local stageText = self.stageText
        if not stageText then
            stageText = self:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
            stageText:SetPoint("CENTER", self, "CENTER", 0, 0)
            stageText:SetFont("Interface\\AddOns\\ArenaCore\\Media\\Fonts\\arenacore.ttf", 10, "OUTLINE")
            self.stageText = stageText
        end
        
        local showStage = db.showStageIndicators
        if showStage == nil then showStage = true end
        
        if showStage then
            stageText:Show()
            if isMidnight then
                -- Midnight: Only show 1 or 2 (Green or Red)
                stageText:SetText(stage <= 1 and "1" or "2")
                stageText:SetTextColor(stage <= 1 and 0 or 1, stage <= 1 and 1 or 0, 0, 1)
            else
                -- Pre-Midnight: Show 1, 2, or 3+ (Green, Yellow, Red)
                if stage <= 1 then
                    stageText:SetText("1")
                    stageText:SetTextColor(0, 1, 0, 1)  -- Green
                elseif stage <= 2 then
                    stageText:SetText("2") 
                    stageText:SetTextColor(1, 1, 0, 1)  -- Yellow
                else
                    stageText:SetText("3")
                    stageText:SetTextColor(1, 0, 0, 1)  -- Red
                end
            end
        else
            stageText:Hide()
        end
        
        -- Border colors.
        local colorBorders = db.colorCodedBorders
        if colorBorders then
            self:ApplyDRBorderColors(stage, isMidnight)
        else
            -- If color borders are off, put it back to default orange-ish behavior.
            if self.Icon and self.Icon.SetVertexColor then
                self.Icon:SetVertexColor(1, 1, 1, 1)
            end
            if self.Cooldown and self.Cooldown.SetBorderColor then
                -- Match trinket/racial borders: use the baked-in orange from the texture (no tint)
                self.Cooldown:SetBorderColor(1, 1, 1, 1)
            end
        end
    end
    
    -- Add ApplyDRBorderColors method
    function drItem:ApplyDRBorderColors(stage, isMidnight)
        if not self.Icon then return end
        
        local r, g, b, a = 1, 1, 1, 1
        
        if isMidnight then
            -- Midnight: Green (stage 1) or Red (stage 2+)
            if stage <= 1 then
                r, g, b, a = 0, 1, 0, 1  -- Green
            else
                r, g, b, a = 1, 0, 0, 1  -- Red
            end
        else
            -- Pre-Midnight: Green -> Yellow -> Red
            if stage <= 1 then
                r, g, b, a = 0, 1, 0, 1  -- Green
            elseif stage <= 2 then
                r, g, b, a = 1, 1, 0, 1  -- Yellow
            else
                r, g, b, a = 1, 0, 0, 1  -- Red
            end
        end
        
        -- Apply border color if we can access the border
        if self.Icon.SetVertexColor then
            self.Icon:SetVertexColor(r, g, b, a)
        end
        
        -- Try to apply to cooldown border as well
        if self.Cooldown and self.Cooldown.SetBorderColor then
            self.Cooldown:SetBorderColor(r, g, b, a)
        end
    end
end

function DR_PvP:UpdateAllDRStages()
    for item in pairs(styledTrayItems) do
        if item then
            self:StyleTrayItem(item)
        end
    end
end

function DR_PvP:UpdateSpiralAnimations()
    local ac = GetAC()
    if not ac or not ac.DRSpiralAnimation or not ac.DRSpiralAnimation.ApplySettings then
        return
    end

    for item in pairs(styledTrayItems) do
        local cd = item and item.Cooldown
        if cd then
            ac.DRSpiralAnimation:ApplySettings(cd)
        end
    end

    local frames = GetFrames()
    if not frames then return end
    for i = 1, MAX_ARENA_ENEMIES do
        local frame = frames[i]
        local tray = frame and frame.acDrTray
        if tray and tray.GetChildren then
            local children = { tray:GetChildren() }
            for j = 1, #children do
                local item = children[j]
                local cd = item and item.Cooldown
                if cd then
                    ac.DRSpiralAnimation:ApplySettings(cd)
                end
            end
        end
        if tray and tray._acPreviewItems then
            for _categoryEnum, item in pairs(tray._acPreviewItems) do
                local cd = item and item.Cooldown
                if cd then
                    ac.DRSpiralAnimation:ApplySettings(cd)
                end
            end
        end
    end
end

function DR_PvP:UpdateSpiralGlowLine()
    for item in pairs(styledTrayItems) do
        local cd = item and item.Cooldown
        if cd then
            ApplyCooldownEdgeStyle(cd)
        end
        local edge = item and item.ACCooldownEdge
        if edge then
            ApplyCooldownEdgeStyle(edge)
        end
    end

    local frames = GetFrames()
    if not frames then return end

    for i = 1, MAX_ARENA_ENEMIES do
        local frame = frames[i]
        local tray = frame and frame.acDrTray
        if tray and tray.GetChildren then
            local children = { tray:GetChildren() }
            for j = 1, #children do
                local item = children[j]
                local cd = item and item.Cooldown
                if cd then
                    ApplyCooldownEdgeStyle(cd)
                end
                local edge = item and item.ACCooldownEdge
                if edge then
                    ApplyCooldownEdgeStyle(edge)
                end
            end
        end
        if tray and tray._acPreviewItems then
            for _categoryEnum, item in pairs(tray._acPreviewItems) do
                local cd = item and item.Cooldown
                if cd then
                    ApplyCooldownEdgeStyle(cd)
                end
                local edge = item and item.ACCooldownEdge
                if edge then
                    ApplyCooldownEdgeStyle(edge)
                end
            end
        end
    end
end

-- ============================================================================
-- TEST MODE SUPPORT (PvP CATEGORIES WITH PROPER ICONS)
-- ============================================================================

local testModeTicker = nil

function DR_PvP:ShowTestIcons()
    -- SAFETY FIX: Never show test icons in real arena matches
    local _, instanceType = IsInInstance()
    if instanceType == "arena" then
        local ac = GetAC()
        if ac then
            ac.testModeEnabled = false  -- Force clear stuck flag
        end
        print("|cffFF0000ArenaCore DR:|r Cannot show test icons in real arena")
        return
    end
    
    local frames = GetFrames()
    if not frames then 
        print("|cffFF0000ArenaCore DR:|r No frames found for test mode")
        return 
    end
    
    local ac = GetAC()
    if ac and C_CVar and C_CVar.SetCVar then
        C_CVar.SetCVar("spellDiminishPVPEnemiesEnabled", "1")
    end

    for i = 1, MAX_ARENA_ENEMIES do
        local frame = frames[i]
        if not frame then break end

        local tray = self:EnsureTray(frame, "arena" .. i)
        if tray and tray.trayItemPool and tray.RefreshTrayLayout then
            tray._acTestPreview = true
            tray:Show()

            tray.trayItemPool:ReleaseAll()
            tray._acPreviewItems = tray._acPreviewItems or {}
            wipe(tray._acPreviewItems)

            if tray.__acLocalTray then
                tray.trayItemOrder = tray.trayItemOrder or {}
                tray.activeItemForCategory = tray.activeItemForCategory or {}
                wipe(tray.trayItemOrder)
                wipe(tray.activeItemForCategory)
            end

            for _, categoryEnum in ipairs(PVP_TRAY_ORDER) do
                local arenacoreName = MIDNIGHT_TO_ARENACORE[categoryEnum]
                if arenacoreName and self:IsPvPCategoryEnabled(arenacoreName) then
                    local item = tray.trayItemPool:Acquire()
                    tray._acPreviewItems[categoryEnum] = item
                    item.isEditModePreview = true

                    if tray.__acLocalTray and tray.AddCategoryToOrder and tray.activeItemForCategory then
                        pcall(tray.AddCategoryToOrder, tray, categoryEnum)
                        tray.activeItemForCategory[categoryEnum] = item
                    end

                    item:SetCategoryInfo({
                        name = PVP_DR_CATEGORIES[categoryEnum].name,
                        category = categoryEnum,
                        icon = PVP_DR_CATEGORIES[categoryEnum].icon,
                    })

                    item:Show()

                    local previewImmune = IsTestPreviewImmune(categoryEnum)
                    item._acPreviewImmune = previewImmune
                    item:UpdateState({
                        startTime = GetTime(),
                        duration = 18.0,
                        showCountdown = true,
                        isImmune = previewImmune,
                    })

                    -- Ensure cooldown edge overlay is created and synced after UpdateState sets the cooldown.
                    self:StyleTrayItem(item)

                    if ac and ac.DRSpiralAnimation and ac.DRSpiralAnimation.ApplySettings and item.Cooldown then
                        ac.DRSpiralAnimation:ApplySettings(item.Cooldown)
                    end
                end
            end

            tray:RefreshTrayLayout()
        end
    end

    self:RefreshLayout()
    self:StartTestModeTicker()

end

function DR_PvP:StartTestModeTicker()
    -- Cancel existing ticker if any.
    if testModeTicker then
        testModeTicker:Cancel()
        testModeTicker = nil
    end
    
    -- Refresh the preview every DR reset.
    testModeTicker = C_Timer.NewTicker(18.0, function()
        local frames = GetFrames()
        if not frames then return end
        
        local now = GetTime()
        
        for i = 1, MAX_ARENA_ENEMIES do
            local frame = frames[i]
            if not frame then break end

            local tray = frame.acDrTray
            if tray and tray._acTestPreview and tray._acPreviewItems then
                for categoryEnum, item in pairs(tray._acPreviewItems) do
                    if item and item.isEditModePreview and item.UpdateState then
                        local previewImmune = IsTestPreviewImmune(categoryEnum)
                        item._acPreviewImmune = previewImmune
                        item:UpdateState({
                            startTime = now,
                            duration = 18.0,
                            showCountdown = true,
                            isImmune = previewImmune,
                        })

                        local ac = GetAC()
                        if ac and ac.DRSpiralAnimation and ac.DRSpiralAnimation.ApplySettings and item.Cooldown then
                            ac.DRSpiralAnimation:ApplySettings(item.Cooldown)
                        end
                    end
                end
            end
        end
        
    end)
    
end

function DR_PvP:HideTestIcons()
    -- Stop the preview ticker.
    if testModeTicker then
        testModeTicker:Cancel()
        testModeTicker = nil
    end
    
    local frames = GetFrames()
    if not frames then return end
    
    for i = 1, MAX_ARENA_ENEMIES do
        local frame = frames[i]
        if not frame then break end

        local tray = frame.acDrTray
        if tray and tray._acTestPreview then
            if tray.RemoveAllTrayItems then
                tray:RemoveAllTrayItems()
            elseif tray.trayItemPool and tray.trayItemOrder and tray.activeItemForCategory then
                tray.trayItemPool:ReleaseAll()
                tray.trayItemOrder = tray.trayItemOrder or {}
                tray.activeItemForCategory = tray.activeItemForCategory or {}
                if tray.trayItemOrder then
                    wipe(tray.trayItemOrder)
                end
                if tray.activeItemForCategory then
                    wipe(tray.activeItemForCategory)
                end
            end

            tray._acTestPreview = nil
            tray:Hide()
        end
    end
    
end

local function SetBlizzardDREnabled(enabled)
    if not C_CVar or not C_CVar.SetCVar then
        return
    end

    local value = enabled and "1" or "0"
    pcall(C_CVar.SetCVar, "spellDiminishPVPEnemiesEnabled", value)
end

GetBlizzardArenaTray = function(arenaIndex)
    if not arenaIndex then return nil end

    local caf = _G.CompactArenaFrame
    if not caf and _G.CompactArenaFrame_Generate then
        pcall(_G.CompactArenaFrame_Generate)
        caf = _G.CompactArenaFrame
    end
    if not caf then return nil end

    local memberFrames = caf.memberUnitFrames
    if not memberFrames then return nil end

    local unitFrame = memberFrames[arenaIndex]
    if not unitFrame then return nil end

    return unitFrame.SpellDiminishStatusTray
end

function DR_PvP:PopulateTestPreviewTray(tray)
    if not tray or not tray.trayItemPool or not tray.RefreshTrayLayout then
        return
    end

    local db = GetSettings()
    if not db or db.enabled == false then
        return
    end

    tray._acTestPreview = true
    tray:Show()

    tray.trayItemPool:ReleaseAll()
    tray.trayItemOrder = tray.trayItemOrder or {}
    tray.activeItemForCategory = tray.activeItemForCategory or {}
    if tray.trayItemOrder then
        wipe(tray.trayItemOrder)
    end
    if tray.activeItemForCategory then
        wipe(tray.activeItemForCategory)
    end

    for _, categoryEnum in ipairs(PVP_TRAY_ORDER) do
        local arenacoreName = MIDNIGHT_TO_ARENACORE[categoryEnum]
        if arenacoreName and self:IsPvPCategoryEnabled(arenacoreName) then
            local item = tray.trayItemPool:Acquire()
            tray:AddCategoryToOrder(categoryEnum)
            tray.activeItemForCategory[categoryEnum] = item
            item.isEditModePreview = true

            item:SetCategoryInfo({
                name = PVP_DR_CATEGORIES[categoryEnum].name,
                category = categoryEnum,
                icon = PVP_DR_CATEGORIES[categoryEnum].icon,
            })

            item:Show()
            local previewImmune = IsTestPreviewImmune(categoryEnum)
            item._acPreviewImmune = previewImmune
            item:UpdateState({
                startTime = GetTime(),
                duration = 18.0,
                showCountdown = true,
                isImmune = previewImmune,
            })
        end
    end

    tray:RefreshTrayLayout()
end

-- ============================================================================
-- SETTINGS AND LAYOUT (PvP FOCUSED)
-- ============================================================================

function DR_PvP:RefreshLayout()
    local frames = GetFrames()
    if not frames then return end
    
    local db = GetSettings()
    if not db or db.enabled == false then
        SetBlizzardDREnabled(false)
        self:HideTestIcons()

        for i = 1, MAX_ARENA_ENEMIES do
            local frame = frames[i]

            if frame and frame.drIcons then
                for _category, drIcon in pairs(frame.drIcons) do
                    if drIcon then
                        drIcon:Hide()
                    end
                end
            end

            local tray = frame and frame.acDrTray
            if tray then
                if tray._acTestPreview then
                    if tray.RemoveAllTrayItems then
                        tray:RemoveAllTrayItems()
                    end
                    tray:Hide()
                elseif tray.UpdateShownState then
                    tray:UpdateShownState()
                end
            end
        end

        return
    end

    SetBlizzardDREnabled(true)

    local baseX = (db.positioning and db.positioning.horizontal) or 0
    local baseY = (db.positioning and db.positioning.vertical) or 0
    local iconSize = (db.sizing and db.sizing.size) or 22

    local ac = GetAC()
    local _, instanceType = IsInInstance()
    local inArena = instanceType == "arena"
    local inPrepRoom = IsPrepRoom()
    
    -- SAFETY FIX: Never show test mode in real arena matches
    -- This prevents stuck testModeEnabled flag from causing issues
    local inTestMode = false
    if ac and ac.testModeEnabled and not inArena then
        inTestMode = true
    end

    local useBlizzardTrays = inArena
    if inArena then
        self:StartArenaStyleTicker()
    end

    for i = 1, MAX_ARENA_ENEMIES do
        local frame = frames[i]
        if not frame then break end

        if frame.drIcons then
            for _category, drIcon in pairs(frame.drIcons) do
                if drIcon then
                    drIcon:Hide()
                end
            end
        end

        local tray = frame.acDrTray
        if useBlizzardTrays then
            local oldTray = tray
            tray = GetBlizzardArenaTray(i)
            frame.acDrTray = tray

            if oldTray and oldTray ~= tray then
                if oldTray.UnregisterAllEvents then
                    oldTray:UnregisterAllEvents()
                end
                if oldTray.__acLocalTray or oldTray._acTestPreview then
                    oldTray:Hide()
                end
            end

            if tray and not tray._acChildrenPrestyled then
                tray._acChildrenPrestyled = true
                if tray.GetChildren then
                    local children = { tray:GetChildren() }
                    for j = 1, #children do
                        local item = children[j]
                        if item and item.Icon and item.Cooldown then
                            self:StyleTrayItem(item)
                        end
                    end
                end
            end

        else
            -- Leaving arena leaves a stale Blizzard tray on frame.acDrTray (no __acLocalTray flag).
            -- Clear it so we don't try to iterate its forbidden pool on the way out.
            if tray and not tray.__acLocalTray then
                frame.acDrTray = nil
                tray = nil
            end
            if inTestMode then
                tray = self:EnsureTray(frame, "arena" .. i)
            end
        end

        if inTestMode and not inArena and tray and not tray._acTestPreview then
            self:PopulateTestPreviewTray(tray)
        end

        if tray and not inArena and tray.trayItemPool and tray.trayItemPool.EnumerateActive then
            for item in tray.trayItemPool:EnumerateActive() do
                if item then
                    self:StyleTrayItem(item)
                end
            end
        elseif tray and tray._acTestPreview and tray.activeItemForCategory then
            for _categoryEnum, item in pairs(tray.activeItemForCategory) do
                if item then
                    self:StyleTrayItem(item)
                end
            end
        end

        if tray and (inArena or inTestMode or tray._acTestPreview) then
            local anchorOffset = (iconSize / 2)
            if tray.__acLocalTray or tray._acTestPreview then
                tray:ClearAllPoints()

                if GetGrowthDirection() == 4 then
                    tray:SetPoint("RIGHT", frame, "CENTER", baseX + anchorOffset, baseY)
                else
                    tray:SetPoint("LEFT", frame, "CENTER", baseX - anchorOffset, baseY)
                end

                if tray.RefreshTrayLayout then
                    tray:RefreshTrayLayout()
                end
                tray:Show()
            elseif inArena then
                if tray.SetParent and tray:GetParent() ~= frame then
                    pcall(tray.SetParent, tray, frame)
                end

                if tray.UpdateShownState then
                    pcall(tray.UpdateShownState, tray)
                else
                    pcall(tray.Show, tray)
                end

                pcall(tray.ClearAllPoints, tray)
                if GetGrowthDirection() == 4 then
                    pcall(tray.SetPoint, tray, "RIGHT", frame, "CENTER", baseX + anchorOffset, baseY)
                else
                    pcall(tray.SetPoint, tray, "LEFT", frame, "CENTER", baseX - anchorOffset, baseY)
                end
            end
        elseif tray and (tray.__acLocalTray or tray._acTestPreview) then
            tray:Hide()
        end

        if inPrepRoom and tray then
            FilterPrepRoomTrayItems(tray)
        end
    end

    if inTestMode and not testModeTicker then
        self:StartTestModeTicker()
    end
end

function DR_PvP:UpdatePositions(frame)
    -- UI calls this when sliders move. We just do a full refresh and call it a day.
    self:RefreshLayout()
end

-- ============================================================================
-- PVP CATEGORY MANAGEMENT
-- ============================================================================

function DR_PvP:GetAllPvPCategories()
    local categories = {}
    
    if C_SpellDiminish and C_SpellDiminish.GetAllSpellDiminishCategories then
        local blizzCategories = C_SpellDiminish.GetAllSpellDiminishCategories(Enum.SpellDiminishRuleset.PvP)
        for _, categoryInfo in ipairs(blizzCategories) do
            -- Only keep the categories we actually use.
            if PVP_DR_CATEGORIES[categoryInfo.category] then
                local arenacoreName = MIDNIGHT_TO_ARENACORE[categoryInfo.category]
                if arenacoreName then
                    categories[arenacoreName] = {
                        enum = categoryInfo.category,
                        name = categoryInfo.name,
                        icon = categoryInfo.icon
                    }
                end
            end
        end
    end
    
    return categories
end

function DR_PvP:IsPvPCategoryEnabled(categoryName)
    local db = GetSettings()
    if not db or not db.categories then return true end
    
    return db.categories[categoryName] ~= false
end

-- ============================================================================
-- CLEANUP AND RESET
-- ============================================================================

function DR_PvP:ClearAllDRs()
    local frames = GetFrames()
    if not frames then return end

    local _, instanceType = IsInInstance()
    local inArena = (instanceType == "arena")
    
    for i = 1, MAX_ARENA_ENEMIES do
        local frame = frames[i]
        if frame and frame.drIcons then
            for _category, drIcon in pairs(frame.drIcons) do
                if drIcon then
                    drIcon:Hide()
                    drIcon:ClearAllPoints()
                end
            end
            frame.drIcons = {}
        end

        local tray = frame and frame.acDrTray
        if tray and tray.RemoveAllTrayItems and (tray.__acLocalTray or tray._acTestPreview) and (not inArena) then
            tray:RemoveAllTrayItems()
        end
    end
end

function DR_PvP:ResetForSoloShuffle()
    -- Solo Shuffle swaps people around, so we wipe the slate between rounds.
    self:ClearAllDRs()
    
    -- Re-hook trays if needed.
    C_Timer.After(0.1, function()
        local _, instanceType = IsInInstance()
        if instanceType == "arena" then
            return
        end
        self:IntegrateBlizzardDRTrays()
    end)
end

-- ============================================================================
-- HOOKING INTO ARENACORE SYSTEM
-- ============================================================================

local function HookCoreFunctions()
    local ac = GetAC()
    local manager = ac.MasterFrameManager or ac.FrameManager
    if not manager then
        if C_Timer and C_Timer.After then
            C_Timer.After(0.1, HookCoreFunctions)
        end
        return
    end

    if not manager._drPvPModuleHooked then
        -- Replace old DR functions with new PvP ones
        manager.CreateDRIcon = function(self, parent, category)
            return DR_PvP:CreateDRIcon(parent, category)
        end

        manager.ShowTestDRIcons = function(self)
            return DR_PvP:ShowTestIcons()
        end

        manager.HideTestDRIcons = function(self)
            return DR_PvP:HideTestIcons()
        end

        manager._drPvPModuleHooked = true
    end

    -- Hook into main ArenaCore functions
    function ac:RefreshDRLayout()
        DR_PvP:RefreshLayout()
    end

    function ac:UpdateDRPositions(frame)
        DR_PvP:UpdatePositions(frame)
    end
    
end

-- ============================================================================
-- MIDNIGHT DR EVENT HANDLING (Custom Styling Integration)
-- ============================================================================

-- Our own little DR event frame (so we're not fighting other stuff).
local DREventFrame = CreateFrame("Frame")
DREventFrame:UnregisterAllEvents()

-- Register for arena state events to handle DR updates properly
DREventFrame:RegisterEvent("ARENA_OPPONENT_UPDATE")
DREventFrame:RegisterEvent("ARENA_PREP_OPPONENT_SPECIALIZATIONS")
DREventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")

DREventFrame:SetScript("OnEvent", function(self, event, ...)
    if event == "ARENA_OPPONENT_UPDATE" or event == "ARENA_PREP_OPPONENT_SPECIALIZATIONS" or event == "PLAYER_ENTERING_WORLD" then
        -- Refresh DR layout when arena state changes
        C_Timer.After(0.1, function()
            if DR_PvP and DR_PvP.RefreshLayout then
                DR_PvP:RefreshLayout()
            end
        end)
    end
end)

-- ============================================================================
-- SOLO SHUFFLE SUPPORT
-- ============================================================================

-- Solo Shuffle round transitions.
local soloShuffleFrame = CreateFrame("Frame")
soloShuffleFrame:RegisterEvent("GROUP_ROSTER_UPDATE")
soloShuffleFrame:SetScript("OnEvent", function(self, event)
    if event == "GROUP_ROSTER_UPDATE" then
        local _, instanceType = IsInInstance()
        if instanceType == "arena" then
            DR_PvP:ResetForSoloShuffle()
        end
    end
end)

SLASH_ARENACOREDRICONS1 = "/acdricons"
SlashCmdList["ARENACOREDRICONS"] = function()
    if not C_SpellDiminish or not C_SpellDiminish.GetSpellDiminishCategoryInfo then
        print("|cffFF0000ArenaCore DR:|r C_SpellDiminish.GetSpellDiminishCategoryInfo not available")
        return
    end

    local categories = {
        { name = "Stun", enum = Enum.SpellDiminishCategory.Stun },
        { name = "Incapacitate", enum = Enum.SpellDiminishCategory.Incapacitate },
        { name = "Silence", enum = Enum.SpellDiminishCategory.Silence },
        { name = "Disorient", enum = Enum.SpellDiminishCategory.Disorient },
    }

    print("|cff00FF00ArenaCore DR:|r Blizzard PvP DR category icons:")
    for i = 1, #categories do
        local c = categories[i]
        local info = C_SpellDiminish.GetSpellDiminishCategoryInfo(c.enum)
        if info then
            print(string.format("|cff00FF00[DR ICON]|r %s enum=%s name=%s icon=%s", tostring(c.name), tostring(c.enum), tostring(info.name), tostring(info.icon)))
        else
            print(string.format("|cffFF0000[DR ICON]|r %s enum=%s (no info)", tostring(c.name), tostring(c.enum)))
        end
    end
end

-- Boot it up.
function DR_PvP:Initialize()
    if self:InitializeDRSystem() then
        HookCoreFunctions()
        
        -- Integrate Blizzard trays after a short delay to ensure frames are created
        C_Timer.After(1.0, function()
            self:IntegrateBlizzardDRTrays()
        end)

        -- Make sure real-arena styling/anchoring doesn't depend on other modules
        -- remembering to call RefreshDRLayout at the perfect time.
        C_Timer.After(1.1, function()
            self:StartArenaStyleTicker()
        end)
        
        return true
    end
    return false
end

-- ============================================================================
-- REGISTER AS PRIMARY DR MODULE (main entry point)
-- ============================================================================

-- Register DR_PvP as AC.DR so all existing callsites work
local function RegisterAsPrimaryDRModule()
    local ac = GetAC()
    if not ac then
        C_Timer.After(0.1, RegisterAsPrimaryDRModule)
        return
    end
    
    -- Clear any old DR system references
    if ac.DR and ac.DR ~= DR_PvP then
        local oldDR = ac.DR
        if oldDR.ClearAllDRs then
            oldDR:ClearAllDRs()
        end
        if oldDR.CancelTestTicker then
            oldDR:CancelTestTicker()
        end
        if oldDR.CancelRealArenaTicker then
            oldDR:CancelRealArenaTicker()
        end
    end
    
    -- Register DR_PvP as the primary DR module
    ac.DR = DR_PvP
    ac.MasterFrameManager = ac.MasterFrameManager or {}
    ac.MasterFrameManager.DR = DR_PvP
    ac.FrameManager = ac.FrameManager or ac.MasterFrameManager
    ac.FrameManager.DR = DR_PvP
    
    -- Export for external access
    _G.ArenaCoreDR_PvP = DR_PvP
    
end

-- Initialize and register on load
C_Timer.After(0.5, function()
    local ac = GetAC()
    if ac and ac.DB then
        RegisterAsPrimaryDRModule()
        
        -- Initialize the DR system
        if DR_PvP:Initialize() then
        else
            print("|cffFF0000ArenaCore DR:|r Failed to initialize PvP DR system")
        end
    else
        C_Timer.After(0.5, RegisterAsPrimaryDRModule)
    end
end)

-- ============================================================================
-- DEBUG COMMANDS (from DR_PvP_Initializer.lua)
-- ============================================================================

SLASH_ARENACOREDRTEST1 = "/acdrtest"
SlashCmdList["ARENACOREDRTEST"] = function()
    local ac = GetAC()
    if ac and ac.DR_PvP then
        print("|cff00FF00ArenaCore DR:|r Testing PvP DR icons...")
        ac.DR_PvP:ShowTestIcons()
        
        if C_SpellDiminish and C_SpellDiminish.IsSystemSupported() then
            print("|cff00FF00[API]|r Midnight DR System Supported: " .. tostring(C_SpellDiminish.IsSystemSupported()))
            
            if C_SpellDiminish.GetAllSpellDiminishCategories then
                local categories = C_SpellDiminish.GetAllSpellDiminishCategories(Enum.SpellDiminishRuleset.PvP)
                print("|cff00FF00[API]|r Found " .. #categories .. " PvP categories:")
                for i, cat in ipairs(categories) do
                    print("|cff00FF00[API]|r   " .. i .. ". " .. (cat.name or "Unknown") .. " (enum: " .. cat.category .. ")")
                end
            end
        else
            print("|cffFF0000[API]|r Midnight DR System not available")
        end
    else
        print("|cffFF0000ArenaCore DR:|r PvP DR system not loaded")
    end
end

SLASH_ARENACOREDRHIDE1 = "/acdrhide"
SlashCmdList["ARENACOREDRHIDE"] = function()
    local ac = GetAC()
    if ac and ac.DR_PvP then
        print("|cff00FF00ArenaCore DR:|r Hiding PvP DR test icons...")
        ac.DR_PvP:HideTestIcons()
    else
        print("|cffFF0000ArenaCore DR:|r PvP DR system not loaded")
    end
end

SLASH_ARENACOREDRPOS1 = "/acdrpos"
SlashCmdList["ARENACOREDRPOS"] = function()
    local ac = GetAC()
    if ac and ac.DR_PvP then
        print("|cff00FF00ArenaCore DR:|r Testing positioning system...")
        
        local db = ac.DB and ac.DB.profile and ac.DB.profile.diminishingReturns
        if db then
            print("|cff00FF00[POS]|r Current positioning settings:")
            print("|cff00FF00[POS]|r   Horizontal: " .. (db.positioning and db.positioning.horizontal or "NOT SET"))
            print("|cff00FF00[POS]|r   Vertical: " .. (db.positioning and db.positioning.vertical or "NOT SET"))
            print("|cff00FF00[POS]|r   Size: " .. (db.sizing and db.sizing.size or "NOT SET"))
            
            print("|cff00FF00[POS]|r Testing RefreshLayout...")
            ac.DR_PvP:RefreshLayout()
            
            print("|cff00FF00[POS]|r Positioning test complete!")
        else
            print("|cffFF0000[POS]|r No DR settings found")
        end
    else
        print("|cffFF0000ArenaCore DR:|r PvP DR system not loaded")
    end
end
