local AC = _G.ArenaCore or {}

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

local AbsorbsMidnight = {}

local absorbStates = {}

-- Known absorb spell IDs for Midnight fallback detection
-- Since UnitGetTotalAbsorbs returns secret values in PvP, we scan auras for these known absorbs
local ABSORB_SPELLS = {
    -- Priest
    [17] = true,           -- Power Word: Shield
    [47585] = true,        -- Dispersion (damage reduction, counts as shield-like)
    -- Mage
    [11426] = true,        -- Ice Barrier
    [108271] = true,       -- Nether Ward (magic absorb)
    -- Warlock
    [108416] = true,       -- Dark Pact (health sacrifice absorb)
    [207299] = true,       -- Sacrificial Pact
    -- Monk
    [122470] = true,       -- Touch of Karma
    [116849] = true,       -- Life Cocoon
    -- Paladin
    [1022] = true,         -- Blessing of Protection (immunity, shows shield)
    [204018] = true,       -- Blessing of Spellwarding
    [642] = true,          -- Divine Shield (immunity, shows shield)
    -- Death Knight
    [48707] = true,        -- Anti-Magic Shell
    [48792] = true,        -- Icebound Fortitude (damage reduction)
    -- Warrior
    [202427] = true,       -- Ignore Pain
    -- Hunter
    [186265] = true,       -- Aspect of the Turtle (immunity)
    -- Shaman
    [108271] = true,       -- Astral Shift (damage reduction)
    -- Druid
    [22812] = true,        -- Barkskin (damage reduction)
    [61336] = true,        -- Survival Instincts
    -- Rogue
    [31224] = true,        -- Cloak of Shadows (immunity)
    -- Demon Hunter
    [187827] = true,       -- Metamorphosis (armor increase)
    [196555] = true,       -- Nether Bond (damage sharing)
    -- Evoker
    [363916] = true,       -- Prescience (not absorb but shows visual)
    [357170] = true,       -- Time Dilation (damage reduction)
}

local function GetSettings()
    local ac = GetAC()
    return ac.DB and ac.DB.profile and ac.DB.profile.moreGoodies and ac.DB.profile.moreGoodies.absorbs
end

function AbsorbsMidnight:GetTotalAbsorbs(unitToken)
    if not UnitExists(unitToken) then
        return 0
    end
    
    -- Use standard UnitGetTotalAbsorbs (still available in Midnight).
    local totalAbsorbs = UnitGetTotalAbsorbs(unitToken) or 0
    
    return totalAbsorbs
end

-- Scan unit's auras for known absorb spells (Midnight fallback)
function AbsorbsMidnight:HasKnownAbsorbAura(unitToken)
    if not UnitExists(unitToken) then
        return false
    end
    
    -- Scan HELPFUL auras for known absorb spell IDs
    for i = 1, 40 do
        local auraInfo = C_UnitAuras.GetAuraDataByIndex(unitToken, i, "HELPFUL")
        if auraInfo and auraInfo.spellId then
            -- spellId can be a secret value in PvP, need pcall for safe table lookup
            local isKnownAbsorb = false
            pcall(function()
                isKnownAbsorb = ABSORB_SPELLS[auraInfo.spellId] == true
            end)
            if isKnownAbsorb then
                return true
            end
        end
    end
    
    return false
end

