local AC = _G.ArenaCore or {}

local CastBars = {}
local bit_band = bit.band

local function ResolveSpellSchoolMask(spellOrMask)
    if not spellOrMask then
        return 1  -- Physical (default)
    end

    if type(spellOrMask) == "number" then
        if C_Spell and C_Spell.GetSpellInfo then
            local info = C_Spell.GetSpellInfo(spellOrMask)
            if info and info.schoolMask and info.schoolMask ~= 0 then
                -- Successfully retrieved spell school from spell ID
                return info.schoolMask
            end
        end

        -- CRITICAL FIX: If we can't get spell info, assume it's already a school mask
        -- School masks are small numbers (1, 2, 4, 8, 16, 32, 64 or combinations)
        -- Spell IDs are typically large (100+)
        -- If input is < 100, treat as school mask; otherwise default to Physical
        if spellOrMask < 100 then
            return spellOrMask
        else
            -- Spell ID but couldn't get info - default to Physical
            return 1
        end
    end

    return 1  -- Physical (default)
end

---Return RGB values for a given spell school or spell ID.
---@param spellOrMask number|nil Spell school mask or spell ID.
function CastBars:GetSpellSchoolColor(spellOrMask)
    local spellSchool = ResolveSpellSchoolMask(spellOrMask)

    -- Spell School Color Mapping (WoW Standard)
    if not spellSchool or spellSchool == 0 then
        return 1.0, 0.7, 0.0  -- Unknown/Default - Orange
    elseif spellSchool == 1 then
        return 1.0, 1.0, 1.0  -- Physical - White
    elseif spellSchool == 2 or bit_band(spellSchool, 2) > 0 then
        return 1.0, 0.9, 0.0  -- Holy - Gold/Yellow
    elseif spellSchool == 4 or bit_band(spellSchool, 4) > 0 then
        return 1.0, 0.3, 0.0  -- Fire - Orange/Red
    elseif spellSchool == 8 or bit_band(spellSchool, 8) > 0 then
        return 0.3, 1.0, 0.3  -- Nature - Green
    elseif spellSchool == 16 or bit_band(spellSchool, 16) > 0 then
        return 0.3, 0.8, 1.0  -- Frost - Light Blue
    elseif spellSchool == 32 or bit_band(spellSchool, 32) > 0 then
        return 0.5, 0.3, 0.7  -- Shadow - Purple
    elseif spellSchool == 64 or bit_band(spellSchool, 64) > 0 then
        return 1.0, 0.5, 1.0  -- Arcane - Pink/Purple
    else
        return 1.0, 0.7, 0.0  -- Fallback - Orange
    end
end


---Register all UNIT_SPELLCAST events that drive cast bar updates.
function CastBars:RegisterEvents(eventFrame)
    if not eventFrame then return end
    
    eventFrame:RegisterUnitEvent("UNIT_SPELLCAST_START", "arena1", "arena2", "arena3")
    eventFrame:RegisterUnitEvent("UNIT_SPELLCAST_STOP", "arena1", "arena2", "arena3")
    eventFrame:RegisterUnitEvent("UNIT_SPELLCAST_FAILED", "arena1", "arena2", "arena3")
    eventFrame:RegisterUnitEvent("UNIT_SPELLCAST_INTERRUPTED", "arena1", "arena2", "arena3")
    eventFrame:RegisterUnitEvent("UNIT_SPELLCAST_CHANNEL_START", "arena1", "arena2", "arena3")
    eventFrame:RegisterUnitEvent("UNIT_SPELLCAST_CHANNEL_STOP", "arena1", "arena2", "arena3")
    eventFrame:RegisterUnitEvent("UNIT_SPELLCAST_EMPOWER_START", "arena1", "arena2", "arena3")
    eventFrame:RegisterUnitEvent("UNIT_SPELLCAST_EMPOWER_STOP", "arena1", "arena2", "arena3")
end

