<?php

declare(strict_types=1);

namespace App\Framework\LiveComponents\ValueObjects;

/**
 * Represents an event emitted by a LiveComponent
 *
 * Events enable component-to-component communication.
 * Components can dispatch events that other components (or client-side code) can listen to.
 *
 * @example
 * // Dispatch event to all components
 * ComponentEvent::broadcast('counter:updated', EventPayload::fromArray(['value' => 42]))
 *
 * // Dispatch event to specific component
 * ComponentEvent::target('notification:show', 'notification-bell:user-123', EventPayload::fromArray(['message' => 'Saved!']))
 */
final readonly class ComponentEvent
{
    public function __construct(
        public string $name,
        public EventPayload $payload,
        public ?string $targetComponentId = null  // null = broadcast to all
    ) {
        if (empty($name)) {
            throw new \InvalidArgumentException('Event name cannot be empty');
        }
    }

    /**
     * Check if this is a broadcast event (no specific target)
     */
    public function isBroadcast(): bool
    {
        return $this->targetComponentId === null;
    }

    /**
     * Check if this event targets a specific component
     */
    public function isTargeted(): bool
    {
        return $this->targetComponentId !== null;
    }

    /**
     * Check if this event targets the given component ID
     */
    public function targetsComponent(string $componentId): bool
    {
        return $this->targetComponentId === $componentId;
    }

    /**
     * Convert to array for JSON serialization
     */
    public function toArray(): array
    {
        return [
            'name' => $this->name,
            'payload' => $this->payload->toArray(),
            'target' => $this->targetComponentId,
        ];
    }

    /**
     * Create broadcast event (no specific target)
     */
    public static function broadcast(string $name, ?EventPayload $payload = null): self
    {
        return new self($name, $payload ?? EventPayload::empty(), null);
    }

    /**
     * Create targeted event (specific component)
     */
    public static function target(string $name, string $targetComponentId, ?EventPayload $payload = null): self
    {
        return new self($name, $payload ?? EventPayload::empty(), $targetComponentId);
    }
}
