<?php

namespace Signteer\Core\Event;

use Plainwork\Core\App;
use Signteer\Core\Event\StorableEventInterface;

class EventBus
{
    public $app = App::class;
    private array $listeners = [];
    private array $registry = [];

    public function register(string $eventClass): self
    {
        $this->registry[] = $eventClass;

        return $this;
    }

    public function reconstruct(string $alias, array $data): ?StorableEventInterface
    {
        $eventClass = null;

        foreach ($this->registry as $tryClass) {
            if ($tryClass::alias() === $alias) {
                $eventClass = $tryClass;
                break;
            }
        }

        $ret = $eventClass ? $eventClass::fromArray($data) : null;

        return $ret;
    }

    public function listen(string $eventClass, $listener): self
    {
        $this->listeners[$eventClass] ??= [];
        $this->listeners[$eventClass][] = $listener;

        return $this;
    }

    public function listenAll($listener): self
    {
        return $this->listen('*', $listener);
    }

    public function emit(object $event)
    {
        $listeners = $this->findListeners($event);
        foreach ($listeners as $listener) {
            $listener($event);
        }
    }

    private function findListeners(object $event): array
    {
        $eventClass = get_class($event);
        $ret = $this->listeners[$eventClass] ?? [];
        $ret = array_merge($ret, $this->listeners['*'] ?? []);

        foreach (array_keys($ret) as $ii) {
            $ret[$ii] = $this->app->makeFunc($ret[$ii]);
        }

        return $ret;
    }
}