---Handle UNIT_SPELLCAST_* events and update the supplied cast bar.
function CastBars:Update(frame, unit, event)
    if not frame or not frame.castBar then return end

    if _G.ArenaCore and _G.ArenaCore.testModeEnabled then
        return
    end

    local name, text, texture, startTime, endTime, isTradeSkill, castID, notInterruptible, spellID
    local isMidnight = frame.castBar._isMidnightBlizzardFrame

    if event == "UNIT_SPELLCAST_START" then
        name, text, texture, startTime, endTime, isTradeSkill, castID, notInterruptible, spellID = UnitCastingInfo(unit)
        if name then
            frame.castBar.isCasting = true
            frame.castBar.isChanneling = false
        end
    elseif event == "UNIT_SPELLCAST_CHANNEL_START" then
        name, text, texture, startTime, endTime, isTradeSkill, notInterruptible, spellID = UnitChannelInfo(unit)
        if name then
            frame.castBar.isChanneling = true
            frame.castBar.isCasting = false
        end
    elseif event == "UNIT_SPELLCAST_EMPOWER_START" then
        name, text, texture, startTime, endTime, isTradeSkill, notInterruptible, spellID = UnitChannelInfo(unit)
        if name then
            frame.castBar.isChanneling = true
            frame.castBar.isCasting = false
        end
    end

    -- CRITICAL: For Midnight frames in live arena, startTime/endTime are secret values
    -- We cannot do ANY arithmetic on them or the addon will error
    -- Show a static "casting" indicator instead of an animated bar
    if isMidnight and (not name or not startTime or not endTime) then
        -- Secret values present - show static cast bar without animation
        frame.castBar:Show()
        frame.castBar:SetAlpha(1.0)
        frame.castBar:SetStatusBarColor(1.0, 0.7, 0.0)
        frame.castBar:SetMinMaxValues(0, 1)
        frame.castBar:SetValue(1) -- Full bar to indicate casting
        
        if frame.castBar.Text then
            frame.castBar.Text:SetText("Casting")
            frame.castBar.Text:Show()
        end
        
        if frame.castBar.Icon and texture then
            frame.castBar.Icon:SetTexture(texture)
            frame.castBar.Icon:Show()
        end
        
        return
    end
    
    if not name or not startTime or not endTime then
        self:Hide(frame)
        return
    end

    -- Show border frame
    if frame.castBar.borderFrame then
        frame.castBar.borderFrame:Show()
    end

    -- CRITICAL: notInterruptible and spellID are secret values in Midnight
    -- Cannot check them safely - use default orange color for all casts
    -- This is a limitation of Blizzard's secret-value system
    if frame.castBar.shieldOverlay then
        frame.castBar.shieldOverlay:Hide()
    end

    -- Default orange for all casts (cannot use spell school colors due to secret spellID)
    frame.castBar:SetStatusBarColor(1.0, 0.7, 0.0)

    local statusBarTexture = frame.castBar:GetStatusBarTexture()
    if statusBarTexture then
        statusBarTexture:SetDrawLayer("ARTWORK", 0)
        statusBarTexture:SetAlpha(1.0)
        statusBarTexture:Show()
    end

    frame.castBar:Show()
    frame.castBar:SetAlpha(1.0)

    if frame.castBar.bg then
        frame.castBar.bg:Show()
    end

    -- Handle text display (Midnight uses Text, custom uses text)
    if isMidnight and frame.castBar.Text then
        frame.castBar.Text:SetText(name or text or "")
        frame.castBar.Text:Show()
    elseif frame.castBar.text then
        frame.castBar.text:SetText(name or text or "")
        frame.castBar.text:Show()
    end

    -- Handle spell icon (Midnight uses Icon, custom uses spellIcon.texture)
    if isMidnight and frame.castBar.Icon and texture then
        frame.castBar.Icon:SetTexture(texture)
        frame.castBar.Icon:Show()
    elseif frame.castBar.spellIcon and frame.castBar.spellIcon.texture and texture then
        frame.castBar.spellIcon.texture:SetTexture(texture)
        -- Use rawget to bypass metatable defaults
        local spellIconsEnabled = false
        if castBarDB and castBarDB.spellIcons then
            local enabled = rawget(castBarDB.spellIcons, "enabled")
            spellIconsEnabled = (enabled == nil and true) or (enabled == true)
        end
        if spellIconsEnabled then
            frame.castBar.spellIcon:Show()
            
            -- CRITICAL FIX: Show the border textures when showing the spell icon
            -- These were hidden in UpdatePrepRoomUnit and need to be shown again
            if frame.castBar.spellIcon.border then
                if frame.castBar.spellIcon.border.top then frame.castBar.spellIcon.border.top:Show() end
                if frame.castBar.spellIcon.border.bottom then frame.castBar.spellIcon.border.bottom:Show() end
                if frame.castBar.spellIcon.border.left then frame.castBar.spellIcon.border.left:Show() end
                if frame.castBar.spellIcon.border.right then frame.castBar.spellIcon.border.right:Show() end
            end
            -- Also check styledBorder (alternative storage location)
            if frame.castBar.spellIcon.styledBorder then
                if frame.castBar.spellIcon.styledBorder.top then frame.castBar.spellIcon.styledBorder.top:Show() end
                if frame.castBar.spellIcon.styledBorder.bottom then frame.castBar.spellIcon.styledBorder.bottom:Show() end
                if frame.castBar.spellIcon.styledBorder.left then frame.castBar.spellIcon.styledBorder.left:Show() end
                if frame.castBar.spellIcon.styledBorder.right then frame.castBar.spellIcon.styledBorder.right:Show() end
            end
        else
            frame.castBar.spellIcon:Hide()

            -- Hide borders too (some borders are separate textures and can linger)
            if frame.castBar.spellIcon.border then
                if frame.castBar.spellIcon.border.top then frame.castBar.spellIcon.border.top:Hide() end
                if frame.castBar.spellIcon.border.bottom then frame.castBar.spellIcon.border.bottom:Hide() end
                if frame.castBar.spellIcon.border.left then frame.castBar.spellIcon.border.left:Hide() end
                if frame.castBar.spellIcon.border.right then frame.castBar.spellIcon.border.right:Hide() end
            end
            if frame.castBar.spellIcon.styledBorder then
                if frame.castBar.spellIcon.styledBorder.top then frame.castBar.spellIcon.styledBorder.top:Hide() end
                if frame.castBar.spellIcon.styledBorder.bottom then frame.castBar.spellIcon.styledBorder.bottom:Show() end
                if frame.castBar.spellIcon.styledBorder.left then frame.castBar.spellIcon.styledBorder.left:Hide() end
                if frame.castBar.spellIcon.styledBorder.right then frame.castBar.spellIcon.styledBorder.right:Hide() end
            end
        end
    end

    -- For non-Midnight frames or when timing values are available, animate the cast bar
    local duration = (endTime - startTime) / 1000
    frame.castBar:SetMinMaxValues(0, duration)
    
    -- CRITICAL FIX: Channeled spells start at max and count down
    -- Normal casts start at 0 and count up
    if frame.castBar.isChanneling then
        -- Channeling: Start at max (full bar), count down to 0
        frame.castBar:SetValue(duration)
    else
        -- Normal cast: Start at 0, count up to max
        frame.castBar:SetValue((GetTime() * 1000 - startTime) / 1000)
    end
    
    frame.castBar._castStartTimeMS = startTime
    frame.castBar._castEndTimeMS = endTime

    if frame.castBar.updateTimer then
        frame.castBar.updateTimer:Cancel()
        frame.castBar.updateTimer = nil
    end

    frame.castBar.updateTimer = C_Timer.NewTicker(0.01, function()
        if not frame.castBar:IsShown() then
            if frame.castBar.updateTimer then
                frame.castBar.updateTimer:Cancel()
                frame.castBar.updateTimer = nil
            end
            return
        end

        local newTime = GetTime() * 1000
        local duration = frame.castBar._castEndTimeMS - frame.castBar._castStartTimeMS
        local elapsed = newTime - frame.castBar._castStartTimeMS

        -- CRITICAL FIX: Different update logic for channeling vs casting
        if frame.castBar.isChanneling then
            -- Channeling: Count down from max to 0 (bar empties)
            local remaining = duration - elapsed
            if remaining <= 0 then
                CastBars:Hide(frame)
                return
            end
            frame.castBar:SetValue(remaining / 1000)
        else
            -- Normal cast: Count up from 0 to max (bar fills)
            if elapsed >= duration then
                CastBars:Hide(frame)
                return
            end
            frame.castBar:SetValue(elapsed / 1000)
        end
    end)
