<?php

use App\Filament\Resources\InventoryItemResource;
use App\Livewire\BulkOperationProgress;
use App\Models\OperationRun;
use App\Models\ManagedEnvironment;
use App\Support\OpsUx\OperationRunUrl;
use Filament\Facades\Filament;
use Livewire\Livewire;

it('keeps the shell inert when no tenant context is selected', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'user_id' => (int) $user->getKey(),
        'type' => 'inventory_sync',
        'status' => 'running',
        'outcome' => 'pending',
        'started_at' => now()->subMinute(),
    ]);

    Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns')
        ->assertSet('disabled', true)
        ->assertSet('hasVisibleRuns', false)
        ->assertDontSee('Inventory sync')
        ->assertDontSee('Active operations');
})->group('ops-ux');

it('keeps the shell inert when the actor cannot view operation runs', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $this->actingAs($user);
    Filament::setTenant($tenant, true);
    session()->forget(\App\Support\Workspaces\WorkspaceContext::SESSION_KEY);

    OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'user_id' => (int) $user->getKey(),
        'type' => 'inventory_sync',
        'status' => 'running',
        'outcome' => 'pending',
        'started_at' => now()->subMinute(),
    ]);

    Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns')
        ->assertSet('disabled', true)
        ->assertSet('hasVisibleRuns', false)
        ->assertDontSee('Inventory sync')
        ->assertDontSee('Active operations');
})->group('ops-ux');

it('does not expose another tenant run through the selected tenant shell', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $foreignTenant = ManagedEnvironment::factory()->create([
        'workspace_id' => (int) $tenant->workspace_id,
    ]);

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

    OperationRun::factory()->create([
        'managed_environment_id' => (int) $foreignTenant->getKey(),
        'workspace_id' => (int) $foreignTenant->workspace_id,
        'type' => 'policy.sync',
        'status' => 'running',
        'outcome' => 'pending',
        'initiator_name' => 'Foreign tenant run',
        'started_at' => now()->subMinute(),
    ]);

    Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns')
        ->assertSet('disabled', false)
        ->assertSet('hasVisibleRuns', false)
        ->assertDontSee('Policy sync')
        ->assertDontSee('Foreign tenant run');
})->group('ops-ux');

it('renders three visible run summaries while grouping banner actions in one action area', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    $firstRun = null;

    foreach (range(0, 3) as $offset) {
        $run = OperationRun::factory()->create([
            'managed_environment_id' => (int) $tenant->getKey(),
            'workspace_id' => (int) $tenant->workspace_id,
            'user_id' => (int) $user->getKey(),
            'type' => 'inventory_sync',
            'status' => 'queued',
            'outcome' => 'pending',
            'created_at' => now()->subMinutes($offset),
        ]);

        if ($offset === 0) {
            $firstRun = $run;
        }
    }

    $component = Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns');

    $html = $component->html();
    $pageText = preg_replace('/\s+/', ' ', strip_tags($html));

    expect(substr_count($html, 'data-testid="ops-ux-activity-feedback-item"'))->toBe(3)
        ->and($html)->toContain('Active operations')
        ->and($pageText)->toContain('Queued and running work stays here until diagnostics are needed.')
        ->and(substr_count($html, 'Review operations'))->toBe(1)
        ->and(substr_count($html, 'View operation'))->toBe(0)
        ->and($html)->toContain('data-testid="ops-ux-activity-feedback-actions"')
        ->and($html)->toContain('data-testid="ops-ux-activity-feedback-primary-action"')
        ->and($html)->toContain('Show all operations')
        ->and($html)->toContain('Hide activity')
        ->and($html)->not->toContain('Dismiss')
        ->and($html)->not->toContain('Acknowledge')
        ->and($html)->toContain(OperationRunUrl::index($tenant))
        ->and($html)->not->toContain($firstRun instanceof OperationRun ? OperationRunUrl::view($firstRun, $tenant) : '')
        ->and($html)->not->toContain('Open operation');
})->group('ops-ux');