function AbsorbsMidnight:ShowAbsorbLines(frameIndex)
    local settings = GetSettings()
    if not settings or not settings.enabled then
        return
    end
    
    local ac = GetAC()
    if not ac.FrameManager or not ac.FrameManager.frames then return end
    
    local frame = ac.FrameManager.frames[frameIndex]
    if not frame or not frame.healthBar then return end
    
    if not frame.liveAbsorbTexture then
        frame.liveAbsorbTexture = CreateFrame("Frame", nil, frame)
        frame.liveAbsorbTexture:SetAllPoints(frame.healthBar)
        frame.liveAbsorbTexture:SetFrameStrata("MEDIUM")
        frame.liveAbsorbTexture:SetFrameLevel(frame.healthBar:GetFrameLevel() + 1)
        
        local fillBar = frame.liveAbsorbTexture:CreateTexture(nil, "BACKGROUND")
        fillBar:SetAllPoints(frame.liveAbsorbTexture)
        fillBar:SetTexture("Interface\\RaidFrame\\Shield-Fill")
        fillBar:SetVertexColor(0.5, 0.8, 1, 0.7)
        fillBar:Show()
        frame.liveAbsorbTexture.fillBar = fillBar
        
        local overlay = frame.liveAbsorbTexture:CreateTexture(nil, "BORDER")
        overlay:SetAllPoints(frame.liveAbsorbTexture)
        overlay:SetTexture("Interface\\RaidFrame\\Shield-Overlay", true, true)
        overlay:SetVertexColor(1, 1, 1, 1)
        overlay:SetAlpha(1.0)
        overlay.tileSize = 32
        overlay:Show()
        frame.liveAbsorbTexture.overlay = overlay
        
        local glow = frame.liveAbsorbTexture:CreateTexture(nil, "BORDER")
        glow:SetTexture("Interface\\RaidFrame\\Shield-Overshield")
        glow:SetBlendMode("ADD")
        glow:SetWidth(16)
        glow:SetPoint("BOTTOMLEFT", frame.healthBar, "BOTTOMRIGHT", -7, 0)
        glow:SetPoint("TOPLEFT", frame.healthBar, "TOPRIGHT", -7, 0)
        glow:Hide()
        frame.liveAbsorbTexture.overGlow = glow
    end
    
    frame.liveAbsorbTexture:Show()
    if frame.liveAbsorbTexture.fillBar then frame.liveAbsorbTexture.fillBar:Show() end
    if frame.liveAbsorbTexture.overlay then frame.liveAbsorbTexture.overlay:Show() end
    
    local unit = "arena" .. frameIndex
    if UnitExists(unit) then
        local totalAbsorbs = self:GetTotalAbsorbs(unit)
        local maxHealth = UnitHealthMax(unit) or 1
        local currentHealth = UnitHealth(unit) or 0
        
        -- Safe comparison for secret values in Midnight
        local showGlow = false
        pcall(function()
            showGlow = totalAbsorbs > 0 and (currentHealth + totalAbsorbs >= maxHealth)
        end)
        if showGlow then
            if frame.liveAbsorbTexture.overGlow then
                frame.liveAbsorbTexture.overGlow:Show()
            end
        else
            if frame.liveAbsorbTexture.overGlow then
                frame.liveAbsorbTexture.overGlow:Hide()
            end
        end
    end
end

function AbsorbsMidnight:HideAbsorbLines(frameIndex)
    local ac = GetAC()
    if not ac.FrameManager or not ac.FrameManager.frames then return end
    
    local frame = ac.FrameManager.frames[frameIndex]
    if frame and frame.liveAbsorbTexture then
        frame.liveAbsorbTexture:Hide()
    end
end

