<?php

declare(strict_types=1);

use App\Filament\Clusters\Monitoring\AlertsCluster;
use App\Filament\Pages\TenantDashboard;
use App\Filament\Resources\AlertDestinationResource;
use App\Filament\Resources\AlertRuleResource;
use App\Filament\Resources\RestoreRunResource;
use App\Models\AuditLog;
use App\Models\OperationRun;
use App\Models\Tenant;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Support\OperateHub\OperateHubShell;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Bus;

it('renders operate hub pages DB-only with no outbound HTTP and no queued jobs', function (): void {
    [$user, $tenant] = createMinimalUserWithTenant(role: 'owner');

    $run = OperationRun::factory()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'type' => 'provider.connection.check',
        'status' => 'completed',
        'outcome' => 'blocked',
        'initiator_name' => 'System',
    ]);

    $this->actingAs($user);

    Bus::fake();
    Filament::setTenant(null, true);

    $session = [
        WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
    ];

    assertNoOutboundHttp(function () use ($run, $session): void {
        $this->withSession($session)
            ->get(route('admin.operations.index'))
            ->assertOk()
            ->assertSee('All tenants')
            ->assertDontSee('Scope: Tenant')
            ->assertDontSee('Scope: Workspace');

        $this->withSession($session)
            ->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
            ->assertOk()
            ->assertSee('All tenants')
            ->assertDontSee('Scope: Tenant')
            ->assertDontSee('Scope: Workspace');

        $this->withSession($session)
            ->followingRedirects()
            ->get(AlertsCluster::getUrl(panel: 'admin'))
            ->assertOk()
            ->assertSee('All tenants')
            ->assertDontSee('Scope: Tenant')
            ->assertDontSee('Scope: Workspace');

        $this->withSession($session)
            ->get(route('admin.monitoring.audit-log'))
            ->assertOk()
            ->assertSee('All tenants')
            ->assertDontSee('Scope: Tenant')
            ->assertDontSee('Scope: Workspace');
    });

    Bus::assertNothingDispatched();
})->group('ops-ux');

it('shows back to tenant on run detail when tenant context is active and entitled', function (): void {
    [$user, $tenant] = createMinimalUserWithTenant(role: 'owner');

    $run = OperationRun::factory()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'type' => 'policy.sync',
        'status' => 'queued',
        'outcome' => 'pending',
    ]);

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

    $response = $this->withSession([
        WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
    ])->get(route('admin.operations.view', ['run' => (int) $run->getKey()]));

    $response
        ->assertOk()
        ->assertSee('← Back to '.$tenant->name)
        ->assertSee(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant), false)
        ->assertDontSee('Back to Operations');

    $this->withSession([
        WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
    ])->followingRedirects()
        ->get(AlertsCluster::getUrl(panel: 'admin'))
        ->assertOk()
        ->assertDontSee('Back to Operations');

    expect(substr_count(html_entity_decode((string) $response->getContent(), ENT_QUOTES | ENT_HTML5), '← Back to '.$tenant->name))->toBe(1);
})->group('ops-ux');

it('shows back to tenant when filament tenant is absent but last tenant memory exists', function (): void {
    [$user, $tenant] = createMinimalUserWithTenant(role: 'owner');

    $run = OperationRun::factory()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'type' => 'policy.sync',
        'status' => 'queued',
        'outcome' => 'pending',
    ]);

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

    $workspaceId = (int) $tenant->workspace_id;
    $lastTenantMap = [(string) $workspaceId => (int) $tenant->getKey()];

    $response = $this->withSession([
        WorkspaceContext::SESSION_KEY => $workspaceId,
        WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY => $lastTenantMap,
    ])->get(route('admin.operations.view', ['run' => (int) $run->getKey()]));

    $response
        ->assertOk()
        ->assertSee('← Back to '.$tenant->name)
        ->assertSee(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant), false)
        ->assertSee('Show all operations')
        ->assertDontSee('Back to Operations');
})->group('ops-ux');

