-- lx-bundle:true

local config = require("core.config")

local undo = {}

-- Pushes an undo command entry and advances stack index with pruning
function undo.push_undo(undo_stack, time, type, ...)
	undo_stack[undo_stack.idx] = { type = type, time = time, ... }
	undo_stack[undo_stack.idx - config.max_undos] = nil
	undo_stack.idx = undo_stack.idx + 1
end

-- Pops and applies one merged undo/redo command sequence
function undo.pop_undo(self, undo_stack, redo_stack)
	while true do
		local cmd = undo_stack[undo_stack.idx - 1]
		if not cmd then
			return
		end
		undo_stack.idx = undo_stack.idx - 1

		-- Delegate replay so base undo stays generic
		if self:apply_undo_entry(cmd, redo_stack) == false then
			return false
		end

		-- Keep adjacent entries inside one merge window in the same undo step
		local next = undo_stack[undo_stack.idx - 1]
		if not next or math.abs(cmd.time - next.time) >= config.undo_merge_timeout then
			return
		end
	end
end

-- Performs one undo step from the undo stack
function undo.undo(self)
	undo.pop_undo(self, self.undo_stack, self.redo_stack)
end

-- Performs one redo step from the redo stack
function undo.redo(self)
	undo.pop_undo(self, self.redo_stack, self.undo_stack)
end

return undo
