<?php

declare(strict_types=1);

use App\Filament\Pages\Monitoring\Operations;
use App\Models\OperationRun;
use App\Models\Tenant;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
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([
        'tenant_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'type' => 'policy.sync',
    ]);

    Filament::setTenant($tenant, true);

    $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 = 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');

    $matching = OperationRun::factory()->create([
        'tenant_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([
        'tenant_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([
        'tenant_id' => (int) $tenantB->getKey(),
        'workspace_id' => (int) $tenantB->workspace_id,
        'type' => 'policy.sync',
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Succeeded->value,
    ]);

    Filament::setTenant($tenantA, true);
    $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([
        'tenant_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'created_at' => now()->subDay(),
    ]);

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

    Filament::setTenant($tenant, true);
    $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]);
});
