<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\DI\Graph;

use PpPhp\Core\Platform\DI\Definition\ClassDefinition;
use PpPhp\Core\Platform\DI\Definition\AliasDefinition;
use PpPhp\Core\Platform\DI\Repository\DefinitionRepository;
use PpPhp\Core\Platform\DI\Reflection\ReflectionService;

final class DependencyGraphBuilder
{
    public function __construct(private readonly ReflectionService $reflection = new ReflectionService()) {}

    public function build(DefinitionRepository $repository): DependencyGraph
    {
        $graph = new DependencyGraph();

        foreach ($repository->all() as $definition) {
            $graph->addNode(new DependencyNode($definition->id(), $definition->type(), [
                'lifetime' => $definition->lifetime(),
                'visibility' => $definition->visibility(),
                'lazy' => $definition->lazy(),
            ]));

            if ($definition instanceof AliasDefinition) {
                $graph->addEdge(new DependencyEdge($definition->id(), $definition->target(), 'alias'));
                continue;
            }

            if ($definition instanceof ClassDefinition && class_exists($definition->className())) {
                $metadata = $this->reflection->inspect($definition->className());
                $constructor = $metadata->constructor();

                if (!$constructor) {
                    continue;
                }

                foreach ($constructor->parameters() as $parameter) {
                    $type = $parameter->type();
                    if ($type !== null && !$parameter->builtin()) {
                        $graph->addEdge(new DependencyEdge($definition->id(), $type, 'constructor:$' . $parameter->name()));
                    }
                }
            }
        }

        return $graph;
    }
}