end

---Hide and reset the cast bar for the supplied frame.
function CastBars:Hide(frame)
    if not frame or not frame.castBar then return end

    if frame.castBar.updateTimer then
        frame.castBar.updateTimer:Cancel()
        frame.castBar.updateTimer = nil
    end

    frame.castBar:Hide()
    frame.castBar:SetValue(0)
    frame.castBar.isCasting = false
    frame.castBar.isChanneling = false

    if frame.castBar.bg then
        frame.castBar.bg:Hide()
    end

    if frame.castBar.text then
        frame.castBar.text:SetText("")
        frame.castBar.text:Hide()
    end

    if frame.castBar.spellIcon then
        frame.castBar.spellIcon:Hide()
    end

    if frame.castBar.shieldOverlay then
        frame.castBar.shieldOverlay:Hide()
    end

    if frame.castBar.borderFrame then
        frame.castBar.borderFrame:Hide()
    end
end

---Apply static test-mode spell visuals to a frame's cast bar.
---@param frame table Arena frame container.
---@param spellData table Table with `name`, `icon`, `spellSchool` fields.
---@param opts table|nil Optional config `{ isNonInterruptible=bool, progress=number }`.
function CastBars:ApplyTestSpell(frame, spellData, opts)
    if not frame or not frame.castBar or not spellData then return end

    local castBarDB = AC.DB and AC.DB.profile and AC.DB.profile.castBars
    local useSpellSchoolColors = castBarDB and castBarDB.spellSchoolColors
    -- Use rawget to bypass metatable defaults
    local spellIconsEnabled = false
    if castBarDB and castBarDB.spellIcons then
        local enabled = rawget(castBarDB.spellIcons, "enabled")
        spellIconsEnabled = (enabled == nil and true) or (enabled == true)
    end
    local progress = opts and opts.progress or 75
    local nonInterruptible = opts and opts.isNonInterruptible or false

    local castBar = frame.castBar
    local isMidnightBlizzard = castBar._isMidnightBlizzardFrame

    castBar.testSpellName = spellData.name
    castBar.testSpellIcon = spellData.icon
    castBar.testSpellSchool = spellData.spellSchool or 1
    castBar.testNotInterruptible = nonInterruptible

    castBar:SetMinMaxValues(0, 100)
    castBar:SetValue(progress)
    castBar:SetAlpha(1)
    castBar:Show()

    -- Handle Blizzard vs custom cast bar differences
    if isMidnightBlizzard then
        -- Blizzard CastingBarFrame uses Text (capital T) and Icon
        if castBar.Text then
            castBar.Text:SetText(spellData.name or "")
            castBar.Text:Show()
        end
        if castBar.Icon and spellData.icon then
            castBar.Icon:SetTexture(spellData.icon)
            if spellIconsEnabled then
                castBar.Icon:Show()
                if castBar.Icon._borderFrame then
                    castBar.Icon._borderFrame:Show()
                end
            else
                castBar.Icon:Hide()
                if castBar.Icon._borderFrame then
                    castBar.Icon._borderFrame:Hide()
                end
            end
        end
        if castBar.BorderShield then
            if nonInterruptible then
                castBar.BorderShield:Show()
            else
                castBar.BorderShield:Hide()
            end
        end
        -- Set color (always orange for consistency with live mode)
        castBar:SetStatusBarColor(1.0, 0.7, 0.0)  -- Orange for test mode
    else
        -- Custom cast bar (non-Midnight)
        if castBar.fill then
            castBar.fill:Show()
        end
        if castBar.bg then
            castBar.bg:Show()
        end
        if castBar.borderFrame then
            castBar.borderFrame:Show()
        end

        if castBar.text then
            castBar.text:SetText(spellData.name or "")
            castBar.text:Show()
        end

        if castBar.spellIcon and castBar.spellIcon.texture then
            if spellData.icon then
                castBar.spellIcon.texture:SetTexture(spellData.icon)
            end
            if spellIconsEnabled then
                castBar.spellIcon:Show()
                
                -- Apply spell icon positioning and scaling settings
                if castBarDB and castBarDB.spellIcons then
                    -- Use SetScale() instead of SetSize()
                    local scalePct = (castBarDB.spellIcons.sizing and castBarDB.spellIcons.sizing.scale or 100) / 100
                    castBar.spellIcon:SetScale(scalePct)

                    -- Position relative to the bar
                    local ix = (castBarDB.spellIcons.positioning and castBarDB.spellIcons.positioning.horizontal) or -4
                    local iy = (castBarDB.spellIcons.positioning and castBarDB.spellIcons.positioning.vertical) or 0
                    castBar.spellIcon:ClearAllPoints()
                    castBar.spellIcon:SetPoint("RIGHT", castBar, "LEFT", ix, iy)
                end
                
                if castBar.spellIcon.border then
                    if castBar.spellIcon.border.top then castBar.spellIcon.border.top:Show() end
                    if castBar.spellIcon.border.bottom then castBar.spellIcon.border.bottom:Show() end
                    if castBar.spellIcon.border.left then castBar.spellIcon.border.left:Show() end
                    if castBar.spellIcon.border.right then castBar.spellIcon.border.right:Show() end
                end
                if castBar.spellIcon.styledBorder then
                    if castBar.spellIcon.styledBorder.top then castBar.spellIcon.styledBorder.top:Show() end
                    if castBar.spellIcon.styledBorder.bottom then castBar.spellIcon.styledBorder.bottom:Show() end
                    if castBar.spellIcon.styledBorder.left then castBar.spellIcon.styledBorder.left:Show() end
                    if castBar.spellIcon.styledBorder.right then castBar.spellIcon.styledBorder.right:Show() end
                end
            else
                castBar.spellIcon:Hide()
                if castBar.spellIcon.border then
                    if castBar.spellIcon.border.top then castBar.spellIcon.border.top:Hide() end
                    if castBar.spellIcon.border.bottom then castBar.spellIcon.border.bottom:Hide() end
                    if castBar.spellIcon.border.left then castBar.spellIcon.border.left:Hide() end
                    if castBar.spellIcon.border.right then castBar.spellIcon.border.right:Hide() end
                end
                if castBar.spellIcon.styledBorder then
                    if castBar.spellIcon.styledBorder.top then castBar.spellIcon.styledBorder.top:Hide() end
                    if castBar.spellIcon.styledBorder.bottom then castBar.spellIcon.styledBorder.bottom:Hide() end
                    if castBar.spellIcon.styledBorder.left then castBar.spellIcon.styledBorder.left:Hide() end
                    if castBar.spellIcon.styledBorder.right then castBar.spellIcon.styledBorder.right:Hide() end
                end
            end
        end

        if castBar.shieldOverlay then
            if nonInterruptible then
                castBar.shieldOverlay:Show()
            else
                castBar.shieldOverlay:Hide()
            end
        end

        -- Always use orange for consistency with live mode (secret values prevent school colors)
        castBar:SetStatusBarColor(1.0, 0.7, 0.0)
    end
