<?php
declare(strict_types=1);

namespace App\Service\Utils;

use ReflectionException;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Class Reflection : Gestion des réflection de class
 * @package App\Service\Utils
 */
class Reflection
{
    public function __construct(readonly private ContainerInterface $container)
    {}

    /**
     * Appelle une fonction avec ses paramètres depuis le nom d'un service
     *
     * @param string $serviceName
     * @param string $method
     * @param mixed[] $parameters
     * @return mixed
     */
    public function dynamicInvokeServiceWithArgsAndMethod(string $serviceName, string $method, array $parameters = []): mixed
    {
        $class = $this->container->get($serviceName);
        if ($class === null) {
            throw new \LogicException("no class found for service " . $serviceName, 400);
        }
        if (!method_exists($class, $method)) {
            throw new \LogicException("method_not_exist", 400);
        }
        return $class->{$method}(...$parameters);
    }

    /**
     * Appelle une fonction avec ses paramètres depuis le nom d'une classe
     *
     * @param string $className
     * @param string $methodName
     * @param mixed[] $parameters
     * @param mixed[] $constructorParameters
     * @return mixed
     * @throws ReflectionException
     */
    public function dynamicInvokeClassWithArgsAndMethod(string $className, string $methodName, array $parameters = [], array $constructorParameters = []): mixed
    {
        $reflection = new \ReflectionClass($className);
        $method = $reflection->getMethod($methodName);

        if($method->isStatic()){
            return $method->invoke(null, ...$parameters);
        }
        return $method->invoke(new $className(...$constructorParameters), ...$parameters);
    }
}