it('shows no tenant return affordance when active and last tenant contexts are not entitled', function (): void {
    [$user, $entitledTenant] = createMinimalUserWithTenant(role: 'owner');

    $nonEntitledTenant = Tenant::factory()->create([
        'workspace_id' => (int) $entitledTenant->workspace_id,
    ]);

    $run = OperationRun::factory()->create([
        'tenant_id' => (int) $entitledTenant->getKey(),
        'workspace_id' => (int) $entitledTenant->workspace_id,
        'type' => 'policy.sync',
        'status' => 'queued',
        'outcome' => 'pending',
    ]);

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

    $workspaceId = (int) $entitledTenant->workspace_id;

    $response = $this->withSession([
        WorkspaceContext::SESSION_KEY => $workspaceId,
        WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY => [(string) $workspaceId => (int) $nonEntitledTenant->getKey()],
    ])->get(route('admin.operations.view', ['run' => (int) $run->getKey()]));

    $response
        ->assertOk()
        ->assertSee('Back to Operations')
        ->assertDontSee('← Back to '.$nonEntitledTenant->name)
        ->assertDontSee('Show all operations');
})->group('ops-ux');

it('renders shared scope and return copy as secondary monitoring context on operations surfaces', function (): void {
    [$user, $tenant] = createMinimalUserWithTenant(role: 'owner');

    $run = OperationRun::factory()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'type' => 'policy.sync',
        'status' => 'queued',
        'outcome' => 'pending',
    ]);

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

    $this->withSession([
        WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
    ])->get(route('admin.operations.index'))
        ->assertOk()
        ->assertSee('Monitoring landing')
        ->assertSee('Scope context')
        ->assertSee('Scope reset');

    $this->withSession([
        WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
    ])->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
        ->assertOk()
        ->assertSee('Monitoring detail')
        ->assertSee('Navigation lane')
        ->assertSee('Follow-up lane');
})->group('ops-ux');

it('returns 404 for non-member workspace access on /admin/operations', function (): void {
    $user = User::factory()->create();
    $workspace = Workspace::factory()->create();

    // User is NOT a member — stale workspace context is denied as not found.
    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
        ->get(route('admin.operations.index'))
        ->assertNotFound();
})->group('ops-ux');

it('returns 404 for non-entitled tenant dashboard direct access', function (): void {
    $tenant = Tenant::factory()->create();
    $user = User::factory()->create();

    WorkspaceMembership::factory()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'user_id' => (int) $user->getKey(),
        'role' => 'owner',
    ]);

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant))
        ->assertNotFound();
})->group('ops-ux');

it('keeps member-without-capability workflow start denial as 403 with no run side effects', function (): void {
    [$user, $tenant] = createMinimalUserWithTenant(role: 'operator');

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

    $this->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get(RestoreRunResource::getUrl('create', tenant: $tenant))
        ->assertForbidden();

    expect(OperationRun::query()
        ->where('tenant_id', (int) $tenant->getKey())
        ->exists())->toBeFalse();
})->group('ops-ux');

it('does not mutate workspace or last-tenant session memory on /admin/operations', function (): void {
    [$user, $tenant] = createMinimalUserWithTenant(role: 'owner');

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

    $workspaceId = (int) $tenant->workspace_id;
    $lastTenantMap = [(string) $workspaceId => (int) $tenant->getKey()];

    $response = $this->withSession([
        WorkspaceContext::SESSION_KEY => $workspaceId,
        WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY => $lastTenantMap,
    ])->get(route('admin.operations.index'));

    $response->assertOk();
    $response->assertSessionHas(WorkspaceContext::SESSION_KEY, $workspaceId);
    $response->assertSessionHas(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, $lastTenantMap);
})->group('ops-ux');