end

---Refresh stored test-mode visuals after layout changes.
---@param frame table Arena frame container.
---@param castBarDB table|nil Cast bar database settings.
function CastBars:RefreshTestLayout(frame, castBarDB)
    if not frame or not frame.castBar then return end
    local castBar = frame.castBar

    if not AC.testModeEnabled or not castBar:IsShown() then
        return
    end

    castBarDB = castBarDB or (AC.DB and AC.DB.profile and AC.DB.profile.castBars)
    local useSpellSchoolColors = castBarDB and castBarDB.spellSchoolColors
    -- Use rawget to bypass metatable defaults
    local spellIconsEnabled = false
    if castBarDB and castBarDB.spellIcons then
        local enabled = rawget(castBarDB.spellIcons, "enabled")
        spellIconsEnabled = (enabled == nil and true) or (enabled == true)
    end

    castBar:SetAlpha(1)

    if castBar.fill then
        castBar.fill:Show()
    end
    if castBar.bg then
        castBar.bg:Show()
    end
    -- Show border frame
    if castBar.borderFrame then
        castBar.borderFrame:Show()
    end

    if castBar.text and castBar.testSpellName then
        castBar.text:SetText(castBar.testSpellName)
        castBar.text:Show()
    end

    if castBar.spellIcon and castBar.spellIcon.texture and castBar.testSpellIcon then
        castBar.spellIcon.texture:SetTexture(castBar.testSpellIcon)
        if spellIconsEnabled then
            castBar.spellIcon:Show()
            
            -- Apply spell icon positioning and scaling settings
            local spellIconsDB = castBarDB and castBarDB.spellIcons
            if spellIconsDB then
                -- Use SetScale() instead of SetSize() (like sArena does)
                local scalePct = (spellIconsDB.sizing and spellIconsDB.sizing.scale or 100) / 100
                castBar.spellIcon:SetScale(scalePct)

                -- Position relative to the bar
                local ix = (spellIconsDB.positioning and spellIconsDB.positioning.horizontal) or -4
                local iy = (spellIconsDB.positioning and spellIconsDB.positioning.vertical) or 0
                castBar.spellIcon:ClearAllPoints()
                castBar.spellIcon:SetPoint("RIGHT", castBar, "LEFT", ix, iy)
            end
            
            -- CRITICAL FIX: Show the border textures when showing the spell icon
            if castBar.spellIcon.border then
                if castBar.spellIcon.border.top then castBar.spellIcon.border.top:Show() end
                if castBar.spellIcon.border.bottom then castBar.spellIcon.border.bottom:Show() end
                if castBar.spellIcon.border.left then castBar.spellIcon.border.left:Show() end
                if castBar.spellIcon.border.right then castBar.spellIcon.border.right:Show() end
            end
            if castBar.spellIcon.styledBorder then
                if castBar.spellIcon.styledBorder.top then castBar.spellIcon.styledBorder.top:Show() end
                if castBar.spellIcon.styledBorder.bottom then castBar.spellIcon.styledBorder.bottom:Show() end
                if castBar.spellIcon.styledBorder.left then castBar.spellIcon.styledBorder.left:Show() end
                if castBar.spellIcon.styledBorder.right then castBar.spellIcon.styledBorder.right:Show() end
            end
        else
            castBar.spellIcon:Hide()
            if castBar.spellIcon.border then
                if castBar.spellIcon.border.top then castBar.spellIcon.border.top:Hide() end
                if castBar.spellIcon.border.bottom then castBar.spellIcon.border.bottom:Hide() end
                if castBar.spellIcon.border.left then castBar.spellIcon.border.left:Hide() end
                if castBar.spellIcon.border.right then castBar.spellIcon.border.right:Hide() end
            end
            if castBar.spellIcon.styledBorder then
                if castBar.spellIcon.styledBorder.top then castBar.spellIcon.styledBorder.top:Hide() end
                if castBar.spellIcon.styledBorder.bottom then castBar.spellIcon.styledBorder.bottom:Hide() end
                if castBar.spellIcon.styledBorder.left then castBar.spellIcon.styledBorder.left:Hide() end
                if castBar.spellIcon.styledBorder.right then castBar.spellIcon.styledBorder.right:Hide() end
            end
        end
    elseif castBar.spellIcon and not spellIconsEnabled then
        castBar.spellIcon:Hide()
        if castBar.spellIcon.border then
            if castBar.spellIcon.border.top then castBar.spellIcon.border.top:Hide() end
            if castBar.spellIcon.border.bottom then castBar.spellIcon.border.bottom:Hide() end
            if castBar.spellIcon.border.left then castBar.spellIcon.border.left:Hide() end
            if castBar.spellIcon.border.right then castBar.spellIcon.border.right:Hide() end
        end
        if castBar.spellIcon.styledBorder then
            if castBar.spellIcon.styledBorder.top then castBar.spellIcon.styledBorder.top:Hide() end
            if castBar.spellIcon.styledBorder.bottom then castBar.spellIcon.styledBorder.bottom:Hide() end
            if castBar.spellIcon.styledBorder.left then castBar.spellIcon.styledBorder.left:Hide() end
            if castBar.spellIcon.styledBorder.right then castBar.spellIcon.styledBorder.right:Hide() end
        end
    end

    if castBar.shieldOverlay then
        if castBar.testNotInterruptible then
            castBar.shieldOverlay:Show()
        else
            castBar.shieldOverlay:Hide()
        end
    end

    -- Always use orange for consistency with live mode (secret values prevent school colors)
    castBar:SetStatusBarColor(1.0, 0.7, 0.0)
