local _, ns = ...

local addonFrame = ns.frame

local LIVE_REFRESH_KEYS = {
    "utility",
    "vault",
    "prey",
    "dailyPve",
    "midnightRares",
    "delves",
    "worldWeekly",
    "darkmoonFaire",
    "pvpWeekly",
    "professionWeekly",
    "professionKnowledge",
    "professionCooldowns",
    "renownForce",
}

local LIVE_REFRESH_ALL = {}
for _, key in ipairs(LIVE_REFRESH_KEYS) do
    LIVE_REFRESH_ALL[key] = true
end

local liveRefreshPending = false
local pendingLiveRefreshSpec = nil
local liveOnlyRefreshEventsRegistered = false
local liveRefreshGeneration = 0
local LIVE_ONLY_REFRESH_EVENTS = {
    "MYTHIC_PLUS_CURRENT_AFFIX_UPDATE",
    "PLAYER_HOUSE_LIST_UPDATED",
    "HOUSE_LEVEL_FAVOR_UPDATED",
    "HOUSE_LEVEL_CHANGED",
}

local function cloneLiveRefreshSpec(spec)
    local copy = {}
    for key, value in pairs(spec or {}) do
        if value == true and LIVE_REFRESH_ALL[key] then
            copy[key] = true
        end
    end
    return copy
end

local function normalizeLiveRefreshSpec(spec)
    if type(spec) ~= "table" then
        return cloneLiveRefreshSpec(LIVE_REFRESH_ALL)
    end

    local normalized = cloneLiveRefreshSpec(spec)
    if next(normalized) == nil then
        return cloneLiveRefreshSpec(LIVE_REFRESH_ALL)
    end

    return normalized
end

local function mergeLiveRefreshSpec(target, source)
    local merged = cloneLiveRefreshSpec(target)
    for key in pairs(normalizeLiveRefreshSpec(source)) do
        merged[key] = true
    end
    return merged
end

local function buildLiveRefreshSpec(...)
    local spec = {}
    for index = 1, select("#", ...) do
        local key = select(index, ...)
        if LIVE_REFRESH_ALL[key] then
            spec[key] = true
        end
    end
    return normalizeLiveRefreshSpec(spec)
end

function ns:BuildLiveRefreshSpec(...)
    return buildLiveRefreshSpec(...)
end

local function isVaultloomUIShown()
    return ns and ns.UI and ns.UI.frame and ns.UI.frame:IsShown()
end

local function isChronicleViewShown()
    return isVaultloomUIShown()
        and ns.GetSelectedMainTab
        and ns:GetSelectedMainTab() == "chronicle"
end

function ns:SetLiveRefreshEventsEnabled(enabled)
    local shouldEnable = enabled == true
    if liveOnlyRefreshEventsRegistered == shouldEnable then
        return
    end

    liveOnlyRefreshEventsRegistered = shouldEnable
    for _, eventName in ipairs(LIVE_ONLY_REFRESH_EVENTS) do
        if shouldEnable then
            addonFrame:RegisterEvent(eventName)
        else
            addonFrame:UnregisterEvent(eventName)
        end
    end
end

local function scheduleLiveDataRefresh(delaySeconds, refreshSpec)
    pendingLiveRefreshSpec = mergeLiveRefreshSpec(pendingLiveRefreshSpec, refreshSpec)

    if liveRefreshPending then
        return
    end

    local effectiveDelay = tonumber(delaySeconds) or 0.25
    if not isVaultloomUIShown() then
        effectiveDelay = math.max(effectiveDelay, 0.75)
    end

    liveRefreshPending = true
    local scheduledGeneration = liveRefreshGeneration
    C_Timer.After(effectiveDelay, function()
        if scheduledGeneration ~= liveRefreshGeneration then
            return
        end

        liveRefreshPending = false
        local scheduledSpec = pendingLiveRefreshSpec
        pendingLiveRefreshSpec = nil
        if ns and ns.RefreshCurrentCharacterLiveData then
            ns:RefreshCurrentCharacterLiveData(scheduledSpec)
        end
    end)
end

function ns:ScheduleLiveDataRefresh(delaySeconds, refreshSpec)
    scheduleLiveDataRefresh(delaySeconds, refreshSpec)
end

function ns:DiscardDeferredLiveRefresh()
    pendingLiveRefreshSpec = nil
    liveRefreshPending = false
    liveRefreshGeneration = liveRefreshGeneration + 1
end

function ns:FlushDeferredLiveRefresh(suppressUIRefresh)
    if not pendingLiveRefreshSpec then
        return false
    end

    local scheduledSpec = pendingLiveRefreshSpec
    pendingLiveRefreshSpec = nil
    liveRefreshPending = false
    liveRefreshGeneration = liveRefreshGeneration + 1
    if self.RefreshCurrentCharacterLiveData then
        self:RefreshCurrentCharacterLiveData(scheduledSpec, suppressUIRefresh)
    end
    return true
end

function ns:RefreshCurrentCharacterLiveData(refreshSpec, suppressUIRefresh)
    if type(refreshSpec) ~= "table" and liveRefreshPending then
        pendingLiveRefreshSpec = nil
        liveRefreshPending = false
        liveRefreshGeneration = liveRefreshGeneration + 1
    end

    local spec = normalizeLiveRefreshSpec(refreshSpec)

    if spec.utility then
        self:RefreshCurrentCharacterUtilityData()
    end
    if spec.vault then
        self:RefreshCurrentCharacterVaultData()
    end
    if spec.prey then
        self:RefreshCurrentCharacterPreyData()
    end
    if spec.dailyPve then
        self:RefreshCurrentCharacterDailyPveData()
    end
    if spec.midnightRares and self.RefreshCurrentCharacterMidnightRareData then
        self:RefreshCurrentCharacterMidnightRareData()
    end
    if spec.delves then
        self:RefreshCurrentCharacterDelvesData()
    end
    if spec.worldWeekly then
        self:RefreshCurrentCharacterWorldWeeklyData()
    end
    if spec.darkmoonFaire and self.RefreshCurrentCharacterDarkmoonFaireData then
        self:RefreshCurrentCharacterDarkmoonFaireData()
    end
    if spec.pvpWeekly then
        self:RefreshCurrentCharacterPvpWeeklyData()
    end
    if spec.professionWeekly then
        self:RefreshCurrentCharacterProfessionWeeklyData()
    end
    if spec.professionKnowledge then
        self:RefreshCurrentCharacterProfessionKnowledgeData()
    end
    if spec.professionCooldowns and self.RefreshCurrentCharacterProfessionCooldownData then
        self:RefreshCurrentCharacterProfessionCooldownData()
    end

    if (spec.renownForce == true or isChronicleViewShown())
        and self.ScanRenownProgress
        and self.GetCurrentCharacterInfo
        and (not self.IsRenownSystemEnabled or self:IsRenownSystemEnabled())
    then
        self:ScanRenownProgress(self:GetCurrentCharacterInfo(), nil, {
            source = "live",
            force = spec.renownForce == true,
        })
    end

    local uiRefreshed = false
    if not suppressUIRefresh and self.UI and self.UI.frame and self.UI.frame:IsShown() and self.UI.Refresh then
        self.UI:Refresh()
        uiRefreshed = true
    end
    if not suppressUIRefresh and not uiRefreshed and self.UI and self.UI.RefreshCustomTaskTracker then
        self.UI:RefreshCustomTaskTracker()
    end
end
