<?php

declare(strict_types=1);

use App\Filament\Pages\Reviews\CustomerReviewWorkspace;
use App\Filament\Resources\EnvironmentReviewResource;
use App\Support\ManagedEnvironmentLinks;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
use Illuminate\Support\Facades\Route;

/**
 * @return list<string>
 */
function spec317Files(array $roots): array
{
    $files = [];

    foreach ($roots as $root) {
        if (is_file($root)) {
            $files[] = $root;

            continue;
        }

        if (! is_dir($root)) {
            continue;
        }

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

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

            if ($file->getFilename() === 'LegacyTenantPlatformContextCleanupTest.php') {
                continue;
            }

            if (! in_array($file->getExtension(), ['php', 'md'], true)) {
                continue;
            }

            $files[] = $file->getPathname();
        }
    }

    sort($files);

    return array_values(array_unique($files));
}

/**
 * @param  list<string>  $files
 * @param  list<string>  $patterns
 * @return list<string>
 */
function spec317PatternHits(array $files, array $patterns): array
{
    $hits = [];

    foreach ($files as $path) {
        $contents = file_get_contents($path);

        if (! is_string($contents)) {
            continue;
        }

        $lines = preg_split('/\R/', $contents) ?: [];

        foreach ($patterns as $pattern) {
            foreach ($lines as $lineNumber => $line) {
                if (preg_match($pattern, $line) !== 1) {
                    continue;
                }

                $hits[] = str_replace(repo_path().'/', '', $path).':'.($lineNumber + 1).' -> '.trim($line);
            }
        }
    }

    return $hits;
}

it('removes retired platform-context helper and class names from active runtime seams', function (): void {
    $files = spec317Files([
        base_path('app'),
        base_path('bootstrap/app.php'),
        base_path('routes/web.php'),
        base_path('tests/Feature/Guards'),
        base_path('tests/Feature/Navigation'),
        base_path('tests/Feature/Reviews'),
    ]);

    $hits = spec317PatternHits($files, [
        '/\btenantPrefilterUrl\s*\(/',
        '/\bCanonicalAdminTenantFilterState\b/',
        '/\bWorkspaceScopedTenantRoutes\b/',
        '/\bTenantPageCategory\b/',
        '/\bEnsureFilamentTenantSelected\b/',
        '/ensure-filament-tenant-selected/',
        '/\blastTenantId\s*\(/',
        '/\brememberedTenant\s*\(/',
        '/\brememberTenantContext\s*\(/',
        '/\bLAST_TENANT_IDS_SESSION_KEY\b/',
        '/\bTenantBound\b/',
        '/\bTenantScopedEvidence\b/',
    ]);

    expect($hits)->toBeEmpty("Retired Tenant platform-context names remain:\n".implode("\n", $hits));
});

it('keeps current product-truth docs on workspace and environment terminology', function (): void {
    $files = spec317Files([
        repo_path('docs/HANDOVER.md'),
        repo_path('docs/product/spec-candidates.md'),
        repo_path('docs/product/implementation-ledger.md'),
        repo_path('docs/product/roadmap.md'),
        repo_path('docs/product/principles.md'),
        repo_path('docs/ui'),
        repo_path('docs/architecture-guidelines.md'),
        repo_path('docs/filament-guidelines.md'),
        repo_path('docs/testing-guidelines.md'),
    ]);

    $hits = spec317PatternHits($files, [
        '/\btenantPrefilterUrl\b/',
        '/\bCanonicalAdminTenantFilterState\b/',
        '/\bWorkspaceScopedTenantRoutes\b/',
        '/\bTenantPageCategory\b/',
        '/\bEnsureFilamentTenantSelected\b/',
        '/\blastTenantId\b/',
        '/\btenantScopedUrl\b/',
    ]);

    expect($hits)->toBeEmpty("Current docs still describe retired Tenant platform context:\n".implode("\n", $hits));
});

