<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\DI\Resolver;

use PpPhp\Core\Platform\DI\Contracts\ContainerInterface;
use PpPhp\Core\Platform\DI\Contracts\DefinitionInterface;
use PpPhp\Core\Platform\DI\Contracts\ResolverInterface;
use PpPhp\Core\Platform\DI\Reflection\ReflectionCache;
use PpPhp\Core\Platform\DI\Reflection\ReflectionService;

final class DefinitionResolver implements ResolverInterface
{
    private ReflectionService $reflection;
    private ConstructorResolver $constructor;
    private ResolutionStack $stack;

    public function __construct(?ReflectionService $reflection = null, ?ConstructorResolver $constructor = null, ?ResolutionStack $stack = null)
    {
        $this->reflection = $reflection ?? new ReflectionService(new ReflectionCache());
        $this->constructor = $constructor ?? new ConstructorResolver($this->reflection, new ParameterResolver());
        $this->stack = $stack ?? new ResolutionStack();
    }

    public function resolve(DefinitionInterface $definition, ContainerInterface $container): mixed
    {
        $this->stack->push($definition->id());

        try {
            return $definition->resolve($container, $this);
        } finally {
            $this->stack->pop();
        }
    }

    public function buildClass(string $className, ContainerInterface $container): object
    {
        return $this->constructor->build($className, $container);
    }

    public function reflection(): ReflectionService
    {
        return $this->reflection;
    }

    public function stack(): ResolutionStack
    {
        return $this->stack;
    }
}
