---@class Deque
---@field private first integer
---@field private last integer
---@field private _data table<integer, any>
local Deque = {}
Deque.__index = Deque

---Создать пустую очередь
---@return Deque
local function new()
    ---@type Deque
    local self = setmetatable({
        first = 1,
        last = 0,
        _data = {},
    }, Deque)
    return self
end

---Количество элементов
---@return integer
function Deque:size()
    return self.last - self.first + 1
end

---Пуста ли очередь
---@return boolean
function Deque:is_empty()
    return self.first > self.last
end

---Добавить в начало
---@param value any
---@return Deque self
function Deque:push_front(value)
    self.first = self.first - 1
    self._data[self.first] = value
    return self
end

---Добавить в конец
---@param value any
---@return Deque self
function Deque:push_back(value)
    self.last = self.last + 1
    self._data[self.last] = value
    return self
end

---Забрать из начала
---@return any
function Deque:pop_front()
    if self.first > self.last then return nil end
    local value = self._data[self.first]
    self._data[self.first] = nil
    self.first = self.first + 1
    return value
end

---Забрать из конца
---@return any
function Deque:pop_back()
    if self.first > self.last then return nil end
    local value = self._data[self.last]
    self._data[self.last] = nil
    self.last = self.last - 1
    return value
end

---Подсмотреть начало
---@return any
function Deque:peek_front()
    if self.first > self.last then return nil end
    return self._data[self.first]
end

---Подсмотреть конец
---@generic T
---@return T|nil
function Deque:peek_back()
    if self.first > self.last then return nil end
    return self._data[self.last]
end

---Очистить очередь
function Deque:clear()
    -- Полная очистка таблицы для GC
    for i = self.first, self.last do
        self._data[i] = nil
    end
    self.first, self.last = 1, 0
end

---Итератор по значениям слева направо
---@return fun():any
function Deque:values()
    local i = self.first
    return function()
        if i <= self.last then
            local v = self._data[i]
            i = i + 1
            return v
        end
    end
end

---Преобразовать в массив
---@return any[]
function Deque:to_array()
    local n = self:size()
    local arr = {}
    if n <= 0 then return arr end
    local j = 1
    for i = self.first, self.last do
        arr[j] = self._data[i]
        j = j + 1
    end
    return arr
end

return { new = new }
