<?php

namespace MintyPHP\Tests\Architecture;

use PHPUnit\Framework\TestCase;

/**
 * Guard against fragile alias rewrites when query parameters are present.
 *
 * Minty's Router::applyRoutes() compares the full REQUEST_URI (including query)
 * against alias source paths. Therefore, route aliases with query strings are
 * brittle when path != target and should be avoided in runtime code.
 */
final class RouteAliasQuerySafetyContractTest extends TestCase
{
    use ProjectFileAssertionSupport;

    public function testRuntimeCodeDoesNotUseCoreAliasPathsWithQueryStringsWhenPathDiffersFromTarget(): void
    {
        $aliases = $this->coreAliasPathsWithDifferentTargets();
        $this->assertNotSame([], $aliases, 'Expected at least one core route alias with path != target.');

        $scanTargets = ['core', 'pages', 'templates', 'modules'];
        $extensions = ['php', 'phtml'];

        $violations = [];
        foreach ($this->runtimeSourceFiles($scanTargets, $extensions) as $relativePath) {
            $content = $this->readProjectFile($relativePath);
            foreach ($aliases as $aliasPath) {
                $quotedAlias = preg_quote($aliasPath, '#');
                if (preg_match("#(?:lurl|Request::withLocale|Router::redirect)\\(\\s*['\"]{$quotedAlias}\\?#", $content) === 1) {
                    $violations[] = $relativePath . " uses alias '{$aliasPath}' with query string.";
                }
            }
        }

        sort($violations);
        $this->assertSame([], $violations, "Alias+query routing anti-pattern found:\n" . implode("\n", $violations));
    }

    public function testAccessControlUsesConcreteLoginTargetPathForReturnToRedirect(): void
    {
        $content = $this->readProjectFile('core/Http/AccessControl.php');

        $this->assertStringContainsString(
            "Request::withLocale('auth/login', \$locale)",
            $content
        );
        $this->assertStringNotContainsString(
            "Request::withLocale('login', \$locale)",
            $content
        );
    }

    /**
     * @return list<string>
     */
    private function coreAliasPathsWithDifferentTargets(): array
    {
        $routesFile = $this->projectRootPath() . '/config/routes.php';
        $this->assertFileExists($routesFile, 'Missing config/routes.php');

        $routes = require $routesFile;
        $this->assertIsArray($routes, 'config/routes.php must return an array');

        $aliases = [];
        foreach ($routes as $entry) {
            if (!is_array($entry)) {
                continue;
            }

            $path = trim((string) ($entry['path'] ?? ''));
            $target = trim((string) ($entry['target'] ?? ''));
            if ($path === '' || $target === '' || $path === $target) {
                continue;
            }

            $aliases[] = $path;
        }

        $aliases = array_values(array_unique($aliases));
        sort($aliases);

        return $aliases;
    }

    /**
     * @param list<string> $scanTargets
     * @param list<string> $extensions
     * @return list<string>
     */
    private function runtimeSourceFiles(array $scanTargets, array $extensions): array
    {
        $root = $this->projectRootPath();
        $files = [];

        foreach ($scanTargets as $target) {
            $fullPath = $root . '/' . $target;
            if (!is_dir($fullPath)) {
                continue;
            }

            $iterator = new \RecursiveIteratorIterator(
                new \RecursiveDirectoryIterator($fullPath, \FilesystemIterator::SKIP_DOTS)
            );

            foreach ($iterator as $file) {
                if (!$file->isFile()) {
                    continue;
                }

                $extension = strtolower((string) $file->getExtension());
                if (!in_array($extension, $extensions, true)) {
                    continue;
                }

                $files[] = str_replace($root . '/', '', $file->getPathname());
            }
        }

        $files = array_values(array_unique($files));
        sort($files);

        return $files;
    }
}
