<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Event\Listener;

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

final class EventListenerDefinition
{
    private mixed $listener;

    public function __construct(
        private readonly string $eventName,
        mixed $listener,
        private readonly int $priority = 0,
        private readonly string $id = ''
    ) {
        if ($eventName === '') {
            throw new InvalidArgumentException('Event listener definition requires a non-empty event name.');
        }
        if (!$listener instanceof EventListenerInterface && !is_callable($listener)) {
            throw new InvalidArgumentException('Event 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 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 'callable:' . md5($this->eventName . '|' . $this->priority);
    }

    public function toArray(): array
    {
        return [
            'eventName' => $this->eventName,
            'priority' => $this->priority,
            'id' => $this->id(),
            'listenerType' => $this->listener instanceof EventListenerInterface ? 'listener-object' : gettype($this->listener),
        ];
    }
}
