-- ERT/Core/Alerts.lua
-- Alerts when a rare you still need is confirmed up. The actionable moment is
-- "it's up RIGHT NOW" (a vignette / line-of-sight confirmation), not a mere
-- prediction — predictions would cry wolf. We fire at most once per spawn, and
-- by default only for rares with something uncollected (collection-gated), so
-- the alert means "drop what you're doing, it's up and you need it".

local ADDON_NAME, NS = ...
local ETB = NS.ETB
local ERT = ETB.ERT

-- Settings live in the saved DB so they persist. Defaults are conservative:
-- alerts on, needed-only on, sound on.
local function Settings()
    ETB_RareDB = ETB_RareDB or {}
    local s = ETB_RareDB.alerts
    if not s then
        s = { enabled = true, neededOnly = true, sound = true }
        ETB_RareDB.alerts = s
    end
    return s
end
ERT.AlertSettings = Settings

-- Remember the spawn we last alerted for, per npc, so a lingering "up" state
-- doesn't re-alert every tick — only a genuinely new spawn does.
local alertedSpawn = {}

local function Announce(name, st, needs)
    local s = Settings()
    local bits = {}
    if needs then
        if needs.nMounts and needs.nMounts > 0 then bits[#bits + 1] = needs.nMounts .. " mount" .. (needs.nMounts > 1 and "s" or "") end
        if needs.nPets and needs.nPets > 0 then bits[#bits + 1] = needs.nPets .. " pet" .. (needs.nPets > 1 and "s" or "") end
    end
    local what = (#bits > 0) and (" — need " .. table.concat(bits, ", ")) or ""
    local msg = "|cffEEE4AE[ETB Rare]|r |cff40ff40" .. (name or "A rare") .. " is UP NOW|r" .. what
    if DEFAULT_CHAT_FRAME then DEFAULT_CHAT_FRAME:AddMessage(msg) end
    if s.sound and PlaySound then
        -- 8959 = RaidWarning; widely available. Guarded in case the constant set differs.
        pcall(PlaySound, 8959, "Master")
    end
    if RaidNotice_AddMessage and RaidWarningFrame and ChatTypeInfo then
        pcall(RaidNotice_AddMessage, RaidWarningFrame, (name or "Rare") .. " is up!", ChatTypeInfo["RAID_WARNING"])
    end
end

-- Scan tracked rares; alert for any that are confirmed up, pass the needed-only
-- filter, and we haven't already announced for this spawn.
function ERT:CheckAlerts()
    local s = Settings()
    if not s.enabled then return end
    for _, npcID in ipairs(self:GetTrackedNPCs()) do
        local st = self:GetStatus(npcID)
        if st and st.state == "alive" and st.confirmed then
            local needs = self:NeedsRare(npcID)
            if (not s.neededOnly) or needs.any then
                local key = st.spawnTime or st.lastDeath or 0
                if alertedSpawn[npcID] ~= key then
                    alertedSpawn[npcID] = key
                    Announce(self:GetName(npcID), st, needs)
                end
            end
        end
    end
end

-- Event-driven, zero-idle-cost alert dispatch.
--
-- An alert means "a rare you need is confirmed UP right now". That confirmed
-- state is only ever set by a game event (a vignette or a line-of-sight
-- sighting) — never by the passage of time alone — so we never need a
-- wall-clock poll to RAISE an alert. Instead we listen for the Observer's
-- ETB_RARE_STATUS_CHANGED signal and run a single debounced check.
--
-- The debounce frame ticks ONLY during the brief settle window after a status
-- change, then detaches itself. When nothing is happening, no OnUpdate is alive
-- at all — unlike the old frame that ran every tick forever.
local DEBOUNCE = 0.5
local debounce = CreateFrame("Frame")
debounce:Hide()   -- hidden frames receive no OnUpdate; we only show it on demand
local dacc = 0
debounce:SetScript("OnUpdate", function(self, elapsed)
    dacc = dacc + (elapsed or 0)
    if dacc < DEBOUNCE then return end
    dacc = 0
    self:Hide()                       -- detach: stop ticking until the next change
    if ERT.CheckAlerts then ERT:CheckAlerts() end
end)

-- Coalesce a burst of status changes into one check after the settle window.
local function RequestAlertCheck()
    if not Settings().enabled then return end
    dacc = 0
    debounce:Show()
end
ERT.RequestAlertCheck = RequestAlertCheck

if ETB.EventBus and ETB.EventBus.Register then
    ETB.EventBus:Register("ETB_RARE_STATUS_CHANGED", function() RequestAlertCheck() end)
end
ERT._AlertDriver = debounce
