<?php

namespace App\Service;

use App\Dto\CachableDtoInterface;
use InvalidArgumentException;
use ReflectionClass;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;

class RequestDtoCache implements ValueResolverInterface
{
    private const string SESSION_CACHE_PREFIX = 'dto.';

    public function resolve(Request $request, ArgumentMetadata $argument): iterable
    {
        $session = $request->getSession();
        $className = $argument->getType();
        if (!$className || !is_subclass_of($className, CachableDtoInterface::class)
        ) {
            return [];
        }

        $reflection = new ReflectionClass($className);
        $constructor = $reflection->getConstructor();

        if (!$constructor) {
            return []; // No constructor: return empty instance
        }

        $cacheKey = self::SESSION_CACHE_PREFIX . (implode('.', [
                $argument->getControllerName(),
                $argument->getName(),
                $className,
            ]));

        $cacheData = $session->get($cacheKey, []);
        $queryData = $request->query->all();
        $params = $constructor->getParameters();

        if (isset($queryData['reset'])) {
            $queryData = $cacheData = [];
        }

        $args = [];
        foreach ($params as $param) {
            $name = $param->getName();
            if (array_key_exists($name, $queryData)) {
                $args[$name] = $queryData[$name];
            } elseif (array_key_exists($name, $cacheData)) {
                $args[$name] = $cacheData[$name];
            } elseif ($param->isDefaultValueAvailable()) {
                $args[$name] = $param->getDefaultValue();
            } else {
                throw new InvalidArgumentException(sprintf('Missing required parameter "%s" for class "%s"', $name, $className));
            }
        }

        // Store the cache data in the session
        $session->set($cacheKey, $args);

        yield $reflection->newInstanceArgs($args);
    }
}