<?php
declare(strict_types=1);

namespace ROITheme\Shared\Application\UseCases\GetComponent;

use ROITheme\Shared\Domain\Contracts\ComponentRepositoryInterface;
use ROITheme\Shared\Domain\Contracts\CacheServiceInterface;
use ROITheme\Shared\Domain\Exceptions\ComponentNotFoundException;
use ROITheme\Shared\Domain\ValueObjects\ComponentName;

/**
 * GetComponentUseCase - Caso de Uso para obtener componente
 *
 * RESPONSABILIDAD: Orquestar la lógica de obtener un componente
 *
 * FLUJO:
 * 1. Intentar obtener del cache
 * 2. Si no está en cache, obtener del repositorio
 * 3. Si no existe, lanzar excepción
 * 4. Guardar en cache
 * 5. Retornar respuesta
 *
 * OPTIMIZACIÓN:
 * - Cache-first strategy para reducir queries a BD
 * - TTL de 1 hora en cache
 *
 * USO:
 * ```php
 * $useCase = new GetComponentUseCase($repository, $cache);
 * $request = new GetComponentRequest('top_bar');
 * $response = $useCase->execute($request);
 * ```
 *
 * @package ROITheme\Shared\Application\UseCases\GetComponent
 */
final class GetComponentUseCase
{
    private const CACHE_TTL = 3600; // 1 hora

    /**
     * @param ComponentRepositoryInterface $repository Repositorio de componentes
     * @param CacheServiceInterface $cache Servicio de cache
     */
    public function __construct(
        private ComponentRepositoryInterface $repository,
        private CacheServiceInterface $cache
    ) {}

    /**
     * Ejecutar Use Case
     *
     * @param GetComponentRequest $request Datos de entrada
     * @return GetComponentResponse Respuesta (éxito o fallo)
     */
    public function execute(GetComponentRequest $request): GetComponentResponse
    {
        try {
            $componentNameString = $request->getComponentName();
            $componentName = new ComponentName($componentNameString);
            $cacheKey = $this->getCacheKey($componentNameString);

            // 1. Intentar obtener del cache
            $cached = $this->cache->get($cacheKey);

            if ($cached !== null) {
                return GetComponentResponse::success($cached);
            }

            // 2. Si no está en cache, obtener del repositorio
            $component = $this->repository->findByName($componentName);

            if ($component === null) {
                throw new ComponentNotFoundException(
                    "Component '{$componentNameString}' not found"
                );
            }

            $data = $component->toArray();

            // 3. Guardar en cache
            $this->cache->set($cacheKey, $data, self::CACHE_TTL);

            // 4. Retornar respuesta exitosa
            return GetComponentResponse::success($data);

        } catch (ComponentNotFoundException $e) {
            return GetComponentResponse::failure($e->getMessage());
        } catch (\Exception $e) {
            return GetComponentResponse::failure(
                'Unexpected error: ' . $e->getMessage()
            );
        }
    }

    /**
     * Generar key de cache para componente
     *
     * @param string $componentName
     * @return string
     */
    private function getCacheKey(string $componentName): string
    {
        return "component_{$componentName}";
    }
}