it('prefers the filament tenant over remembered workspace tenant state when both are entitled', function (): void {
    $tenantA = Tenant::factory()->create();
    [$user, $tenantA] = createMinimalUserWithTenant(tenant: $tenantA, role: 'owner');

    $tenantB = Tenant::factory()->create([
        'workspace_id' => (int) $tenantA->workspace_id,
    ]);

    createMinimalUserWithTenant(tenant: $tenantB, user: $user, role: 'owner');

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

    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id);
    session()->put(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [
        (string) $tenantA->workspace_id => (int) $tenantA->getKey(),
    ]);

    $resolved = app(OperateHubShell::class)->activeEntitledTenant();

    expect($resolved?->is($tenantB))->toBeTrue();
})->group('ops-ux');

it('prefers the current filament tenant over remembered tenant state on canonical run routes', function (): void {
    $runTenant = Tenant::factory()->create([
        'workspace_id' => null,
    ]);
    [$user, $runTenant] = createMinimalUserWithTenant(tenant: $runTenant, role: 'owner');

    $currentTenant = Tenant::factory()->create([
        'workspace_id' => (int) $runTenant->workspace_id,
    ]);

    createMinimalUserWithTenant(tenant: $currentTenant, user: $user, role: 'owner');

    $run = OperationRun::factory()->create([
        'workspace_id' => (int) $runTenant->workspace_id,
        'tenant_id' => (int) $runTenant->getKey(),
        'type' => 'policy.sync',
    ]);

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

    $workspaceId = (int) $runTenant->workspace_id;

    session()->put(WorkspaceContext::SESSION_KEY, $workspaceId);
    session()->put(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [
        (string) $workspaceId => (int) $runTenant->getKey(),
    ]);

    $request = Request::create(route('admin.operations.view', ['run' => (int) $run->getKey()]));
    $request->setLaravelSession(app('session.store'));

    $route = app('router')->getRoutes()->match($request);
    $request->setRouteResolver(static fn () => $route);

    $resolved = app(OperateHubShell::class)->activeEntitledTenant($request);

    expect($resolved?->is($currentTenant))->toBeTrue();
})->group('ops-ux');

it('keeps an administratively discoverable current tenant context on canonical run routes even when it is selector-ineligible', function (): void {
    $runTenant = Tenant::factory()->active()->create([
        'name' => 'Canonical Run Tenant',
    ]);
    [$user, $runTenant] = createMinimalUserWithTenant(tenant: $runTenant, role: 'owner');

    $currentTenant = Tenant::factory()->onboarding()->create([
        'workspace_id' => (int) $runTenant->workspace_id,
        'name' => 'Current Onboarding Tenant',
    ]);

    createMinimalUserWithTenant(
        tenant: $currentTenant,
        user: $user,
        role: 'owner',
        workspaceRole: 'owner',
        ensureDefaultMicrosoftProviderConnection: false,
    );

    $run = OperationRun::factory()->create([
        'workspace_id' => (int) $runTenant->workspace_id,
        'tenant_id' => (int) $runTenant->getKey(),
        'type' => 'policy.sync',
    ]);

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

    $workspaceId = (int) $runTenant->workspace_id;

    session()->put(WorkspaceContext::SESSION_KEY, $workspaceId);
    session()->put(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [
        (string) $workspaceId => (int) $runTenant->getKey(),
    ]);

    $request = Request::create(route('admin.operations.view', ['run' => (int) $run->getKey()]));
    $request->setLaravelSession(app('session.store'));

    $route = app('router')->getRoutes()->match($request);
    $request->setRouteResolver(static fn () => $route);

    $resolved = app(OperateHubShell::class)->activeEntitledTenant($request);

    expect($resolved?->is($currentTenant))->toBeTrue();
})->group('ops-ux');