function AbsorbsMidnight:CheckAbsorbsOnFrame(frameIndex)
    local settings = GetSettings()
    if not settings or not settings.enabled then
        self:HideAbsorbLines(frameIndex)
        return
    end
    
    local ac = GetAC()
    if not ac.FrameManager or not ac.FrameManager.frames then return end
    
    local frame = ac.FrameManager.frames[frameIndex]
    if not frame then return end
    
    local unit = "arena" .. frameIndex
    
    if UnitExists(unit) then
        local totalAbsorbs = self:GetTotalAbsorbs(unit)
        
        -- Hybrid detection for Midnight:
        -- 1. Try UnitGetTotalAbsorbs (works for friendly units, may be secret for arena enemies)
        -- 2. If secret value fallback, scan auras for known absorb spells
        local hasAbsorb = false
        local apiSucceeded = pcall(function()
            hasAbsorb = totalAbsorbs > 0
        end)
        
        -- If API failed (secret value) or returned 0, try aura scan fallback
        if not apiSucceeded or not hasAbsorb then
            hasAbsorb = self:HasKnownAbsorbAura(unit)
        end
        
        local hasImmunity = false
        if ac.ImmunityTracker and ac.ImmunityTracker.CheckImmunity then
            local immunityType = ac.ImmunityTracker:CheckImmunity(unit)
            hasImmunity = (immunityType ~= nil)
        end
        
        local shouldShowLines = hasAbsorb or hasImmunity
        
        if absorbStates[frameIndex] ~= shouldShowLines then
            absorbStates[frameIndex] = shouldShowLines
            
            if shouldShowLines then
                self:ShowAbsorbLines(frameIndex)
            else
                self:HideAbsorbLines(frameIndex)
            end
        end
    else
        if absorbStates[frameIndex] ~= false then
            absorbStates[frameIndex] = false
            self:HideAbsorbLines(frameIndex)
        end
    end
end

function AbsorbsMidnight:UpdateAllAbsorbs()
    for i = 1, 3 do
        self:CheckAbsorbsOnFrame(i)
    end
end

function AbsorbsMidnight:Initialize()
    if self.initialized then return true end
    
    -- Check if UnitGetTotalAbsorbs is available.
    if not UnitGetTotalAbsorbs then
        print("|cffFF0000[Absorbs Midnight]|r UnitGetTotalAbsorbs API not available")
        return false
    end
    
    if not self.eventFrame then
        self.eventFrame = CreateFrame("Frame")
        
        self.eventFrame:RegisterEvent("UNIT_HEALTH")
        self.eventFrame:RegisterEvent("UNIT_MAXHEALTH")
        self.eventFrame:RegisterEvent("UNIT_AURA")
        self.eventFrame:RegisterEvent("UNIT_ABSORB_AMOUNT_CHANGED")
        self.eventFrame:RegisterEvent("ARENA_OPPONENT_UPDATE")
        self.eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
        
        self.eventFrame:SetScript("OnEvent", function(_, event, ...)
            if event == "UNIT_HEALTH" or event == "UNIT_MAXHEALTH" or event == "UNIT_AURA" or event == "UNIT_ABSORB_AMOUNT_CHANGED" then
                local unit = ...
                if unit and unit:match("^arena%d$") then
                    local frameIndex = tonumber(unit:match("arena(%d)"))
                    if frameIndex then
                        AbsorbsMidnight:CheckAbsorbsOnFrame(frameIndex)
                    end
                end
            elseif event == "ARENA_OPPONENT_UPDATE" or event == "PLAYER_ENTERING_WORLD" then
                C_Timer.After(0.5, function()
                    AbsorbsMidnight:UpdateAllAbsorbs()
                end)
            end
        end)
    end
    
    if not self.ticker then
        self.ticker = C_Timer.NewTicker(0.5, function()
            local _, instanceType = IsInInstance()
            if instanceType == "arena" then
                AbsorbsMidnight:UpdateAllAbsorbs()
            end
        end)
    end
    
    self.initialized = true
    return true
end

function AbsorbsMidnight:Cleanup()
    absorbStates = {}
end

AC.AbsorbsMidnight = AbsorbsMidnight

local function TryInitialize()
    local ac = GetAC()
    
    if not ac.Midnight or not ac.Midnight.isMidnight then
        return
    end
    
    if AbsorbsMidnight:Initialize() then
    else
        print("|cff8B45FFArena|r|cffB266FFCore|r |cffFF0000Midnight absorbs tracking failed to initialize|r")
    end
end

C_Timer.After(1, TryInitialize)

if AC.Midnight and AC.Midnight.isMidnight then
    TryInitialize()
end

return AbsorbsMidnight
