<?php

namespace MintyPHP\Tests\Architecture;

/**
 * Module code must prefix session keys with "module.<id>." to prevent
 * collisions between modules and with core session state.
 */
final class ModuleSessionKeyPrefixContractTest extends AbstractModuleStructureContractTestCase
{
    /**
     * Pattern matches direct $_SESSION access with a string key that does NOT
     * start with "module.".
     */
    private const SESSION_ACCESS_PATTERN = '/\$_SESSION\s*\[\s*[\'"](?!module\.)/';

    public function testModulePhpFilesUseSessionPrefix(): void
    {
        $modulesDir = realpath(__DIR__ . '/../../modules');
        self::assertNotFalse($modulesDir);

        $violations = [];

        foreach (self::$modules as $module) {
            $moduleId = $module['id'];

            foreach (['lib', 'pages'] as $subdir) {
                $dir = $module['path'] . '/' . $subdir;
                if (!is_dir($dir)) {
                    continue;
                }

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

                foreach ($iterator as $file) {
                    /** @var \SplFileInfo $file */
                    $ext = $file->getExtension();
                    if ($ext !== 'php' && $ext !== 'phtml') {
                        continue;
                    }

                    $content = file_get_contents($file->getPathname());
                    if ($content === false) {
                        continue;
                    }

                    if (preg_match(self::SESSION_ACCESS_PATTERN, $content)) {
                        $relativePath = 'modules/' . $moduleId . '/' . $subdir . '/' . str_replace($dir . '/', '', $file->getPathname());
                        $violations[] = $relativePath . " (module '{$moduleId}') — session keys must start with 'module.{$moduleId}.'";
                    }
                }
            }
        }

        self::assertSame(
            [],
            $violations,
            "Module session keys must be prefixed with 'module.<id>.':\n" . implode("\n", $violations)
        );
    }
}
