<?php

namespace MintyPHP\Tests\Architecture;

use PHPUnit\Framework\TestCase;

/**
 * GR-SEC-007: API requests must not start session/cookie/remember-me web flows.
 */
final class ApiSessionIsolationContractTest extends TestCase
{
    use ProjectFileAssertionSupport;

    public function testApiActionsDoNotUseSessionOrWebGuardFlows(): void
    {
        $apiFiles = $this->collectFilesByExtension('pages/api/v1', ['php']);
        self::assertNotSame([], $apiFiles, 'Expected API actions under pages/api/v1.');

        $patterns = [
            '/\bSession::/' => 'Session::*',
            '/\bGuard::/' => 'Guard::*',
            '/\bsetcookie\s*\(/i' => 'setcookie(...)',
            '/\bsession_start\s*\(/i' => 'session_start(...)',
            '/remember[-_ ]?me/i' => 'remember-me',
            '/session[_ ]?timeout/i' => 'session-timeout',
        ];

        $violations = [];
        foreach ($apiFiles as $relativePath) {
            $content = $this->readProjectFile($relativePath);
            foreach ($patterns as $regex => $label) {
                if (preg_match($regex, $content)) {
                    $violations[] = "{$relativePath} uses {$label}";
                }
            }
        }

        sort($violations);
        self::assertSame(
            [],
            $violations,
            "API action files contain web-session flow references (GR-SEC-007):\n" . implode("\n", $violations)
        );
    }

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

        self::assertStringNotContainsString('Session::start(', $content);
        self::assertStringNotContainsString('RememberMe', $content);
        self::assertStringNotContainsString('CookieStore', $content);
        self::assertStringNotContainsString('session timeout', strtolower($content));
    }

    /**
     * @param list<string> $extensions
     * @return list<string>
     */
    private function collectFilesByExtension(string $relativeDir, array $extensions): array
    {
        $root = $this->projectRootPath();
        $dir = $root . '/' . $relativeDir;
        if (!is_dir($dir)) {
            return [];
        }

        $result = [];
        $iterator = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS)
        );

        foreach ($iterator as $file) {
            if (!$file->isFile()) {
                continue;
            }
            if (!in_array(strtolower($file->getExtension()), $extensions, true)) {
                continue;
            }

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

        sort($result);
        return $result;
    }
}
