<?php

/*
 * This file is part of the Serenity package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Serenity\CoreBundle\DependencyInjection;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;

/**
 * Ensures that project template paths are always resolved first
 * for selected Twig namespaces, allowing projects to override
 * bundle templates cleanly.
 */
class TwigOverridePass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container): void
    {
        if (!$container->hasDefinition('twig.loader.native_filesystem')) {
            return;
        }

        $projectDir = (string) $container->getParameter('kernel.project_dir');

        $loader = $container->getDefinition('twig.loader.native_filesystem');

        $namespaces = [
            'components' => $projectDir . '/templates/components',
            'stream' => $projectDir . '/templates/stream',
            'layout' => $projectDir . '/templates/layout',
            'extends' => $projectDir . '/templates/extends',
        ];

        foreach ($namespaces as $namespace => $projectPath) {
            $this->prioritizeNamespacePath($loader, $namespace, $projectPath, $projectDir);
        }
    }

    private function prioritizeNamespacePath(
        Definition $loader,
        string $namespace,
        string $projectPath,
        string $projectDir,
    ): void {
        $calls = $loader->getMethodCalls();

        $namespaceCalls = [];
        $otherCalls = [];

        foreach ($calls as $call) {
            [$method, $args] = $call;

            if ('addPath' === $method && isset($args[1]) && $namespace === $args[1]) {
                $namespaceCalls[] = $call;
            } else {
                $otherCalls[] = $call;
            }
        }

        $reordered = [];
        $projectFound = false;

        foreach ($namespaceCalls as $call) {
            $path = (string) ($call[1][0] ?? '');

            if (str_starts_with($path, $projectDir . '/templates')) {
                array_unshift($reordered, $call);
                $projectFound = true;
            } else {
                $reordered[] = $call;
            }
        }

        if (!$projectFound && is_dir($projectPath)) {
            array_unshift($reordered, ['addPath', [$projectPath, $namespace]]);
        }

        $loader->setMethodCalls(array_merge($otherCalls, $reordered));
    }
}
