<?php

use App\Livewire\BulkOperationProgress;
use App\Models\OperationRun;
use App\Models\ManagedEnvironment;
use Filament\Facades\Filament;
use Livewire\Livewire;

it('keeps the Ops UX progress widget DB-only (no outbound HTTP) and tenant-scoped', function () {
    $tenantA = ManagedEnvironment::factory()->create();
    $tenantB = ManagedEnvironment::factory()->create();

    [$user] = createUserWithTenant($tenantA, role: 'owner');

    $user->tenants()->syncWithoutDetaching([
        $tenantB->getKey() => ['role' => 'owner'],
    ]);

    OperationRun::factory()->create([
        'managed_environment_id' => $tenantA->getKey(),
        'type' => 'policy.sync',
        'status' => 'running',
        'outcome' => 'pending',
        'initiator_name' => 'TenantA',
    ]);

    OperationRun::factory()->create([
        'managed_environment_id' => $tenantB->getKey(),
        'type' => 'inventory_sync',
        'status' => 'running',
        'outcome' => 'pending',
        'initiator_name' => 'TenantB',
    ]);

    $this->actingAs($user);

    Filament::setTenant($tenantA, true);

    assertNoOutboundHttp(function () {
        Livewire::test(BulkOperationProgress::class)
            ->call('refreshRuns')
            ->assertSet('disabled', false)
            ->assertSee('Policy sync')
            ->assertDontSee('Inventory sync');
    });
})->group('ops-ux');

it('stays inert when no selected tenant context exists', function () {
    [$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,
        'type' => 'inventory_sync',
        'status' => 'running',
        'outcome' => 'pending',
        'started_at' => now()->subMinute(),
    ]);

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

it('keeps queued shell hydration indeterminate even when a planned total exists', function () {
    [$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,
        'type' => 'inventory_sync',
        'status' => 'queued',
        'outcome' => 'pending',
        'summary_counts' => [
            'total' => 10,
            'processed' => 4,
        ],
        'created_at' => now()->subSeconds(20),
    ]);

    Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns')
        ->assertSee('Waiting for worker.')
        ->assertSee('Queued for execution')
        ->assertDontSee('4 / 10 processed (40%)')
        ->assertDontSeeHtml('aria-valuenow=');
})->group('ops-ux');

it('keeps a just-completed successful run visible briefly as terminal success', function () {
    [$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,
        'type' => 'inventory_sync',
        'status' => 'completed',
        'outcome' => 'succeeded',
        'started_at' => now()->subMinutes(2),
        'completed_at' => now()->subSeconds(10),
    ]);

    Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns')
        ->assertSet('hasActiveRuns', false)
        ->assertSee('Operation updates')
        ->assertSee('Inventory sync')
        ->assertSee('View operation')
        ->assertDontSee('Review operations')
        ->assertSee('Completed successfully')
        ->assertSee('No action needed.')
        ->assertSee('Dismiss')
        ->assertDontSee('Waiting for worker.')
        ->assertDontSee('Hide activity');
})->group('ops-ux');

it('keeps unresolved terminal follow-up runs visible instead of dropping them silently', function () {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);
    Filament::setTenant($tenant, true);

    Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->set('tenantId', (int) $tenant->getKey())
        ->call('refreshRuns')
        ->assertSet('hasActiveRuns', false)
        ->assertDontSee('Inventory sync');

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

    Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns')
        ->assertSet('hasActiveRuns', false)
        ->assertSee('Operation updates')
        ->assertSee('Inventory sync')
        ->assertSee('View operation')
        ->assertDontSee('Review operations')
        ->assertSee('Acknowledge')
        ->assertDontSee('Dismiss')
        ->assertDontSee('Waiting for worker.')
        ->assertDontSee('Hide activity');
})->group('ops-ux');

it('uses a collective primary action when multiple shell-visible operation updates are shown', function () {
    [$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,
        '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,
        'type' => 'inventory_sync',
        'status' => 'completed',
        'outcome' => 'failed',
        'started_at' => now()->subMinutes(3),
        'completed_at' => now()->subSeconds(5),
    ]);

    Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns')
        ->assertSet('hasActiveRuns', true)
        ->assertSee('Operation updates')
        ->assertSee('Review operations')
        ->assertDontSee('View operation')
        ->assertSee('Show all operations')
        ->assertSee('Acknowledge')
        ->assertDontSee('Dismiss updates');
})->group('ops-ux');

it('shows likely stale runs in the progress overlay and keeps polling when only stale runs remain', function () {
    [$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,
        'type' => 'inventory_sync',
        'status' => 'queued',
        'outcome' => 'pending',
        'created_at' => now()->subWeeks(2),
        'started_at' => null,
    ]);

    Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns')
        ->assertSet('hasActiveRuns', true)
        ->assertSee('Inventory sync')
        ->assertSee('Likely stale')
        ->assertSee('Waiting for worker.');
})->group('ops-ux');

it('clamps counted progress at the shell host when processed exceeds total', function () {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);
    Filament::setTenant($tenant, true);

    Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->set('tenantId', (int) $tenant->getKey())
        ->call('refreshRuns')
        ->assertDontSee('10 / 10 processed (100%)');

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

    Livewire::actingAs($user)
        ->test(BulkOperationProgress::class)
        ->call('refreshRuns')
        ->assertSee('10 / 10 processed (100%)')
        ->assertDontSee('15 / 10 processed (150%)')
        ->assertSeeHtml('aria-valuenow="100"');
})->group('ops-ux');

it('registers Alpine cleanup for the Ops UX poller to avoid stale listeners across re-renders', function () {
    $contents = file_get_contents(resource_path('views/livewire/bulk-operation-progress.blade.php'));

    expect($contents)->toContain('new MutationObserver');
    expect($contents)->toContain('teardownObserver');
    expect($contents)->toContain('wire:poll.10s="refreshRuns"');
    expect($contents)->not->toContain('wire:poll.5s="refreshRuns"');
})->group('ops-ux');