it('keeps workspace hubs free of hidden Filament or remembered Environment scope fallbacks', function (): void {
    $files = spec317Files([
        base_path('app/Filament/Pages/Monitoring/Operations.php'),
        base_path('app/Filament/Pages/Monitoring/FindingExceptionsQueue.php'),
        base_path('app/Filament/Pages/Governance/GovernanceInbox.php'),
        base_path('app/Filament/Pages/Governance/DecisionRegister.php'),
        base_path('app/Filament/Pages/Monitoring/EvidenceOverview.php'),
        base_path('app/Filament/Pages/Reviews/ReviewRegister.php'),
        base_path('app/Filament/Pages/Reviews/CustomerReviewWorkspace.php'),
        base_path('app/Filament/Resources/ProviderConnectionResource.php'),
        base_path('app/Filament/Resources/ProviderConnectionResource/Pages/ListProviderConnections.php'),
    ]);

    $hits = spec317PatternHits($files, [
        '/\bFilament::getTenant\s*\(/',
        '/\blastEnvironmentId\s*\(/',
        '/\brememberedEnvironment\s*\(/',
        '/\brememberEnvironmentContext\s*\(/',
    ]);

    expect($hits)->toBeEmpty("Workspace hubs must not derive scope from Filament tenant or remembered Environment state:\n".implode("\n", $hits));
});

it('keeps helper APIs hard-cut to Environment names and canonical filter keys', function (): void {
    expect(method_exists(CustomerReviewWorkspace::class, 'tenantPrefilterUrl'))->toBeFalse()
        ->and(method_exists(CustomerReviewWorkspace::class, 'environmentFilterUrl'))->toBeTrue();

    $reviewUrlHelper = new ReflectionMethod(EnvironmentReviewResource::class, 'environmentScopedUrl');

    $providerConnectionResource = (string) file_get_contents(base_path('app/Filament/Resources/ProviderConnectionResource.php'));

    expect(method_exists(EnvironmentReviewResource::class, 'tenantScopedUrl'))->toBeFalse()
        ->and($reviewUrlHelper->getNumberOfParameters())->toBe(3)
        ->and($providerConnectionResource)
        ->not->toContain("array_key_exists('tenant', \$parameters)")
        ->not->toContain('resolveRequestedTenantExternalId() ?? static::resolveContextTenantExternalId()');
});

it('keeps active environment dashboard links free of retired tenant query aliases', function (): void {
    [$user, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'owner');

    $workspace = $environment->workspace()->firstOrFail();

    $this->actingAs($user);
    Filament::setTenant($environment, true);

    $response = $this
        ->withSession([
            WorkspaceContext::SESSION_KEY => (int) $workspace->getKey(),
            WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY => [
                (string) $workspace->getKey() => (int) $environment->getKey(),
            ],
        ])
        ->get(ManagedEnvironmentLinks::viewUrl($environment));

    $response->assertOk();

    $content = html_entity_decode((string) $response->getContent(), ENT_QUOTES | ENT_HTML5);

    expect($content)
        ->not->toContain('/admin/t')
        ->not->toContain('?tenant=')
        ->not->toContain('&tenant=')
        ->not->toContain('tenant_id=')
        ->not->toContain('managed_environment_id=')
        ->not->toContain('tenant_scope=');
});

it('does not register active legacy tenant panel routes or providers', function (): void {
    $legacyRouteUris = collect(Route::getRoutes())
        ->map(fn ($route): string => ltrim((string) $route->uri(), '/'))
        ->filter(fn (string $uri): bool => preg_match('#^admin/t(?:/|$)#', $uri) === 1)
        ->values();

    $registeredProviders = require base_path('bootstrap/providers.php');
    $tenantPanelProviders = collect($registeredProviders)
        ->filter(fn (string $provider): bool => str_contains($provider, 'TenantPanelProvider'))
        ->values();

    expect($legacyRouteUris)->toBeEmpty()
        ->and($tenantPanelProviders)->toBeEmpty()
        ->and(file_exists(app_path('Providers/Filament/TenantPanelProvider.php')))->toBeFalse();
});
