<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Event\Queue;

use PpPhp\Core\Platform\Event\EventBus;
use PpPhp\Core\Platform\Event\Contracts\EventInterface;
use PpPhp\Core\Platform\Event\Queue\Contracts\QueueDriverInterface;
use PpPhp\Core\Platform\Event\Queue\Drivers\MemoryQueueDriver;
use PpPhp\Core\Platform\Event\Queue\Drivers\NullQueueDriver;

final class DeferredQueueManager
{
    private array $drivers = [];
    private string $defaultDriver = 'memory';

    public function __construct(private readonly ?EventBus $bus = null)
    {
        $this->registerDriver(new MemoryQueueDriver());
        $this->registerDriver(new NullQueueDriver());
    }

    public function registerDriver(QueueDriverInterface $driver): void
    {
        $this->drivers[$driver->name()] = $driver;
    }

    public function use(string $name): self
    {
        if (isset($this->drivers[$name])) {
            $this->defaultDriver = $name;
        }
        return $this;
    }

    public function driver(?string $name = null): DeferredEventQueue
    {
        $name ??= $this->defaultDriver;
        return new DeferredEventQueue($this->drivers[$name] ?? $this->drivers[$this->defaultDriver]);
    }

    public function enqueue(EventInterface|string $event, array $payload = [], array $metadata = []): string
    {
        return $this->driver()->enqueue(DeferredEvent::fromEvent($event, $payload, $metadata));
    }

    public function flush(?callable $handler = null): int
    {
        $handler ??= function (DeferredEvent $event): void {
            if ($this->bus !== null) {
                $this->bus->dispatch($event->event());
            }
        };

        return $this->driver()->flush($handler);
    }

    public function clear(): void { $this->driver()->clear(); }
    public function snapshot(): QueueSnapshot { return $this->driver()->snapshot(); }
    public function restore(QueueSnapshot $snapshot): void { $this->driver()->restore($snapshot); }
    public function statistics(): QueueStatistics { return $this->driver()->statistics(); }

    public function summary(): array
    {
        return [
            'defaultDriver' => $this->defaultDriver,
            'drivers' => array_keys($this->drivers),
            'statistics' => $this->statistics()->toArray(),
        ];
    }
}
