<?php

declare(strict_types=1);

namespace App\Application\LiveComponents;

use App\Framework\Cache\CacheKey;
use App\Framework\Core\ValueObjects\Duration;
use App\Framework\LiveComponents\ValueObjects\ComponentId;
use App\Framework\StateManagement\StateManager;
use App\Framework\StateManagement\StateManagerStatistics;

/**
 * Domain-specific StateManager wrapper for LiveComponents
 *
 * Provides convenient, type-safe state management for LiveComponent instances
 * with component-aware key generation and lifecycle management.
 *
 * Uses CacheKey Value Object for type-safe key generation and validation.
 *
 * @template T of LiveComponentState
 */
final readonly class LiveComponentStateManager
{
    /**
     * @param StateManager<T> $stateManager Underlying state manager
     */
    public function __construct(
        private StateManager $stateManager,
    ) {
    }

    /**
     * Get state for a specific component instance
     *
     * @param ComponentId $componentId Component instance identifier
     * @return T|null The component state or null if not found
     */
    public function getComponentState(ComponentId $componentId): mixed
    {
        $key = $this->generateKey($componentId);

        return $this->stateManager->getState($key->toString());
    }

    /**
     * Set state for a specific component instance
     *
     * @param ComponentId $componentId Component instance identifier
     * @param T $state The state to persist
     * @param Duration|null $ttl Optional TTL override
     */
    public function setComponentState(
        ComponentId $componentId,
        mixed $state,
        ?Duration $ttl = null
    ): void {
        $key = $this->generateKey($componentId);

        $this->stateManager->setState(
            $key->toString(),
            $state,
            $ttl
        );
    }

    /**
     * Check if state exists for component instance
     *
     * @param ComponentId $componentId Component instance identifier
     */
    public function hasComponentState(ComponentId $componentId): bool
    {
        $key = $this->generateKey($componentId);

        return $this->stateManager->hasState($key->toString());
    }

    /**
     * Remove state for component instance
     *
     * @param ComponentId $componentId Component instance identifier
     */
    public function removeComponentState(ComponentId $componentId): void
    {
        $key = $this->generateKey($componentId);

        $this->stateManager->removeState($key->toString());
    }

    /**
     * Atomically update component state
     *
     * Provides race-condition-free state updates using optimistic locking.
     *
     * @param ComponentId $componentId Component instance identifier
     * @param callable(T|null): T $updater Function to transform state
     * @param Duration|null $ttl Optional TTL override
     * @return T The updated state
     *
     * @example
     * ```php
     * $updatedCart = $stateManager->updateComponentState(
     *     $componentId,
     *     fn($cart) => $cart?->withAddedItem($productId, $name, $price, $qty)
     *         ?? ShoppingCartState::empty()->withAddedItem($productId, $name, $price, $qty)
     * );
     * ```
     */
    public function updateComponentState(
        ComponentId $componentId,
        callable $updater,
        ?Duration $ttl = null
    ): mixed {
        $key = $this->generateKey($componentId);

        return $this->stateManager->updateState(
            $key->toString(),
            $updater,
            $ttl
        );
    }

    /**
     * Get all states for a specific component type
     *
     * Useful for administrative operations or batch processing.
     *
     * @return array<string, T> Map of instance IDs to states
     */
    public function getAllComponentStates(): array
    {
        return $this->stateManager->getAllStates();
    }

    /**
     * Clear all states (use with caution!)
     *
     * Removes all persisted states for this component type.
     * Useful for testing or administrative cleanup.
     */
    public function clearAllComponentStates(): void
    {
        $this->stateManager->clearAll();
    }

    /**
     * Get performance statistics for state operations
     *
     * Provides insights into cache hit rates, operation counts,
     * and performance metrics.
     */
    public function getStatistics(): StateManagerStatistics
    {
        return $this->stateManager->getStatistics();
    }

    /**
     * Generate CacheKey from ComponentId
     *
     * Uses CacheKey::fromNamespace for type-safe key generation.
     * Format: {componentName}:{instanceId}
     * Example: "shopping-cart:user-123"
     */
    private function generateKey(ComponentId $componentId): CacheKey
    {
        return CacheKey::fromNamespace(
            namespace: $componentId->name,
            key: $componentId->instanceId
        );
    }

    /**
     * Create LiveComponentStateManager from factory
     *
     * Convenience factory method for creating type-safe state managers.
     *
     * @template U of LiveComponentState
     * @param StateManager<U> $stateManager
     * @return LiveComponentStateManager<U>
     */
    public static function from(StateManager $stateManager): self
    {
        return new self($stateManager);
    }
}
