<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Event\Registry;

use InvalidArgumentException;
use PpPhp\Core\Platform\Event\Contracts\EventListenerInterface;

final class ListenerRecord
{
    private mixed $listener;

    public function __construct(
        private readonly string $eventName,
        mixed $listener,
        private readonly int $priority = 0,
        private readonly string $id = '',
        private readonly array $tags = [],
        private readonly array $metadata = [],
        private readonly bool $enabled = true,
        private readonly bool $once = false
    ) {
        if ($eventName === '') {
            throw new InvalidArgumentException('ListenerRecord requires a non-empty event name.');
        }

        if (!$listener instanceof EventListenerInterface && !is_callable($listener)) {
            throw new InvalidArgumentException('ListenerRecord listener must be callable or implement EventListenerInterface.');
        }

        $this->listener = $listener;
    }

    public function eventName(): string { return $this->eventName; }
    public function listener(): mixed { return $this->listener; }
    public function priority(): int { return $this->priority; }
    public function tags(): array { return $this->tags; }
    public function metadata(): array { return $this->metadata; }
    public function enabled(): bool { return $this->enabled; }
    public function once(): bool { return $this->once; }

    public function id(): string
    {
        if ($this->id !== '') {
            return $this->id;
        }

        if ($this->listener instanceof EventListenerInterface) {
            return $this->listener::class;
        }

        if (is_array($this->listener)) {
            $target = is_object($this->listener[0]) ? $this->listener[0]::class : (string) $this->listener[0];
            return $target . '::' . (string) $this->listener[1];
        }

        if ($this->listener instanceof \Closure) {
            return 'closure:' . spl_object_id($this->listener);
        }

        if (is_string($this->listener)) {
            return $this->listener;
        }

        if (is_object($this->listener) && method_exists($this->listener, '__invoke')) {
            return $this->listener::class . '::__invoke';
        }

        return sha1($this->eventName . '|' . $this->priority);
    }

    public function toArray(): array
    {
        return [
            'id' => $this->id(),
            'eventName' => $this->eventName,
            'priority' => $this->priority,
            'enabled' => $this->enabled,
            'once' => $this->once,
            'tags' => $this->tags,
            'metadata' => $this->metadata,
        ];
    }
}
