-- Serializes startup dialogs so Mud System notices never overlap each other.

MudSystemDialogQueue = {}
MudSystemDialogQueue.initialDelayMs = 3000
MudSystemDialogQueue.retryDelayMs = 250
MudSystemDialogQueue._queue = {}
MudSystemDialogQueue._queuedIds = {}
MudSystemDialogQueue._active = false
MudSystemDialogQueue._sequence = 0

function MudSystemDialogQueue:loadMap()
    self._queue = {}
    self._queuedIds = {}
    self._active = false
    self._sequence = 0
    self._delay = self.initialDelayMs or 3000
end

function MudSystemDialogQueue:deleteMap()
    self._queue = {}
    self._queuedIds = {}
    self._active = false
end

function MudSystemDialogQueue:isClient()
    local mission = g_currentMission
    if mission ~= nil and mission.getIsClient ~= nil then
        return mission:getIsClient()
    end

    return g_gui ~= nil
end

function MudSystemDialogQueue:enqueue(id, priority, showFunction)
    if id == nil or type(showFunction) ~= "function" then
        return false
    end

    if self._queuedIds[id] == true then
        return false
    end

    self._sequence = (self._sequence or 0) + 1
    self._queuedIds[id] = true
    self._queue[#self._queue + 1] = {
        id = id,
        priority = tonumber(priority) or 0,
        sequence = self._sequence,
        showFunction = showFunction
    }

    table.sort(self._queue, function(a, b)
        if a.priority == b.priority then
            return a.sequence < b.sequence
        end
        return a.priority > b.priority
    end)

    return true
end

function MudSystemDialogQueue:complete(id)
    if id ~= nil then
        self._queuedIds[id] = nil
    end
    self._active = false
    self._delay = self.retryDelayMs or 250
end

function MudSystemDialogQueue:update(dt)
    if not self:isClient() or g_gui == nil then
        return
    end

    self._delay = (self._delay or 0) - (dt or 0)
    if self._delay > 0 or self._active == true or #self._queue == 0 then
        return
    end

    if g_gui.getIsDialogVisible ~= nil and g_gui:getIsDialogVisible() then
        self._delay = self.retryDelayMs or 250
        return
    end

    local entry = table.remove(self._queue, 1)
    if entry == nil then
        return
    end

    self._active = true
    local completed = false
    local function onComplete()
        if completed then
            return
        end
        completed = true
        MudSystemDialogQueue:complete(entry.id)
    end

    local ok, shown = pcall(entry.showFunction, onComplete)
    if not ok then
        Logging.warning(
            "[MudSystemPhysics] Startup dialog '%s' failed: %s",
            tostring(entry.id),
            tostring(shown)
        )
        onComplete()
    elseif shown == false then
        onComplete()
    end
end

addModEventListener(MudSystemDialogQueue)
