<?php
declare(strict_types=1);

namespace CloudXM\SDK\Services;

use CloudXM\SDK\Contracts\EventDispatcherInterface;

/**
 * Simple event dispatcher for CloudXM SDK events with buffering support
 */
final class EventDispatcher implements EventDispatcherInterface
{
    /** @var array<string, callable[]> */
    private array $listeners = [];

    /** @var array<string, object[]> */
    private array $eventBuffer = [];

    /** @var array<string, bool> */
    private array $bufferingEnabled = [];

    /**
     * Enable buffering for a specific event type.
     * Events will be buffered until a listener is registered, then replayed.
     */
    public function enableBuffering(string $eventClass): void
    {
        $this->bufferingEnabled[$eventClass] = true;
        if (!isset($this->eventBuffer[$eventClass])) {
            $this->eventBuffer[$eventClass] = [];
        }
    }

    public function dispatch(object $event): object
    {
        $eventClass = get_class($event);

        // If no listeners and buffering enabled, buffer the event
        if (empty($this->listeners[$eventClass]) && isset($this->bufferingEnabled[$eventClass])) {
            $this->eventBuffer[$eventClass][] = $event;
            return $event;
        }

        // Dispatch to listeners
        if (isset($this->listeners[$eventClass])) {
            foreach ($this->listeners[$eventClass] as $listener) {
                $listener($event);
            }
        }

        return $event;
    }

    public function addListener(string $eventClass, callable $listener): void
    {
        if (!isset($this->listeners[$eventClass])) {
            $this->listeners[$eventClass] = [];
        }

        $this->listeners[$eventClass][] = $listener;

        // Replay buffered events if this is the first listener
        if (count($this->listeners[$eventClass]) === 1 && !empty($this->eventBuffer[$eventClass])) {
            foreach ($this->eventBuffer[$eventClass] as $bufferedEvent) {
                $listener($bufferedEvent);
            }
            // Clear buffer after replay
            $this->eventBuffer[$eventClass] = [];
        }
    }

    public function removeListener(string $eventClass, callable $listener): void
    {
        if (isset($this->listeners[$eventClass])) {
            $key = array_search($listener, $this->listeners[$eventClass], true);
            if ($key !== false) {
                unset($this->listeners[$eventClass][$key]);
            }
        }
    }
}