<?php

namespace MintyPHP\Tests\Architecture;

use PHPUnit\Framework\TestCase;

class CoreStarterkitContractTest extends TestCase
{
    use ProjectFileAssertionSupport;

    public function testPagesDoNotInstantiateServicesRepositoriesOrGatewaysDirectly(): void
    {
        $violations = $this->findPatternMatchesInPhpFiles('pages', '/\bnew\s+[\\\\A-Za-z0-9_]+(?:Service|Gateway|Repository)\s*\(/');
        $this->assertSame([], $violations, "Direct service/repository/gateway instantiation found in pages/:\n" . implode("\n", $violations));
    }

    public function testPagesDoNotUseDatabaseFacadeDirectly(): void
    {
        $violations = $this->findPatternMatchesInPhpFiles('pages', '/\bDB::/');
        $this->assertSame([], $violations, "Direct DB facade usage found in pages/:\n" . implode("\n", $violations));
    }

    public function testAdminPagesDoNotUseFactoryCreateChains(): void
    {
        $violations = $this->findPatternMatchesInPhpFiles('pages/admin', '/app\([^\n]*Factory::class\)->create/');
        $this->assertSame([], $violations, "Factory create-chain usage found in pages/admin/:\n" . implode("\n", $violations));
    }

    public function testAdminPagesDoNotReferenceFactoryClasses(): void
    {
        $violations = $this->findPatternMatchesInPhpFiles('pages/admin', '/Factory::class/');
        $this->assertSame([], $violations, "Factory class usage found in pages/admin/:\n" . implode("\n", $violations));
    }

    public function testPagesUseRequestInputInsteadOfSuperglobals(): void
    {
        $patterns = [
            '/\$_POST/' => '$_POST',
            '/\$_GET/' => '$_GET',
            '/\$_FILES/' => '$_FILES',
            '/REQUEST_METHOD/' => 'REQUEST_METHOD',
            '/\$_SESSION/' => '$_SESSION',
            '/\$_SERVER/' => '$_SERVER',
            '/\$_COOKIE/' => '$_COOKIE',
        ];

        foreach ($patterns as $pattern => $label) {
            $violations = $this->findPatternMatchesInPhpFiles('pages', $pattern);
            $this->assertSame([], $violations, "Superglobal {$label} usage found in pages/:\n" . implode("\n", $violations));
        }
    }

    public function testServicesDoNotUseSuperglobals(): void
    {
        $patterns = [
            '/\$_POST/' => '$_POST',
            '/\$_GET/' => '$_GET',
            '/\$_FILES/' => '$_FILES',
            '/\$_SERVER/' => '$_SERVER',
            '/\$_COOKIE/' => '$_COOKIE',
            '/\$_SESSION/' => '$_SESSION',
            '/\$_REQUEST/' => '$_REQUEST',
        ];

        foreach ($patterns as $pattern => $label) {
            $violations = $this->findPatternMatchesInPhpFiles('lib/Service', $pattern);
            $this->assertSame([], $violations, "Superglobal {$label} usage found in lib/Service/:\n" . implode("\n", $violations));
        }
    }

    public function testApiPagesDoNotReadJsonBodyDirectly(): void
    {
        $violations = $this->findPatternMatchesInPhpFiles('pages/api/v1', '/ApiResponse::readJsonBody\s*\(/');
        $this->assertSame([], $violations, "ApiResponse::readJsonBody usage found in pages/api/v1/:\n" . implode("\n", $violations));
    }

    public function testTemplatesDoNotUseLegacyFilterToggleMarkup(): void
    {
        $pattern = '/data-(?:toolbar-toggle|filter-overflow|filter-toggle)/';
        $violations = array_merge(
            $this->findPatternMatchesInFiles('templates', $pattern, ['phtml']),
            $this->findPatternMatchesInFiles('pages', $pattern, ['phtml'])
        );
        sort($violations);

        $this->assertSame([], $violations, "Legacy filter toggle markup found in templates/pages:\n" . implode("\n", $violations));
    }

    public function testPagesAndTemplatesDoNotUseInlineModuleScripts(): void
    {
        $pattern = '/<script\b(?=[^>]*\btype=["\']module["\'])(?![^>]*\bsrc=)[^>]*>/i';
        $violations = array_merge(
            $this->findPatternMatchesInFiles('templates', $pattern, ['phtml']),
            $this->findPatternMatchesInFiles('pages', $pattern, ['phtml'])
        );
        sort($violations);

        $this->assertSame([], $violations, "Inline module scripts found in templates/pages:\n" . implode("\n", $violations));
    }

    public function testPagesAndTemplatesUseAssetVersionForJsUrls(): void
    {
        $pattern = '/asset\(\s*[\'"][^\'"]+\.js/i';
        $violations = array_merge(
            $this->findPatternMatchesInFiles('templates', $pattern, ['phtml']),
            $this->findPatternMatchesInFiles('pages', $pattern, ['phtml'])
        );
        sort($violations);

        $this->assertSame([], $violations, "asset(...) JS URLs found in templates/pages:\n" . implode("\n", $violations));
    }

    public function testTemplatesDoNotUseDatabaseFacadeDirectly(): void
    {
        $violations = $this->findPatternMatchesInFiles('templates', '/\bDB::/', ['phtml']);
        $this->assertSame([], $violations, "Direct DB facade usage found in templates/:\n" . implode("\n", $violations));
    }

    public function testTemplatesDoNotResolveServiceGatewayOrRepositoryViaDI(): void
    {
        $violations = $this->findPatternMatchesInFiles(
            'templates',
            '/app\(\s*[\\\\A-Za-z0-9_]*(?:Service|Gateway|Repository)::class\s*\)/',
            ['phtml']
        );
        $this->assertSame([], $violations, "DI resolution of Service/Gateway/Repository found in templates/:\n" . implode("\n", $violations));
    }

    public function testNoLegacySettingsGatewayOrServiceReferencesExist(): void
    {
        $patterns = [
            '/\bSettingService::class\b/' => 'SettingService::class',
            '/\bSettingGateway::class\b/' => 'SettingGateway::class',
            '/\bnew\s+SettingService\s*\(/' => 'new SettingService(...)',
            '/\bnew\s+SettingGateway\s*\(/' => 'new SettingGateway(...)',
            '/use\s+[^;]*\\\\SettingService;/' => 'use ...\\SettingService',
            '/use\s+[^;]*\\\\SettingGateway;/' => 'use ...\\SettingGateway',
        ];

        foreach ($patterns as $pattern => $label) {
            $violations = array_merge(
                $this->findPatternMatchesInPhpFiles('lib', $pattern),
                $this->findPatternMatchesInPhpFiles('pages', $pattern),
                $this->findPatternMatchesInPhpFiles('tests', $pattern),
            );
            $violations = array_values(array_filter(
                $violations,
                static fn (string $path): bool => $path !== 'tests/Architecture/CoreStarterkitContractTest.php'
            ));
            $violations = array_values(array_unique($violations));
            sort($violations);

            $this->assertSame([], $violations, "Legacy settings reference {$label} found:\n" . implode("\n", $violations));
        }
    }

}
