<?php

namespace MintyPHP\App\Module;

use MintyPHP\App\AppContainer;
use MintyPHP\App\Module\Contracts\EventListener;

/**
 * Fire-and-forget event dispatcher for module lifecycle events.
 *
 * Listeners are declared in module manifests and lazy-resolved from the container.
 * A failing listener does not break the dispatch chain — the exception is swallowed
 * so that one misbehaving module cannot disrupt core flows.
 */
final class ModuleEventDispatcher
{
    /**
     * @param array<string, list<array{class: class-string, method: string}>> $listenerMap
     */
    public function __construct(
        private readonly array $listenerMap,
        private readonly AppContainer $container
    ) {
    }

    /**
     * @param array<string, mixed> $payload
     */
    public function dispatch(string $event, array $payload): void
    {
        $listeners = $this->listenerMap[$event] ?? [];

        foreach ($listeners as $descriptor) {
            try {
                $class = $descriptor['class'];
                $method = $descriptor['method'];

                $listener = $this->container->get($class);
                if (!$listener instanceof EventListener) {
                    $listener = new $class();
                }

                $listener->{$method}($event, $payload);
            } catch (\Throwable) {
                // Swallow — one failing listener must not break the chain.
            }
        }
    }
}
