<?php

declare(strict_types=1);

use App\Filament\Pages\Monitoring\Operations;
use App\Models\OperationRun;
use App\Models\Tenant;
use App\Support\OperationRunLinks;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
use Livewire\Livewire;

it('preserves tenant context and healthy activity semantics for dashboard operations drill-throughs', function (): void {
    $tenantA = Tenant::factory()->create();
    [$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'owner');

    $tenantB = Tenant::factory()->create([
        'workspace_id' => (int) $tenantA->workspace_id,
    ]);
    createUserWithTenant(tenant: $tenantB, user: $user, role: 'owner');

    $healthyActive = OperationRun::factory()->create([
        'tenant_id' => (int) $tenantA->getKey(),
        'workspace_id' => (int) $tenantA->workspace_id,
        'type' => 'inventory_sync',
        'status' => OperationRunStatus::Running->value,
        'outcome' => OperationRunOutcome::Pending->value,
        'created_at' => now()->subMinute(),
        'started_at' => now()->subMinute(),
    ]);

    $staleActive = OperationRun::factory()->create([
        'tenant_id' => (int) $tenantA->getKey(),
        'workspace_id' => (int) $tenantA->workspace_id,
        'type' => 'inventory_sync',
        'status' => OperationRunStatus::Queued->value,
        'outcome' => OperationRunOutcome::Pending->value,
        'created_at' => now()->subHour(),
    ]);

    $otherTenantActive = OperationRun::factory()->create([
        'tenant_id' => (int) $tenantB->getKey(),
        'workspace_id' => (int) $tenantB->workspace_id,
        'type' => 'inventory_sync',
        'status' => OperationRunStatus::Running->value,
        'outcome' => OperationRunOutcome::Pending->value,
        'created_at' => now()->subMinute(),
        'started_at' => now()->subMinute(),
    ]);

    $this->actingAs($user);
    Filament::setTenant($tenantA, true);
    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id);

    Livewire::withQueryParams([
        'tenant_id' => (string) $tenantA->getKey(),
        'activeTab' => 'active',
    ])
        ->actingAs($user)
        ->test(Operations::class)
        ->assertSet('tableFilters.tenant_id.value', (string) $tenantA->getKey())
        ->assertSet('activeTab', 'active')
        ->assertCanSeeTableRecords([$healthyActive])
        ->assertCanNotSeeTableRecords([$staleActive, $otherTenantActive]);
});

it('uses the stale-attention dashboard landing for likely stale active runs', function (): void {
    $tenantA = Tenant::factory()->create();
    [$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'owner');

    $tenantB = Tenant::factory()->create([
        'workspace_id' => (int) $tenantA->workspace_id,
    ]);
    createUserWithTenant(tenant: $tenantB, user: $user, role: 'owner');

    $staleRun = OperationRun::factory()->create([
        'tenant_id' => (int) $tenantA->getKey(),
        'workspace_id' => (int) $tenantA->workspace_id,
        'type' => 'inventory_sync',
        'status' => OperationRunStatus::Queued->value,
        'outcome' => OperationRunOutcome::Pending->value,
        'created_at' => now()->subHour(),
    ]);

    $terminalRun = OperationRun::factory()->create([
        'tenant_id' => (int) $tenantA->getKey(),
        'workspace_id' => (int) $tenantA->workspace_id,
        'type' => 'policy.sync',
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Failed->value,
    ]);

    $otherTenantStale = OperationRun::factory()->create([
        'tenant_id' => (int) $tenantB->getKey(),
        'workspace_id' => (int) $tenantB->workspace_id,
        'type' => 'inventory_sync',
        'status' => OperationRunStatus::Queued->value,
        'outcome' => OperationRunOutcome::Pending->value,
        'created_at' => now()->subHour(),
    ]);

    $this->actingAs($user);
    Filament::setTenant($tenantA, true);
    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id);

    Livewire::withQueryParams([
        'tenant_id' => (string) $tenantA->getKey(),
        'activeTab' => OperationRun::PROBLEM_CLASS_ACTIVE_STALE_ATTENTION,
        'problemClass' => OperationRun::PROBLEM_CLASS_ACTIVE_STALE_ATTENTION,
    ])
        ->actingAs($user)
        ->test(Operations::class)
        ->assertSet('tableFilters.tenant_id.value', (string) $tenantA->getKey())
        ->assertSet('activeTab', OperationRun::PROBLEM_CLASS_ACTIVE_STALE_ATTENTION)
        ->assertCanSeeTableRecords([$staleRun])
        ->assertCanNotSeeTableRecords([$terminalRun, $otherTenantStale]);
});

