---@class AddonPrivate
local Private = select(2, ...)

---@class Events
local events = {}
Private.Events = events

function events:InitEvents()
    local addon = Private.Addon
    addon:RegisterEvent("PLAYER_ENTERING_WORLD", function ()
        self:RequestQuestLines()
        self:AutoContinent()
        self:UpdateData()
    end)
    addon:RegisterEvent("ACHIEVEMENT_EARNED", function ()
        self:UpdateData()
    end)
    addon:RegisterEvent("CRITERIA_UPDATE", function ()
        self:UpdateData()
    end)
    -- Refresh the objective HUDs when the player changes zone/subzone.
    addon:RegisterEvent("ZONE_CHANGED_NEW_AREA", function ()
        self:RequestQuestLines()
        self:AutoContinent()
        self:RefreshHuds()
    end)
    addon:RegisterEvent("ZONE_CHANGED", function ()
        self:RefreshHuds()
    end)
    -- Questline data loads asynchronously; refresh the planner when it arrives so
    -- the Storylines & Quests section can populate.
    addon:RegisterEvent("QUESTLINE_UPDATE", function ()
        if Private.Objectives then Private.Objectives:InvalidateQuests() end
        self:RefreshHuds()
    end)
    -- Quest log changes affect the "continue this quest" list.
    addon:RegisterEvent("QUEST_ACCEPTED", function () self:QuestsChanged() end)
    addon:RegisterEvent("QUEST_TURNED_IN", function () self:QuestsChanged() end)
    addon:RegisterEvent("QUEST_REMOVED", function () self:QuestsChanged() end)
end

-- Requesting questlines fans out to every zone on the continent, and each reply
-- fires QUESTLINE_UPDATE -- so spamming this (e.g. on every quest event when entering
-- a World Quest area) causes an event storm. Rate-limit: questline AVAILABILITY does
-- not change second-to-second, so at most once per 8s is plenty.
function events:RequestQuestLines()
    local now = GetTime()
    if self._lastQLRequest and (now - self._lastQLRequest) < 8 then return end
    self._lastQLRequest = now
    if Private.Objectives and Private.Objectives.RequestQuestLines then
        Private.Objectives:RequestQuestLines()
    end
end

function events:QuestsChanged()
    if Private.Objectives then Private.Objectives:InvalidateQuests() end
    -- re-request questline data so a completed step rolls to the next quest to pick up
    self:RequestQuestLines()
    self:RefreshHuds()
end

-- Auto open/close the planner + Rare Scanner when the CONTINENT changes (only when the
-- setting is on). Only acts on a real continent transition, so within a meta continent
-- the player's own show/hide choices still stick. Meta continent -> show; a continent
-- with nothing tracked at all -> hide.
function events:AutoContinent()
    local db = Private.Settings and Private.Settings.db
    if not db or not db.autoContinent or not Private.Objectives then return end
    local mapID = C_Map.GetBestMapForUnit and C_Map.GetBestMapForUnit("player")
    local cont = mapID and Private.Objectives:GetContinentID(mapID)
    if not cont or cont == self.lastContinent then return end
    self.lastContinent = cont
    local hasMeta = Private.Objectives:IsMetaContinent(mapID)
    if Private.RouteHud then Private.RouteHud:SetEnabled(hasMeta) end
    if Private.RareAlerts then Private.RareAlerts:SetEnabled(hasMeta) end
end

-- Coalesce bursts of events into ONE refresh. Entering a World Quest area fires a
-- rapid burst of QUESTLINE_UPDATE/quest events (one per zone we requested); refreshing
-- on each would run many continent-wide scans back-to-back -- a multi-second freeze
-- and a spike of throwaway tables. Debounce to a single refresh just after the burst.
function events:RefreshHuds()
    if self._refreshTimer then return end
    self._refreshTimer = C_Timer.NewTimer(0.2, function()
        events._refreshTimer = nil
        if Private.NearbyHud then Private.NearbyHud:Refresh() end
        if Private.RouteHud then Private.RouteHud:Refresh() end
    end)
end

function events:UpdateData()
    Private.UI:QueueUpdate()
    if Private.Objectives then
        Private.Objectives:InvalidateSummaries()
        Private.Objectives:InvalidateInstances()
        Private.Objectives:InvalidateQuests()
    end
    self:RefreshHuds()
end