it('renders a single visible operation with a detail primary action', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    $run = OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'user_id' => (int) $user->getKey(),
        'type' => 'inventory_sync',
        'status' => 'queued',
        'outcome' => 'pending',
        'created_at' => now()->subSeconds(10),
    ]);

    $component = Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns');

    $html = $component->html();
    $pageText = preg_replace('/\s+/', ' ', strip_tags($html));

    expect(substr_count($html, 'data-testid="ops-ux-activity-feedback-item"'))->toBe(1)
        ->and($html)->toContain('Active operations')
        ->and($pageText)->toContain('Queued and running work stays here until diagnostics are needed.')
        ->and(substr_count($html, 'View operation'))->toBe(1)
        ->and($html)->not->toContain('Review operations')
        ->and($html)->toContain(OperationRunUrl::view($run, $tenant))
        ->and($html)->toContain(OperationRunUrl::index($tenant))
        ->and($html)->toContain('Hide activity')
        ->and($html)->not->toContain('Dismiss')
        ->and($html)->not->toContain('Acknowledge');
})->group('ops-ux');

it('renders a recent terminal success state with dismiss instead of hide activity', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'user_id' => (int) $user->getKey(),
        'type' => 'inventory_sync',
        'status' => 'completed',
        'outcome' => 'succeeded',
        'started_at' => now()->subMinutes(2),
        'completed_at' => now()->subSeconds(8),
        'summary_counts' => [
            'total' => 10,
            'processed' => 10,
        ],
    ]);

    $component = Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns');

    $html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
    $pageText = preg_replace('/\s+/', ' ', strip_tags($html));

    expect($component->get('hasActiveRuns'))->toBeFalse()
        ->and($html)->toContain('Operation updates')
        ->and($pageText)->toContain('Successful operation updates stay briefly visible so you can confirm completion and keep working.')
        ->and($pageText)->toContain('Completed successfully')
        ->and($pageText)->toContain('No action needed.')
        ->and($html)->toContain('View operation')
        ->and($html)->not->toContain('Review operations')
        ->and($html)->toContain('Dismiss')
        ->and($html)->not->toContain('Hide activity')
        ->and($html)->not->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
        ->and($html)->not->toContain('role="progressbar"');
})->group('ops-ux');

it('renders terminal follow-up states with acknowledge instead of dismiss semantics', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'user_id' => (int) $user->getKey(),
        'type' => 'inventory_sync',
        'status' => 'completed',
        'outcome' => 'failed',
        'started_at' => now()->subMinutes(3),
        'completed_at' => now()->subSeconds(6),
    ]);

    $component = Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns');

    $html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
    $pageText = preg_replace('/\s+/', ' ', strip_tags($html));

    expect($component->get('hasActiveRuns'))->toBeFalse()
        ->and($html)->toContain('Operation updates')
        ->and($pageText)->toContain('Recent operation updates that may need review.')
        ->and($pageText)->toContain('Review the operation details before retrying.')
        ->and($html)->toContain('View operation')
        ->and($html)->not->toContain('Review operations')
        ->and($html)->toContain('Acknowledge')
        ->and($html)->not->toContain('Dismiss')
        ->and($html)->not->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
        ->and($html)->not->toContain('role="progressbar"')
        ->and($html)->not->toContain('Hide activity');
})->group('ops-ux');

it('uses a collective primary action when active and terminal follow-up items are both visible', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    $runningRun = OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'user_id' => (int) $user->getKey(),
        'type' => 'inventory_sync',
        'status' => 'running',
        'outcome' => 'pending',
        'started_at' => now()->subMinute(),
    ]);

    OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'user_id' => (int) $user->getKey(),
        'type' => 'inventory_sync',
        'status' => 'completed',
        'outcome' => 'failed',
        'started_at' => now()->subMinutes(3),
        'completed_at' => now()->subSeconds(6),
    ]);

    $component = Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns');

    $html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
    $pageText = preg_replace('/\s+/', ' ', strip_tags($html));

    expect($html)->toContain('Review operations')
        ->and($html)->toContain('Operation updates')
        ->and($pageText)->toContain('Active and recent operation updates that may need review.')
        ->and($html)->not->toContain('View operation')
        ->and($html)->toContain('Acknowledge')
        ->and($html)->not->toContain('Dismiss updates')
        ->and($html)->toContain(OperationRunUrl::index($tenant))
        ->and($html)->not->toContain(OperationRunUrl::view($runningRun, $tenant))
        ->and($pageText)->toContain('Execution failed');
})->group('ops-ux');