it('uses the terminal follow-up landing for failed, warning, and blocked runs without mixing in stale active work', function (): void {
    $tenantA = Tenant::factory()->create();
    [$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'owner');

    $tenantB = Tenant::factory()->create([
        'workspace_id' => (int) $tenantA->workspace_id,
    ]);
    createUserWithTenant(tenant: $tenantB, user: $user, role: 'owner');

    $partialRun = OperationRun::factory()->create([
        'tenant_id' => (int) $tenantA->getKey(),
        'workspace_id' => (int) $tenantA->workspace_id,
        'type' => 'policy.sync',
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::PartiallySucceeded->value,
    ]);

    $failedRun = OperationRun::factory()->create([
        'tenant_id' => (int) $tenantA->getKey(),
        'workspace_id' => (int) $tenantA->workspace_id,
        'type' => 'policy.sync',
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Failed->value,
    ]);

    $blockedRun = OperationRun::factory()->create([
        'tenant_id' => (int) $tenantA->getKey(),
        'workspace_id' => (int) $tenantA->workspace_id,
        'type' => 'policy.sync',
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Blocked->value,
    ]);

    $staleRun = OperationRun::factory()->create([
        'tenant_id' => (int) $tenantA->getKey(),
        'workspace_id' => (int) $tenantA->workspace_id,
        'type' => 'inventory_sync',
        'status' => OperationRunStatus::Queued->value,
        'outcome' => OperationRunOutcome::Pending->value,
        'created_at' => now()->subHour(),
    ]);

    $healthyActive = OperationRun::factory()->create([
        'tenant_id' => (int) $tenantA->getKey(),
        'workspace_id' => (int) $tenantA->workspace_id,
        'type' => 'inventory_sync',
        'status' => OperationRunStatus::Queued->value,
        'outcome' => OperationRunOutcome::Pending->value,
        'created_at' => now()->subMinute(),
    ]);

    $otherTenantFailed = OperationRun::factory()->create([
        'tenant_id' => (int) $tenantB->getKey(),
        'workspace_id' => (int) $tenantB->workspace_id,
        'type' => 'policy.sync',
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Failed->value,
    ]);

    $this->actingAs($user);
    Filament::setTenant($tenantA, true);
    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id);

    Livewire::withQueryParams([
        'tenant_id' => (string) $tenantA->getKey(),
        'activeTab' => OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP,
        'problemClass' => OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP,
    ])
        ->actingAs($user)
        ->test(Operations::class)
        ->assertSet('tableFilters.tenant_id.value', (string) $tenantA->getKey())
        ->assertSet('activeTab', OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP)
        ->assertCanSeeTableRecords([$partialRun, $failedRun, $blockedRun])
        ->assertCanNotSeeTableRecords([$healthyActive, $otherTenantFailed]);
});

it('allows workspace-originated operations drill-through to clear tenant context and show workspace-wide terminal follow-up', function (): void {
    $tenantA = Tenant::factory()->create();
    [$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'owner');

    $tenantB = Tenant::factory()->create([
        'workspace_id' => (int) $tenantA->workspace_id,
    ]);
    createUserWithTenant(tenant: $tenantB, user: $user, role: 'owner');

    $workspaceRun = OperationRun::factory()->tenantlessForWorkspace($tenantA->workspace()->firstOrFail())->create([
        'type' => 'policy.sync',
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Failed->value,
    ]);

    $otherTenantFailed = OperationRun::factory()->create([
        'tenant_id' => (int) $tenantB->getKey(),
        'workspace_id' => (int) $tenantB->workspace_id,
        'type' => 'policy.sync',
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Failed->value,
    ]);

    $healthyActive = OperationRun::factory()->create([
        'tenant_id' => (int) $tenantA->getKey(),
        'workspace_id' => (int) $tenantA->workspace_id,
        'type' => 'inventory_sync',
        'status' => OperationRunStatus::Running->value,
        'outcome' => OperationRunOutcome::Pending->value,
        'created_at' => now()->subMinute(),
        'started_at' => now()->subMinute(),
    ]);

    $this->actingAs($user);
    Filament::setTenant($tenantA, true);
    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id);

    Livewire::withQueryParams([
        'tenant_scope' => 'all',
        'activeTab' => OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP,
        'problemClass' => OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP,
    ])
        ->actingAs($user)
        ->test(Operations::class)
        ->assertSet('tableFilters.tenant_id.value', null)
        ->assertSet('activeTab', OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP)
        ->assertCanSeeTableRecords([$workspaceRun, $otherTenantFailed])
        ->assertCanNotSeeTableRecords([$healthyActive]);
});

it('builds canonical dashboard operations URLs with tenant and tab continuity', function (): void {
    $tenant = Tenant::factory()->create();

    expect(OperationRunLinks::index($tenant, activeTab: 'active'))
        ->toBe(route('admin.operations.index', [
            'tenant_id' => (int) $tenant->getKey(),
            'activeTab' => 'active',
        ]))
        ->and(OperationRunLinks::index(
            $tenant,
            activeTab: OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP,
            problemClass: OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP,
        ))
        ->toBe(route('admin.operations.index', [
            'tenant_id' => (int) $tenant->getKey(),
            'activeTab' => OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP,
            'problemClass' => OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP,
        ]))
        ->and(OperationRunLinks::index(
            activeTab: OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP,
            allTenants: true,
            problemClass: OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP,
        ))
        ->toBe(route('admin.operations.index', [
            'tenant_scope' => 'all',
            'activeTab' => OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP,
            'problemClass' => OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP,
        ]));
});

it('ignores unauthorized requested tenant filters while keeping canonical tab continuity', function (): void {
    $tenantA = Tenant::factory()->create();
    [$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'owner');

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

    OperationRun::factory()->create([
        'tenant_id' => (int) $tenantA->getKey(),
        'workspace_id' => (int) $tenantA->workspace_id,
        'type' => 'inventory_sync',
        'status' => OperationRunStatus::Running->value,
        'outcome' => OperationRunOutcome::Pending->value,
        'created_at' => now()->subMinute(),
        'started_at' => now()->subMinute(),
    ]);

    $this->actingAs($user);
    Filament::setTenant($tenantA, true);
    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id);

    $component = Livewire::withQueryParams([
        'tenant_id' => (string) $foreignTenant->getKey(),
        'activeTab' => 'active',
    ])
        ->actingAs($user)
        ->test(Operations::class)
        ->assertSet('tableFilters.tenant_id.value', (string) $tenantA->getKey())
        ->assertSet('activeTab', 'active');

    expect(urldecode($component->instance()->tabUrl(OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP)))
        ->toContain('activeTab='.OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP)
        ->toContain('problemClass='.OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP)
        ->not->toContain('tenant_id='.(int) $foreignTenant->getKey());
});