end


AC.MasterFrameManager = AC.MasterFrameManager or {}
AC.FrameManager = AC.MasterFrameManager
AC.MasterFrameManager.CastBars = CastBars

-- Hook Blizzard's Midnight cast bars to apply ArenaCore texture and borders
-- This runs AFTER Blizzard handles all secret values internally
if AC.Midnight and AC.Midnight.isMidnight then
    function CastBars:StyleMidnightCastBar(castBar)
        if not castBar or not castBar._isMidnightBlizzardFrame then return end
        
        -- Get user's selected cast bar texture
        local texturesDB = AC.DB and AC.DB.profile and AC.DB.profile.textures
        if texturesDB then
            local healthTex = texturesDB.healthBarTexture or "Interface\\AddOns\\ArenaCore\\Media\\Frametextures\\texture1.tga"
            local powerTex = texturesDB.useDifferentPowerBarTexture and texturesDB.powerBarTexture or healthTex
            local castTex = texturesDB.useDifferentCastBarTexture and texturesDB.castBarTexture or powerTex
            
            if castTex then
                -- Store the texture so we can force it to stick
                castBar._arenaCoreTexture = castTex
                
                -- Override GetTypeInfo to force our texture
                -- Returns: {fill=texture, full=texture, glow=texture}
                if not castBar._arenaCoreTypeInfoOverride then
                    castBar._arenaCoreTypeInfoOverride = true
                    castBar._arenaCoreOrigGetTypeInfo = castBar.GetTypeInfo
                    castBar.GetTypeInfo = function(self, barType)
                        local info = castBar._arenaCoreOrigGetTypeInfo and castBar._arenaCoreOrigGetTypeInfo(self, barType)
                        if type(info) == "table" then
                            local t = {}
                            for k, v in pairs(info) do
                                t[k] = v
                            end
                            t.filling = castBar._arenaCoreTexture
                            t.full = castBar._arenaCoreTexture
                            return t
                        end
                        return {
                            filling = castBar._arenaCoreTexture,
                            full = castBar._arenaCoreTexture,
                        }
                    end
                end
                
                -- Apply the texture
                pcall(castBar.SetStatusBarTexture, castBar, castTex)
            end
        end
        
        -- Hide Blizzard's native textures so only ArenaCore's texture shows
        if castBar.Background then castBar.Background:Hide() end
        if castBar.Border then castBar.Border:Hide() end
        if castBar.TextBorder then castBar.TextBorder:Hide() end
        if castBar.Flash then castBar.Flash:Hide() end
        if castBar.Spark then castBar.Spark:Hide() end
        
        -- Add transparent black background behind the texture
        if not castBar._arenaCoreBackground then
            castBar._arenaCoreBackground = true
            
            local bg = castBar:CreateTexture(nil, "BACKGROUND")
            bg:SetAllPoints(castBar)
            bg:SetColorTexture(0, 0, 0, 0.5)  -- Semi-transparent black
            bg:Show()
            castBar._arenaCoreBgTexture = bg
        end
        
        -- Style cast bar text with ArenaCore font and move it UP
        if castBar.Text and not castBar._arenaCoreTextStyled then
            castBar._arenaCoreTextStyled = true
            
            -- Apply ArenaCore's global font
            if AC.SafeSetFont then
                AC.SafeSetFont(castBar.Text, AC.FONT_PATH, 10, "OUTLINE")
            else
                castBar.Text:SetFont("Fonts\\FRIZQT__.TTF", 10, "OUTLINE")
            end
            
            -- Move text DOWN (reposition from default center)
            castBar.Text:ClearAllPoints()
            castBar.Text:SetPoint("CENTER", castBar, "CENTER", 0, -1)  -- Move down by 1 pixel
            castBar.Text:SetTextColor(1, 1, 1)  -- White text
        end
        
        -- Add black borders to cast bar if not already present
        if not castBar._arenaCoreStyledBorders then
            castBar._arenaCoreStyledBorders = true
            
            -- Create border frame for cast bar
            local borderFrame = CreateFrame("Frame", nil, castBar)
            borderFrame:SetAllPoints()
            borderFrame:SetFrameLevel(castBar:GetFrameLevel() + 10)
            
            -- Top border
            local top = borderFrame:CreateTexture(nil, "OVERLAY")
            top:SetColorTexture(0, 0, 0, 1)
            top:SetPoint("TOPLEFT", 0, 0)
            top:SetPoint("TOPRIGHT", 0, 0)
            top:SetHeight(2)
            
            -- Bottom border
            local bottom = borderFrame:CreateTexture(nil, "OVERLAY")
            bottom:SetColorTexture(0, 0, 0, 1)
            bottom:SetPoint("BOTTOMLEFT", 0, 0)
            bottom:SetPoint("BOTTOMRIGHT", 0, 0)
            bottom:SetHeight(2)
            
            -- Left border
            local left = borderFrame:CreateTexture(nil, "OVERLAY")
            left:SetColorTexture(0, 0, 0, 1)
            left:SetPoint("TOPLEFT", 0, 0)
            left:SetPoint("BOTTOMLEFT", 0, 0)
            left:SetWidth(2)
            
            -- Right border
            local right = borderFrame:CreateTexture(nil, "OVERLAY")
            right:SetColorTexture(0, 0, 0, 1)
            right:SetPoint("TOPRIGHT", 0, 0)
            right:SetPoint("BOTTOMRIGHT", 0, 0)
            right:SetWidth(2)
            
            castBar._borderFrame = borderFrame
        end
        
        -- Add black borders to spell icon if not already present
        if castBar.Icon and not castBar.Icon._arenaCoreStyledBorders then
            castBar.Icon._arenaCoreStyledBorders = true
            
            -- Get icon's parent frame
            local iconParent = castBar.Icon:GetParent()
            
            -- Create border frame for spell icon
            local iconBorderFrame = CreateFrame("Frame", nil, iconParent)
            iconBorderFrame:SetAllPoints(castBar.Icon)
            iconBorderFrame:SetFrameLevel(castBar:GetFrameLevel() + 11)  -- Above cast bar borders
            
            -- Top border
            local iconTop = iconBorderFrame:CreateTexture(nil, "OVERLAY")
            iconTop:SetColorTexture(0, 0, 0, 1)
            iconTop:SetPoint("TOPLEFT", 0, 0)
            iconTop:SetPoint("TOPRIGHT", 0, 0)
            iconTop:SetHeight(2)
            
            -- Bottom border
            local iconBottom = iconBorderFrame:CreateTexture(nil, "OVERLAY")
            iconBottom:SetColorTexture(0, 0, 0, 1)
            iconBottom:SetPoint("BOTTOMLEFT", 0, 0)
            iconBottom:SetPoint("BOTTOMRIGHT", 0, 0)
            iconBottom:SetHeight(2)
            
            -- Left border
            local iconLeft = iconBorderFrame:CreateTexture(nil, "OVERLAY")
            iconLeft:SetColorTexture(0, 0, 0, 1)
            iconLeft:SetPoint("TOPLEFT", 0, 0)
            iconLeft:SetPoint("BOTTOMLEFT", 0, 0)
            iconLeft:SetWidth(2)
            
            -- Right border
            local iconRight = iconBorderFrame:CreateTexture(nil, "OVERLAY")
            iconRight:SetColorTexture(0, 0, 0, 1)
            iconRight:SetPoint("TOPRIGHT", 0, 0)
            iconRight:SetPoint("BOTTOMRIGHT", 0, 0)
            iconRight:SetWidth(2)
            
            castBar.Icon._borderFrame = iconBorderFrame
        end
    end
    
    -- CRITICAL FIX: Replace SetUnit entirely for ArenaCore Midnight cast bars
    -- This prevents Blizzard from registering arena units and causing secret value errors
    -- ArenaCore's custom event system (registered in ArenaCore.lua) handles cast bar updates instead
    if _G.CastingBarMixin then
        local originalSetUnit = _G.CastingBarMixin.SetUnit
        _G.CastingBarMixin.SetUnit = function(self, unit, showTradeSkills, showShield)
            -- For ArenaCore Midnight cast bars with arena units, block Blizzard's event registration
            if self._isMidnightBlizzardFrame and unit and string.match(unit, "^arena%d") then
                -- CRITICAL: Set unit to nil to prevent Blizzard from processing any events
                -- ArenaCore's event system will handle everything
                if self.unit ~= nil then
                    self.unit = nil
                    self.spellID = nil
                    self.showTradeSkills = false
                    self.showShield = false
                    self.casting = nil
                    self.channeling = nil
                    self.reverseChanneling = nil
                    self:StopAnims()
                    -- Unregister ALL events to be absolutely sure
                    self:UnregisterAllEvents()
                end
                -- Apply styling immediately
                CastBars:StyleMidnightCastBar(self)
                return
            end
            -- For all other cast bars, use Blizzard's original SetUnit
            return originalSetUnit(self, unit, showTradeSkills, showShield)
        end
    end
end

return CastBars