it('clears stale remembered tenant ids when the remembered tenant is no longer entitled', function (): void {
    [$user, $tenant] = createMinimalUserWithTenant(role: 'owner');

    $staleTenant = Tenant::factory()->create([
        'workspace_id' => (int) $tenant->workspace_id,
    ]);

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

    $workspaceId = (int) $tenant->workspace_id;

    session()->put(WorkspaceContext::SESSION_KEY, $workspaceId);
    session()->put(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [
        (string) $workspaceId => (int) $staleTenant->getKey(),
    ]);

    $resolved = app(OperateHubShell::class)->activeEntitledTenant();

    expect($resolved)->toBeNull();
    expect(session()->get(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, []))
        ->not->toHaveKey((string) $workspaceId);
})->group('ops-ux');

it('prefers the routed tenant over remembered workspace tenant state when a tenant route parameter is present', function (): void {
    $rememberedTenant = Tenant::factory()->create([
        'name' => 'YPTW2',
        'environment' => 'dev',
        'status' => 'active',
    ]);
    [$user, $rememberedTenant] = createMinimalUserWithTenant(tenant: $rememberedTenant, role: 'owner');

    $routedTenant = Tenant::factory()->create([
        'workspace_id' => (int) $rememberedTenant->workspace_id,
        'name' => 'Phoenicon',
        'environment' => 'dev',
        'status' => 'active',
    ]);

    createMinimalUserWithTenant(tenant: $routedTenant, user: $user, role: 'owner');

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

    $workspaceId = (int) $rememberedTenant->workspace_id;

    session()->put(WorkspaceContext::SESSION_KEY, $workspaceId);
    session()->put(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [
        (string) $workspaceId => (int) $rememberedTenant->getKey(),
    ]);

    $request = Request::create("/admin/tenants/{$routedTenant->external_id}/required-permissions");
    $request->setLaravelSession(app('session.store'));

    $route = app('router')->getRoutes()->match($request);
    $request->setRouteResolver(static fn () => $route);

    $resolved = app(OperateHubShell::class)->activeEntitledTenant($request);

    expect($resolved?->is($routedTenant))->toBeTrue();
})->group('ops-ux');

it('prefers the routed tenant resource record over active tenant state on admin tenant view routes', function (): void {
    $rememberedTenant = Tenant::factory()->create([
        'name' => 'YPTW2',
        'environment' => 'dev',
        'status' => 'active',
    ]);
    [$user, $rememberedTenant] = createMinimalUserWithTenant(tenant: $rememberedTenant, role: 'owner');

    $routedTenant = Tenant::factory()->create([
        'workspace_id' => (int) $rememberedTenant->workspace_id,
        'name' => 'Test',
        'environment' => 'dev',
        'status' => Tenant::STATUS_ONBOARDING,
    ]);

    createMinimalUserWithTenant(tenant: $routedTenant, user: $user, role: 'owner');

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

    $workspaceId = (int) $rememberedTenant->workspace_id;

    session()->put(WorkspaceContext::SESSION_KEY, $workspaceId);
    session()->put(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [
        (string) $workspaceId => (int) $rememberedTenant->getKey(),
    ]);

    $request = Request::create("/admin/tenants/{$routedTenant->external_id}");
    $request->setLaravelSession(app('session.store'));

    $route = app('router')->getRoutes()->match($request);
    $request->setRouteResolver(static fn () => $route);

    $resolved = app(OperateHubShell::class)->activeEntitledTenant($request);

    expect($resolved?->is($routedTenant))->toBeTrue();
})->group('ops-ux');

it('shows tenant filter label when tenant context is active', function (): void {
    [$user, $tenant] = createMinimalUserWithTenant(role: 'owner');

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

    $this->withSession([
        WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
    ])->get(route('admin.operations.index'))
        ->assertOk()
        ->assertSee('Tenant scope: '.$tenant->name)
        ->assertDontSee('Scope: Tenant')
        ->assertDontSee('Scope: Workspace')
        ->assertDontSee('All tenants');
})->group('ops-ux');

