<?php

declare (strict_types=1);
namespace Rector\Symfony;

use PhpParser\Node;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\NameResolver;
use PHPStan\Reflection\ReflectionProvider;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\PhpParser\Node\BetterNodeFinder;
use Rector\PhpParser\Parser\RectorParser;
final class BundleClassResolver
{
    /**
     * @readonly
     */
    private BetterNodeFinder $betterNodeFinder;
    /**
     * @readonly
     */
    private NodeNameResolver $nodeNameResolver;
    /**
     * @readonly
     */
    private RectorParser $rectorParser;
    /**
     * @readonly
     */
    private ReflectionProvider $reflectionProvider;
    public function __construct(BetterNodeFinder $betterNodeFinder, NodeNameResolver $nodeNameResolver, RectorParser $rectorParser, ReflectionProvider $reflectionProvider)
    {
        $this->betterNodeFinder = $betterNodeFinder;
        $this->nodeNameResolver = $nodeNameResolver;
        $this->rectorParser = $rectorParser;
        $this->reflectionProvider = $reflectionProvider;
    }
    public function resolveShortBundleClassFromControllerClass(string $class): ?string
    {
        $classReflection = $this->reflectionProvider->getClass($class);
        // resolve bundle from existing ones
        $fileName = $classReflection->getFileName();
        if ($fileName === null) {
            return null;
        }
        $controllerDirectory = dirname($fileName);
        $rootFolder = getenv('SystemDrive', \true) . \DIRECTORY_SEPARATOR;
        // traverse up, un-till first bundle class appears
        $bundleFiles = [];
        while ($bundleFiles === [] && $controllerDirectory !== $rootFolder) {
            $bundleFiles = (array) glob($controllerDirectory . '/**Bundle.php');
            $controllerDirectory = dirname($controllerDirectory);
        }
        /** @var string[] $bundleFiles */
        if ($bundleFiles === []) {
            return null;
        }
        $bundleFile = $bundleFiles[0];
        $bundleClassName = $this->resolveClassNameFromFilePath($bundleFile);
        if ($bundleClassName !== null) {
            return $this->nodeNameResolver->getShortName($bundleClassName);
        }
        return null;
    }
    private function resolveClassNameFromFilePath(string $filePath): ?string
    {
        $nodes = $this->rectorParser->parseFile($filePath);
        $this->addFullyQualifiedNamesToNodes($nodes);
        $classLike = $this->betterNodeFinder->findFirstNonAnonymousClass($nodes);
        if (!$classLike instanceof ClassLike) {
            return null;
        }
        return $this->nodeNameResolver->getName($classLike);
    }
    /**
     * @param Node[] $nodes
     */
    private function addFullyQualifiedNamesToNodes(array $nodes): void
    {
        $nodeTraverser = new NodeTraverser();
        $nameResolver = new NameResolver();
        $nodeTraverser->addVisitor($nameResolver);
        $nodeTraverser->traverse($nodes);
    }
}
