<?php

declare(strict_types=1);

namespace App\Framework\LiveComponents\Contracts;

use App\Framework\LiveComponents\ValueObjects\ComponentId;

/**
 * Interface for Component Registry
 *
 * Provides testable contract for component registration and resolution.
 * Handles BOTH LiveComponents and StaticComponents:
 * - LiveComponents: Dynamic, stateful components with #[LiveComponent] attribute
 * - StaticComponents: Server-rendered components with #[ComponentName] attribute
 *
 * Enables mocking in tests without relying on final class implementations.
 *
 * Framework Pattern: Interface-driven design for testability
 *
 * State Handling (LiveComponents only):
 * - Components use type-safe State Value Objects (CounterState, SearchState, etc.)
 * - Registry creates State VOs from arrays by reading component's $state property type
 * - Components receive fully constructed State VOs in constructor
 */
interface ComponentRegistryInterface
{
    /**
     * Resolve component instance from component ID
     *
     * @param ComponentId $componentId Unique component identifier
     * @param array|null $stateData Initial component state as array (null for new instances)
     * @return LiveComponentContract Resolved component instance
     * @throws \InvalidArgumentException If component not registered
     */
    public function resolve(ComponentId $componentId, ?array $stateData = null): LiveComponentContract;

    /**
     * Render component to HTML
     *
     * @param LiveComponentContract $component Component to render
     * @return string Rendered HTML
     */
    public function render(LiveComponentContract $component): string;

    /**
     * Render component with wrapper (for initial page load)
     *
     * Includes data-component-id and data-component-state attributes.
     *
     * @param LiveComponentContract $component Component to render
     * @return string Rendered HTML with wrapper
     */
    public function renderWithWrapper(LiveComponentContract $component): string;

    /**
     * Check if component is registered
     *
     * @param string $componentName Component name (e.g., 'datatable', 'counter')
     * @return bool True if registered, false otherwise
     */
    public function isRegistered(string $componentName): bool;

    /**
     * Get component class name
     *
     * @param string $componentName Component name
     * @return string|null Fully qualified class name or null if not found
     */
    public function getClassName(string $componentName): ?string;

    /**
     * Get all registered component names
     *
     * @return array<int, string> List of registered component names
     */
    public function getAllComponentNames(): array;
}