it('renders an indeterminate running indicator when processed totals are not trustworthy', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'user_id' => (int) $user->getKey(),
        'type' => 'inventory_sync',
        'status' => 'running',
        'outcome' => 'pending',
        'summary_counts' => [
            'processed' => 4,
        ],
        'started_at' => now()->subMinute(),
    ]);

    $component = Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns');

    $html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
    $pageText = preg_replace('/\s+/', ' ', strip_tags($html));

    expect($html)->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
        ->and($html)->toContain('Active operations')
        ->and($pageText)->toMatch('/Running · .* · Progress details pending\./')
        ->and($html)->not->toContain('role="progressbar"')
        ->and($html)->toContain('View operation')
        ->and($html)->not->toContain('Review operations')
        ->and($html)->toContain('Hide activity');
})->group('ops-ux');

it('shows determinate progress with truthful processed totals and percent when summary counts are valid', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'user_id' => (int) $user->getKey(),
        'type' => 'inventory_sync',
        'status' => 'running',
        'outcome' => 'pending',
        'summary_counts' => [
            'total' => 10,
            'processed' => 4,
        ],
        'started_at' => now()->subWeeks(2),
    ]);

    $component = Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns');

    $html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
    $pageText = preg_replace('/\s+/', ' ', strip_tags($html));

    expect($html)->toContain('role="progressbar"')
        ->and($html)->toContain('aria-valuenow="40"')
        ->and($html)->toContain('Active operations')
        ->and($pageText)->toMatch('/Running · .* · 4 \/ 10 processed \(40%\)/')
        ->and($html)->toContain('View operation')
        ->and($html)->not->toContain('Review operations')
        ->and($html)->not->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
        ->and($html)->not->toContain('Likely stale');
})->group('ops-ux');

it('renders phased fallback progress without inventing a counted percentage', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'user_id' => (int) $user->getKey(),
        'type' => 'baseline_capture',
        'status' => 'running',
        'outcome' => 'pending',
        'summary_counts' => [
            'total' => 10,
            'processed' => 4,
        ],
        'context' => [
            'baseline_capture' => [
                'evidence_capture' => [
                    'requested' => 10,
                    'succeeded' => 3,
                    'skipped' => 1,
                ],
                'resume_token' => 'resume-123',
            ],
        ],
        'started_at' => now()->subMinute(),
    ]);

    $component = Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns');

    $html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
    $pageText = preg_replace('/\s+/', ' ', strip_tags($html));

    expect($html)->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
        ->and($pageText)->toMatch('/Running · .* · Capturing evidence\./')
        ->and($html)->not->toContain('role="progressbar"')
        ->and(strip_tags($html))->not->toContain('processed (');
})->group('ops-ux');

it('renders environment review composite progress from canonical composite metadata without inventing a counted percentage', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'user_id' => (int) $user->getKey(),
        'type' => 'environment.review.compose',
        'status' => 'running',
        'outcome' => 'pending',
        'context' => [
            'progress' => [
                'composite' => [
                    'label' => 'Review composition is aggregating 3 operations.',
                    'operation_count' => 3,
                    'failed_count' => 0,
                    'partial_count' => 0,
                ],
            ],
        ],
        'started_at' => now()->subMinute(),
    ]);

    $component = Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns');

    $html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
    $pageText = preg_replace('/\s+/', ' ', strip_tags($html));

    expect($html)->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
        ->and($pageText)->toMatch('/Running · .* · Review composition is aggregating 3 operations\./')
        ->and($html)->not->toContain('role="progressbar"')
        ->and(strip_tags($html))->not->toContain('processed (');
})->group('ops-ux');