it('does not create audit entries when viewing operate hub pages', function (): void {
    [$user, $tenant] = createMinimalUserWithTenant(role: 'owner');

    $run = OperationRun::factory()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'type' => 'policy.sync',
        'status' => 'queued',
        'outcome' => 'pending',
    ]);

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

    $before = (int) AuditLog::query()->count();

    $session = [
        WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
    ];

    $this->withSession($session)
        ->get(route('admin.operations.index'))
        ->assertOk();

    $this->withSession($session)
        ->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
        ->assertOk();

    $this->withSession($session)
        ->followingRedirects()
        ->get(AlertsCluster::getUrl(panel: 'admin'))
        ->assertOk();

    $this->withSession($session)
        ->get(route('admin.monitoring.audit-log'))
        ->assertOk();

    expect((int) AuditLog::query()->count())->toBe($before);
})->group('ops-ux');

it('suppresses tenant indicator on alert rules list page (manage page)', function (): void {
    [$user, $tenant] = createMinimalUserWithTenant(role: 'owner');

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

    $this->withSession([
        WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
    ])->get(AlertRuleResource::getUrl(panel: 'admin'))
        ->assertOk()
        ->assertDontSee('Filtered by tenant')
        ->assertDontSee('Scope: Tenant')
        ->assertDontSee('Scope: Workspace');
})->group('ops-ux');

it('suppresses tenant indicator on alert destinations list page (manage page)', function (): void {
    [$user, $tenant] = createMinimalUserWithTenant(role: 'owner');

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

    $this->withSession([
        WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
    ])->get(AlertDestinationResource::getUrl(panel: 'admin'))
        ->assertOk()
        ->assertDontSee('Filtered by tenant')
        ->assertDontSee('Scope: Tenant')
        ->assertDontSee('Scope: Workspace');
})->group('ops-ux');

it('suppresses tenant indicator on alert rules list with lastTenantId fallback', function (): void {
    [$user, $tenant] = createMinimalUserWithTenant(role: 'owner');

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

    $workspaceId = (int) $tenant->workspace_id;
    $lastTenantMap = [(string) $workspaceId => (int) $tenant->getKey()];

    $this->withSession([
        WorkspaceContext::SESSION_KEY => $workspaceId,
        WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY => $lastTenantMap,
    ])->get(AlertRuleResource::getUrl(panel: 'admin'))
        ->assertOk()
        ->assertDontSee('Filtered by tenant')
        ->assertDontSee('Scope: Tenant');
})->group('ops-ux');

it('treats selector-ineligible remembered tenants as no selected tenant on canonical viewer routes', function (): void {
    $runTenant = Tenant::factory()->active()->create([
        'name' => 'Canonical Run Tenant',
    ]);
    [$user, $runTenant] = createMinimalUserWithTenant(tenant: $runTenant, role: 'owner');

    $rememberedTenant = Tenant::factory()->onboarding()->create([
        'workspace_id' => (int) $runTenant->workspace_id,
        'name' => 'Stale Onboarding Tenant',
    ]);

    createMinimalUserWithTenant(
        tenant: $rememberedTenant,
        user: $user,
        role: 'owner',
        workspaceRole: 'owner',
        ensureDefaultMicrosoftProviderConnection: false,
    );

    $run = OperationRun::factory()->create([
        'tenant_id' => (int) $runTenant->getKey(),
        'workspace_id' => (int) $runTenant->workspace_id,
        'type' => 'policy.sync',
    ]);

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

    $response = $this->withSession([
        WorkspaceContext::SESSION_KEY => (int) $runTenant->workspace_id,
        WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY => [
            (string) $runTenant->workspace_id => (int) $rememberedTenant->getKey(),
        ],
    ])->get(route('admin.operations.view', ['run' => (int) $run->getKey()]));

    $response
        ->assertOk()
        ->assertSee('All tenants')
        ->assertSee('Canonical workspace view')
        ->assertSee('No tenant context is currently selected.');
})->group('ops-ux');
