<?php

declare(strict_types=1);

namespace App\Framework\LiveComponents\ValueObjects;

use InvalidArgumentException;

/**
 * Value Object representing a LiveComponent ID
 *
 * Format: "component-name:instance-id"
 * Example: "counter:demo", "search:main-form"
 *
 * Provides type safety and validation for component identifiers.
 */
final readonly class ComponentId
{
    private function __construct(
        public string $name,
        public string $instanceId
    ) {
        $this->validate();
    }

    /**
     * Create ComponentId from string format
     *
     * @param string $id Format: "component-name:instance-id"
     * @throws InvalidArgumentException if format is invalid
     */
    public static function fromString(string $id): self
    {
        if (empty($id)) {
            throw new InvalidArgumentException('Component ID cannot be empty');
        }

        // Parse format "name:instance"
        $parts = explode(':', $id, 2);

        if (count($parts) !== 2) {
            throw new InvalidArgumentException(
                "Invalid component ID format. Expected 'name:instance', got: {$id}"
            );
        }

        [$name, $instanceId] = $parts;

        return new self($name, $instanceId);
    }

    /**
     * Generate a new ComponentId with unique instance ID
     *
     * @param string $name Component name (e.g., 'counter', 'search')
     */
    public static function generate(string $name): self
    {
        if (empty($name)) {
            throw new InvalidArgumentException('Component name cannot be empty');
        }

        // Generate unique instance ID
        $instanceId = uniqid('', true);

        return new self($name, $instanceId);
    }

    /**
     * Create ComponentId with specific instance ID
     *
     * @param string $name Component name
     * @param string $instanceId Instance identifier
     */
    public static function create(string $name, string $instanceId): self
    {
        return new self($name, $instanceId);
    }

    /**
     * Convert to string format "name:instance"
     */
    public function toString(): string
    {
        return "{$this->name}:{$this->instanceId}";
    }

    /**
     * Magic __toString for convenient string conversion
     */
    public function __toString(): string
    {
        return $this->toString();
    }

    /**
     * Check if this ID equals another
     */
    public function equals(self $other): bool
    {
        return $this->name === $other->name
            && $this->instanceId === $other->instanceId;
    }

    /**
     * Check if this component has the given name
     */
    public function hasName(string $name): bool
    {
        return $this->name === $name;
    }

    /**
     * Validate component ID parts
     *
     * @throws InvalidArgumentException if validation fails
     */
    private function validate(): void
    {
        if (empty($this->name)) {
            throw new InvalidArgumentException('Component name cannot be empty');
        }

        if (empty($this->instanceId)) {
            throw new InvalidArgumentException('Instance ID cannot be empty');
        }

        // Validate name format (alphanumeric, hyphens, underscores)
        if (! preg_match('/^[a-z0-9_-]+$/i', $this->name)) {
            throw new InvalidArgumentException(
                "Invalid component name format: {$this->name}. " .
                "Only alphanumeric characters, hyphens, and underscores are allowed."
            );
        }

        // Note: Instance ID can contain colons since fromString() splits on first colon only
    }
}