it('renders composite fallback progress without inventing a counted percentage from aggregate counts', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'user_id' => (int) $user->getKey(),
        'type' => 'cross_tenant_promotion.execute',
        'status' => 'running',
        'outcome' => 'pending',
        'summary_counts' => [
            'total' => 10,
            'processed' => 4,
            'operation_count' => 3,
        ],
        'started_at' => now()->subMinute(),
    ]);

    $component = Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns');

    $html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
    $pageText = preg_replace('/\s+/', ' ', strip_tags($html));

    expect($html)->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
        ->and($pageText)->toMatch('/Running · .* · Composite progress pending\./')
        ->and($html)->not->toContain('role="progressbar"')
        ->and(strip_tags($html))->not->toContain('processed (');
})->group('ops-ux');

it('renders an indeterminate queued indicator without fake determinate progress', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'user_id' => (int) $user->getKey(),
        'type' => 'inventory_sync',
        'status' => 'queued',
        'outcome' => 'pending',
        'summary_counts' => [
            'processed' => 4,
        ],
        'created_at' => now()->subSeconds(15),
    ]);

    $component = Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns');

    $html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
    $pageText = preg_replace('/\s+/', ' ', strip_tags($html));

    expect($html)->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
        ->and($html)->toContain('Active operations')
        ->and($pageText)->toContain('Queued · now · Waiting for worker.')
        ->and($html)->not->toContain('aria-valuenow=')
        ->and($html)->toContain('View operation')
        ->and($html)->not->toContain('Review operations')
        ->and($html)->toContain('Hide activity')
        ->and(strip_tags($html))->not->toContain('processed (');
})->group('ops-ux');

it('keeps outcome counters outcome only at the shell host', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'user_id' => (int) $user->getKey(),
        'type' => 'inventory_sync',
        'status' => 'running',
        'outcome' => 'pending',
        'summary_counts' => [
            'succeeded' => 4,
            'failed' => 1,
            'skipped' => 2,
        ],
        'started_at' => now()->subMinute(),
    ]);

    $component = Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns');

    $html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
    $pageText = preg_replace('/\s+/', ' ', strip_tags($html));

    expect($html)->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
        ->and($pageText)->toMatch('/Running · .* · Progress details pending\./')
        ->and($html)->not->toContain('role="progressbar"')
        ->and(strip_tags($html))->not->toContain('processed (');
})->group('ops-ux');

it('keeps the queued status pill on one line for the compact banner layout', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'user_id' => (int) $user->getKey(),
        'type' => 'inventory_sync',
        'status' => 'queued',
        'outcome' => 'pending',
        'created_at' => now()->subSeconds(20),
    ]);

    $component = Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns');

    $html = $component->html();
    preg_match('/class="([^"]+)"[^>]*data-testid="ops-ux-activity-feedback-status-pill"/m', $html, $matches);

    expect($matches[1] ?? '')->toContain('whitespace-nowrap')
        ->and($html)->toContain('Queued for execution');
})->group('ops-ux');

it('renders the activity banner inside the tenant shell instead of before the application chrome', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'user_id' => (int) $user->getKey(),
        'type' => 'inventory_sync',
        'status' => 'running',
        'outcome' => 'pending',
        'started_at' => now()->subMinute(),
    ]);

    $response = $this->actingAs($user)
        ->get(InventoryItemResource::getUrl('index', panel: 'admin', tenant: $tenant));

    $response->assertOk();

    $content = $response->getContent();

    expect(strpos($content, 'ManagedEnvironment-Dashboard'))->toBeLessThan(strpos($content, 'Active operations'))
        ->and($content)->not->toContain('fixed bottom-4 right-4 z-[999999] w-96 space-y-2');
})->group('ops-ux');

it('registers browser-session collapse affordances and run-enqueued reopen wiring for active hints', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'user_id' => (int) $user->getKey(),
        'type' => 'inventory_sync',
        'status' => 'running',
        'outcome' => 'pending',
        'started_at' => now()->subMinute(),
    ]);

    $component = Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns');

    $script = file_get_contents(public_path('js/tenantpilot/ops-ux-progress-widget-poller.js'));

    expect($component->html())->toContain('data-testid="ops-ux-activity-feedback-toggle"')
        ->and($component->html())->toContain('data-testid="ops-ux-activity-feedback-expand"')
        ->and($script)->toContain('sessionStorage')
        ->and($script)->toContain('ops-ux:run-enqueued');
})->group('ops-ux');
