<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Event\Queue\Drivers;

use PpPhp\Core\Platform\Event\Queue\Contracts\QueueDriverInterface;
use PpPhp\Core\Platform\Event\Queue\DeferredEvent;
use PpPhp\Core\Platform\Event\Queue\QueueHydrator;
use PpPhp\Core\Platform\Event\Queue\QueueSnapshot;
use PpPhp\Core\Platform\Event\Queue\QueueStatistics;

final class MemoryQueueDriver implements QueueDriverInterface
{
    private array $events = [];

    public function name(): string { return 'memory'; }

    public function push(DeferredEvent $event): string
    {
        $this->events[$event->id()] = $event;
        return $event->id();
    }

    public function pop(): ?DeferredEvent
    {
        if ($this->events === []) {
            return null;
        }

        $event = array_values($this->events)[0];
        unset($this->events[$event->id()]);
        return $event;
    }

    public function peek(): ?DeferredEvent
    {
        return array_values($this->events)[0] ?? null;
    }

    public function cancel(string $id): bool
    {
        if (!isset($this->events[$id])) {
            return false;
        }

        unset($this->events[$id]);
        return true;
    }

    public function clear(): void { $this->events = []; }
    public function all(): array { return array_values($this->events); }

    public function restore(QueueSnapshot $snapshot): void
    {
        $this->events = [];
        foreach ((new QueueHydrator())->hydrateEvents($snapshot->events()) as $event) {
            $this->events[$event->id()] = $event;
        }
    }

    public function size(): int { return count($this->events); }

    public function statistics(): QueueStatistics
    {
        return new QueueStatistics($this->name(), $this->size(), $this->size());
    }
}
