<?php

declare(strict_types=1);

use App\Filament\Pages\Monitoring\Operations;
use App\Models\ManagedEnvironment;
use App\Models\OperationRun;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Tables\Filters\SelectFilter;
use Livewire\Livewire;

function operationRunFilterIndicatorLabels($component): array
{
    return collect($component->instance()->getTable()->getFilterIndicators())
        ->map(fn ($indicator): string => (string) $indicator->getLabel())
        ->all();
}

it('maps the operation type filter to operation catalog labels', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    setAdminPanelContext($tenant);

    $component = Livewire::actingAs($user)
        ->test(Operations::class)
        ->assertTableFilterExists('type');

    /** @var SelectFilter|null $filter */
    $filter = $component->instance()->getTable()->getFilter('type');

    expect($filter)->not->toBeNull();
    expect($filter?->getOptions()['policy.sync'] ?? null)->toBe('Policy sync');
});

it('filters operations by type and outcome without leaking runs from other tenants', function (): void {
    $tenantA = ManagedEnvironment::factory()->create();
    [$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'owner');

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

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

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

    $wrongType = OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenantA->getKey(),
        'workspace_id' => (int) $tenantA->workspace_id,
        'type' => 'inventory_sync',
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Succeeded->value,
    ]);

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

    setAdminPanelContext($tenantA);
    $this->withSession([WorkspaceContext::SESSION_KEY => (int) $tenantA->workspace_id]);
    session([WorkspaceContext::SESSION_KEY => (int) $tenantA->workspace_id]);

    Livewire::actingAs($user)
        ->test(Operations::class)
        ->filterTable('type', 'policy.sync')
        ->filterTable('outcome', OperationRunOutcome::Succeeded->value)
        ->assertCanSeeTableRecords([$matching])
        ->assertCanNotSeeTableRecords([$wrongType, $otherTenant]);
});

it('filters operations by created date range and can clear the range', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $recent = OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'created_at' => now()->subDay(),
    ]);

    $old = OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'created_at' => now()->subDays(45),
    ]);

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

    $component = Livewire::actingAs($user)
        ->test(Operations::class)
        ->set('tableFilters.created_at.from', now()->subDays(2)->toDateString())
        ->set('tableFilters.created_at.until', now()->toDateString())
        ->assertCanSeeTableRecords([$recent])
        ->assertCanNotSeeTableRecords([$old]);

    expect(operationRunFilterIndicatorLabels($component))
        ->toContain('Created from '.now()->subDays(2)->toFormattedDateString())
        ->toContain('Created until '.now()->toFormattedDateString());

    $component
        ->set('tableFilters.created_at.from', null)
        ->set('tableFilters.created_at.until', null)
        ->assertCanSeeTableRecords([$recent, $old]);
});

it('keeps operation type filter options workspace-scoped even when a remembered environment is active', function (): void {
    $tenantA = ManagedEnvironment::factory()->create();
    [$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'owner');

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

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

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

    OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenantB->getKey(),
        'workspace_id' => (int) $tenantB->workspace_id,
        'type' => 'inventory_sync',
    ]);

    $this->actingAs($user);
    setAdminPanelContext();

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

    $component = Livewire::test(Operations::class);

    /** @var SelectFilter|null $filter */
    $filter = $component->instance()->getTable()->getFilter('type');

    expect($filter)->not->toBeNull();
    expect($filter?->getOptions())->toBe([
        'inventory.sync' => 'Inventory sync',
        'policy.sync' => 'Policy sync',
    ]);
});

it('filters legacy and provider-prefixed inventory runs through one canonical operation selection', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $legacyRun = OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'type' => 'inventory_sync',
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Succeeded->value,
    ]);

    $providerPrefixedRun = OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'type' => 'provider.inventory.sync',
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Succeeded->value,
    ]);

    $otherRun = OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'type' => 'policy.sync',
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Succeeded->value,
    ]);

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

    Livewire::actingAs($user)
        ->test(Operations::class)
        ->filterTable('type', 'inventory.sync')
        ->assertCanSeeTableRecords([$legacyRun, $providerPrefixedRun])
        ->assertCanNotSeeTableRecords([$otherRun]);
});

it('shows one canonical operation filter option for current and historical inventory values', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    foreach (['inventory.sync', 'inventory_sync', 'provider.inventory.sync'] as $type) {
        OperationRun::factory()->create([
            'managed_environment_id' => (int) $tenant->getKey(),
            'workspace_id' => (int) $tenant->workspace_id,
            'type' => $type,
        ]);
    }

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

    $component = Livewire::actingAs($user)
        ->test(Operations::class);

    /** @var SelectFilter|null $filter */
    $filter = $component->instance()->getTable()->getFilter('type');

    expect($filter)->not->toBeNull();
    expect($filter?->getOptions())->toBe([
        'inventory.sync' => 'Inventory sync',
    ]);
});

it('clears tenant-sensitive persisted filters when the canonical tenant context changes', function (): void {
    $tenantA = ManagedEnvironment::factory()->create();
    [$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'owner');

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

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

    OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenantA->getKey(),
        'workspace_id' => (int) $tenantA->workspace_id,
        'type' => 'policy.sync',
        'initiator_name' => 'Alpha',
    ]);

    OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenantB->getKey(),
        'workspace_id' => (int) $tenantB->workspace_id,
        'type' => 'inventory_sync',
        'initiator_name' => 'Bravo',
    ]);

    $this->actingAs($user);
    setAdminPanelContext();

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

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

    $component = Livewire::test(Operations::class)
        ->filterTable('type', 'policy.sync')
        ->filterTable('initiator_name', 'Alpha');

    expect(data_get(session()->get($component->instance()->getTableFiltersSessionKey()), 'type.value'))->toBe('policy.sync');
    expect(data_get(session()->get($component->instance()->getTableFiltersSessionKey()), 'initiator_name.value'))->toBe('Alpha');

    session()->put(WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY, [
        (string) $workspaceId => (int) $tenantB->getKey(),
    ]);

    Livewire::test(Operations::class)
        ->assertSet('tableFilters.managed_environment_id.value', (string) $tenantB->getKey())
        ->assertSet('tableFilters.type.value', null)
        ->assertSet('tableFilters.initiator_name.value', null);
});
