-- =============================================================
-- Specs/EvokerPreservation.lua
-- Nem: Healer Alerts — Preservation Evoker spec module
--
-- FULLY SELF-CONTAINED. Zero dependencies on other spec modules.
--
-- Alerts:
--   1. Echo target glow        (364343) — glow Echo icon on frames
--   2. Reversion low coverage   (366155) — count-based text alert
--   3. Echo+Reversion synergy   (367364) — glow Echo Reversion icon
--
-- Whitelisted spell IDs (non-secret in Midnight):
--   355941 - Dream Breath
--   363502 - Dream Flight
--   364343 - Echo
--   366155 - Reversion
--   367364 - Echo Reversion
--   373267 - Lifebind
--   376788 - Echo Dream Breath
-- =============================================================

local NHA = _G.NemHealerAlerts
if not NHA then return end

local pairs, ipairs       = pairs, ipairs
local GetTime             = GetTime
local UnitExists          = UnitExists
local C_UnitAuras         = C_UnitAuras
local issecretvalue       = NHA.issecretvalue

-- =============================================================
-- Spell IDs
-- =============================================================
local ECHO_ID              = 364343
local REVERSION_ID         = 366155
local ECHO_REVERSION_ID    = 367364
local DREAM_BREATH_ID      = 355941
local ECHO_DREAM_BREATH_ID = 376788
local LIFEBIND_ID          = 373267

-- All Reversion-family IDs for counting
local REVERSION_IDS = {
    [366155] = true,  -- Reversion
    [367364] = true,  -- Echo Reversion
}

-- =============================================================
-- State
-- =============================================================
local state = {
    -- Reversion low coverage
    revActive       = false,
    revWasActive    = false,
    -- Echo glow (no text alert, glow only)
    echoActive      = false,
    -- Synergy glow (no text alert, glow only)
    synergyActive   = false,
    -- Debounce
    playerAuraPending   = false,
    rosterUpdatePending = false,
}

-- Glow frame tables
local echoGlowFrames         = {}  -- buffFrame → true
local echoReversionGlowFrames = {}  -- buffFrame → true

-- =============================================================
-- Alert Definitions
-- =============================================================
local ALERTS = {
    {
        key          = "rev",
        label        = "Reversion Low",
        text         = "* REVERSION LOW *",
        defaultColor = { r = 0.200, g = 0.576, b = 0.498 },  -- Evoker class color
        hasTimer     = false,
        yOffset      = -30,
        defaultSound = "Ping",
    },
}

-- =============================================================
-- Defaults
-- =============================================================
local DEFAULTS = {
    revEnabled           = true,
    revSoundEnabled      = true,
    revSoundName         = "Ping",
    echoGlowEnabled      = true,
    echoRevGlowEnabled   = true,
    revThresholdDungeon  = 2,
    revThresholdRaid     = 4,
    alertColors          = {
        rev  = { r = 0.200, g = 0.576, b = 0.498 },
    },
}

-- =============================================================
-- Reversion Count Scan
-- =============================================================
local function CountActiveReversions()
    local count = 0
    for _, unit in ipairs(NHA:GetGroupUnits()) do
        if UnitExists(unit) and C_UnitAuras and C_UnitAuras.GetAuraDataBySpellID then
            for spellId in pairs(REVERSION_IDS) do
                local aura = C_UnitAuras.GetAuraDataBySpellID(unit, spellId, "HELPFUL")
                if aura and aura.auraInstanceID ~= 0
                   and aura.sourceUnit == "player" then
                    count = count + 1
                end
            end
        end
    end
    return count
end

local function GetReversionThreshold()
    local db = NHA.db
    if IsInRaid and IsInRaid() then
        return db.revThresholdRaid or 4
    end
    return db.revThresholdDungeon or 2
end

-- =============================================================
-- Module Table
-- =============================================================
local EvokerPres = {
    class     = "EVOKER",
    specIndex = 2,  -- Preservation is spec index 2
    specName  = "Preservation",
    alerts    = ALERTS,
    defaults  = DEFAULTS,
    state     = state,

    extraEvents = {
        "UNIT_AURA",
    },
}

-- =============================================================
-- ClearAllGlows
-- =============================================================
function EvokerPres:ClearAllGlows()
    for buffFrame in pairs(echoGlowFrames) do
        NHA:HideProcGlow(buffFrame)
    end
    wipe(echoGlowFrames)
    for buffFrame in pairs(echoReversionGlowFrames) do
        NHA:HideProcGlow(buffFrame)
    end
    wipe(echoReversionGlowFrames)
end

-- =============================================================
-- ClearAllState
-- =============================================================
function EvokerPres:ClearAllState()
    state.revActive     = false
    state.revWasActive  = false
    state.echoActive    = false
    state.synergyActive = false
    self:ClearAllGlows()
