<?php
/**
 * BookiFlex Core
 *
 * @package    BookiFlex
 * @subpackage Core
 * @author     BookiFlex
 * @copyright  Copyright (c) 2025 BookiFlex
 * @license    GPL-2.0-or-later
 *
 * @link       https://bookiflex.com
 */


declare(strict_types=1);
namespace BookiFlex\Core\Contract\DeferrerEvent;

use BookiFlex\Core\Model\Reservation\Reservation;
use Psr\EventDispatcher\EventDispatcherInterface;

defined( 'ABSPATH' ) || exit;

/**
 * This class is responsible for collecting domain events and dispatching them.
 * It collects events from objects and dispatches them using the provided event dispatcher.
 *
 * If an event implements the LastEventInterface, it will be marked as the last event.
 *
 * @see EventsReleaser
 */
class DomainEventCollector
{
    private array $events = [];

    public function collect(object $event): void
    {
        $this->events[] = $event;
    }

    public function dispatch(EventDispatcherInterface $dispatcher): void
    {
        $events = $this->prepareEventsToRelease($this->events);
        foreach ($events as $event) {
            $dispatcher->dispatch($event);
        }
        $this->events = [];
    }

    private function prepareEventsToRelease(array $events): array
    {
        /** @var LatestEventInterface[] $lastEvents */
        $lastEvents     = [];
        $releasedEvents = [];

        foreach ($events as $event) {
            $eventClass = get_class($event);
            $eventKey   = $event instanceof LatestEventInterface ? $eventClass . '#' . $event->getIdentifier() : null;

            if ($eventKey) {
                if (isset($lastEvents[$eventKey])) {
                    $lastEvents[$eventKey]->lastEvent(false);
                }
                $lastEvents[$eventKey] = $event;
            }

            $releasedEvents[] = $event;
        }

        foreach ($lastEvents as $lastEvent) {
            $lastEvent->lastEvent(true);
        }

        return $releasedEvents;
    }
}