end

-- =============================================================
-- NeedsTicker
-- =============================================================
function EvokerPres:NeedsTicker(db)
    return db.echoGlowEnabled or db.echoRevGlowEnabled
end

-- =============================================================
-- RefreshGlows
-- =============================================================
function EvokerPres:RefreshGlows(db)
    -- Echo and Echo Reversion glows are static (always on while buff exists)
    -- No pandemic-window refresh needed
end

-- =============================================================
-- EvaluateFrameGlow
-- =============================================================
function EvokerPres:EvaluateFrameGlow(db, buffFrame, aura)
    if not db or not db.glowEnabled or not db.enabled then
        NHA:HideProcGlow(buffFrame)
        echoGlowFrames[buffFrame]          = nil
        echoReversionGlowFrames[buffFrame] = nil
        return
    end

    local tracked = echoGlowFrames[buffFrame] or echoReversionGlowFrames[buffFrame]

    if not aura then
        if tracked then
            NHA:HideProcGlow(buffFrame)
            echoGlowFrames[buffFrame]          = nil
            echoReversionGlowFrames[buffFrame] = nil
        end
        return
    end

    if issecretvalue(aura.spellId) then
        if tracked then
            NHA:HideProcGlow(buffFrame)
            echoGlowFrames[buffFrame]          = nil
            echoReversionGlowFrames[buffFrame] = nil
        end
        return
    end

    if aura.sourceUnit ~= "player" then
        if tracked then
            NHA:HideProcGlow(buffFrame)
            echoGlowFrames[buffFrame]          = nil
            echoReversionGlowFrames[buffFrame] = nil
        end
        return
    end

    -- Echo glow
    if aura.spellId == ECHO_ID and db.echoGlowEnabled then
        echoGlowFrames[buffFrame] = true
        local c = db.alertColors and db.alertColors.rev
                  or { r=0.200, g=0.576, b=0.498 }
        NHA:ShowProcGlow(buffFrame, c.r, c.g, c.b)
        return
    end

    -- Echo Reversion synergy glow
    if aura.spellId == ECHO_REVERSION_ID and db.echoRevGlowEnabled then
        echoReversionGlowFrames[buffFrame] = true
        local c = db.alertColors and db.alertColors.rev
                  or { r=0.200, g=0.576, b=0.498 }
        NHA:ShowProcGlow(buffFrame, c.r, c.g, c.b)
        return
    end

    -- Not a spell we track
    if tracked then
        NHA:HideProcGlow(buffFrame)
        echoGlowFrames[buffFrame]          = nil
        echoReversionGlowFrames[buffFrame] = nil
    end
end

-- =============================================================
-- Evaluate
-- =============================================================
function EvokerPres:Evaluate(db)
    -- Reversion low coverage
    local revLow = false
    if db.revEnabled and UnitAffectingCombat("player") then
        local count     = CountActiveReversions()
        local threshold = GetReversionThreshold()
        revLow = count < threshold
    end
    state.revActive = revLow

    -- Rising-edge sound
    if revLow and not state.revWasActive then NHA:PlayAlertSound("rev") end
    state.revWasActive = revLow
end

-- =============================================================
-- OnActivate
-- =============================================================
function EvokerPres:OnActivate(db)
    -- Nothing spec-specific needed at login
end

-- =============================================================
-- OnEvent
-- =============================================================
function EvokerPres:OnEvent(db, event, ...)
    if event == "UNIT_AURA" then
        local unit = ...
        if unit == "player" then
            if not state.playerAuraPending then
                state.playerAuraPending = true
                C_Timer.After(0.1, function()
                    state.playerAuraPending = false
                    NHA.Evaluate()
                end)
            end
            return true
        end
        return false
    end

    if event == "GROUP_ROSTER_UPDATE" then
        if not state.rosterUpdatePending then
            state.rosterUpdatePending = true
            C_Timer.After(0.5, function()
                state.rosterUpdatePending = false
                NHA.Evaluate()
            end)
        end
        return true
    end

    return false
end

-- =============================================================
-- BuildOptions
-- =============================================================
function EvokerPres:BuildOptions(parent, db, helpers)
    helpers.MakeCheckbox("Echo Icon Glow", 230, -90,
        function() return db.echoGlowEnabled end,
        function(v) db.echoGlowEnabled = v and true or false end)

    helpers.MakeCheckbox("Echo Reversion Glow", 230, -114,
        function() return db.echoRevGlowEnabled end,
        function(v) db.echoRevGlowEnabled = v and true or false end)
end

-- =============================================================
-- Register
-- =============================================================
NHA:RegisterSpec("EVOKER_PRES", EvokerPres)
