<?php

declare(strict_types=1);

use App\Filament\Resources\AlertDeliveryResource;
use App\Filament\Resources\AlertDeliveryResource\Pages\ListAlertDeliveries;
use App\Models\AlertDelivery;
use App\Models\AlertDestination;
use App\Models\AlertRule;
use App\Models\ManagedEnvironment;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;

uses(RefreshDatabase::class);

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

// ---------------------------------------------------------------------------
// T030 — Deliveries viewer filter coverage (event_type + alert_destination_id)
// ---------------------------------------------------------------------------

it('filters deliveries by event_type', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);

    $workspaceId = (int) session()->get(WorkspaceContext::SESSION_KEY);

    $destination = AlertDestination::factory()->create([
        'workspace_id' => $workspaceId,
        'is_enabled' => true,
    ]);

    $rule = AlertRule::factory()->create([
        'workspace_id' => $workspaceId,
    ]);

    $testDelivery = AlertDelivery::factory()->test()->create([
        'workspace_id' => $workspaceId,
        'alert_destination_id' => $destination->getKey(),
        'status' => AlertDelivery::STATUS_SENT,
    ]);

    $normalDelivery = AlertDelivery::factory()->create([
        'workspace_id' => $workspaceId,
        'managed_environment_id' => $tenant->getKey(),
        'alert_rule_id' => $rule->getKey(),
        'alert_destination_id' => $destination->getKey(),
        'event_type' => 'high_drift',
        'status' => AlertDelivery::STATUS_SENT,
    ]);

    Livewire::test(ListAlertDeliveries::class)
        ->assertCanSeeTableRecords([$testDelivery, $normalDelivery])
        ->filterTable('event_type', AlertDelivery::EVENT_TYPE_TEST)
        ->assertCanSeeTableRecords([$testDelivery])
        ->assertCanNotSeeTableRecords([$normalDelivery]);
});

it('filters deliveries by alert_destination_id', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);

    $workspaceId = (int) session()->get(WorkspaceContext::SESSION_KEY);

    $destinationA = AlertDestination::factory()->create([
        'workspace_id' => $workspaceId,
        'is_enabled' => true,
    ]);

    $destinationB = AlertDestination::factory()->create([
        'workspace_id' => $workspaceId,
        'is_enabled' => true,
    ]);

    $rule = AlertRule::factory()->create([
        'workspace_id' => $workspaceId,
    ]);

    $deliveryA = AlertDelivery::factory()->create([
        'workspace_id' => $workspaceId,
        'managed_environment_id' => $tenant->getKey(),
        'alert_rule_id' => $rule->getKey(),
        'alert_destination_id' => $destinationA->getKey(),
        'status' => AlertDelivery::STATUS_SENT,
    ]);

    $deliveryB = AlertDelivery::factory()->create([
        'workspace_id' => $workspaceId,
        'managed_environment_id' => $tenant->getKey(),
        'alert_rule_id' => $rule->getKey(),
        'alert_destination_id' => $destinationB->getKey(),
        'status' => AlertDelivery::STATUS_SENT,
    ]);

    Livewire::test(ListAlertDeliveries::class)
        ->assertCanSeeTableRecords([$deliveryA, $deliveryB])
        ->filterTable('alert_destination_id', (string) $destinationA->getKey())
        ->assertCanSeeTableRecords([$deliveryA])
        ->assertCanNotSeeTableRecords([$deliveryB]);
});

it('filters deliveries by managed_environment_id for multi-tenant members', function (): void {
    [$user, $tenantA] = createUserWithTenant(role: 'owner');

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

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

    $this->actingAs($user);

    $workspaceId = (int) session()->get(WorkspaceContext::SESSION_KEY);

    $destination = AlertDestination::factory()->create([
        'workspace_id' => $workspaceId,
        'is_enabled' => true,
    ]);

    $rule = AlertRule::factory()->create([
        'workspace_id' => $workspaceId,
    ]);

    $deliveryA = AlertDelivery::factory()->create([
        'workspace_id' => $workspaceId,
        'managed_environment_id' => (int) $tenantA->getKey(),
        'alert_rule_id' => (int) $rule->getKey(),
        'alert_destination_id' => (int) $destination->getKey(),
        'status' => AlertDelivery::STATUS_SENT,
    ]);

    $deliveryB = AlertDelivery::factory()->create([
        'workspace_id' => $workspaceId,
        'managed_environment_id' => (int) $tenantB->getKey(),
        'alert_rule_id' => (int) $rule->getKey(),
        'alert_destination_id' => (int) $destination->getKey(),
        'status' => AlertDelivery::STATUS_SENT,
    ]);

    Livewire::test(ListAlertDeliveries::class)
        ->assertCanSeeTableRecords([$deliveryA, $deliveryB])
        ->filterTable('managed_environment_id', (string) $tenantA->getKey())
        ->assertCanSeeTableRecords([$deliveryA])
        ->assertCanNotSeeTableRecords([$deliveryB]);
});

it('keeps deep-linked delivery filters while surfacing origin context quietly', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    $workspaceId = (int) session()->get(WorkspaceContext::SESSION_KEY);

    $destination = AlertDestination::factory()->create([
        'workspace_id' => $workspaceId,
        'is_enabled' => true,
    ]);

    $rule = AlertRule::factory()->create([
        'workspace_id' => $workspaceId,
    ]);

    $sentDelivery = AlertDelivery::factory()->create([
        'workspace_id' => $workspaceId,
        'managed_environment_id' => (int) $tenant->getKey(),
        'alert_rule_id' => (int) $rule->getKey(),
        'alert_destination_id' => (int) $destination->getKey(),
        'status' => AlertDelivery::STATUS_SENT,
    ]);

    $failedDelivery = AlertDelivery::factory()->create([
        'workspace_id' => $workspaceId,
        'managed_environment_id' => (int) $tenant->getKey(),
        'alert_rule_id' => (int) $rule->getKey(),
        'alert_destination_id' => (int) $destination->getKey(),
        'status' => AlertDelivery::STATUS_FAILED,
    ]);

    Livewire::withQueryParams([
        'nav' => [
            'source_surface' => 'alerts.overview',
            'canonical_route_name' => 'admin.alert-deliveries.index',
            'back_label' => 'Back to alerts',
            'back_url' => \App\Filament\Clusters\Monitoring\AlertsCluster::getUrl(panel: 'admin'),
        ],
    ])
        ->actingAs($user)
        ->test(ListAlertDeliveries::class)
        ->assertActionVisible('operate_hub_back_to_origin_alert_deliveries')
        ->filterTable('status', AlertDelivery::STATUS_SENT)
        ->assertCanSeeTableRecords([$sentDelivery])
        ->assertCanNotSeeTableRecords([$failedDelivery]);
});

it('keeps persisted alert delivery filters tenantless when remembered environment 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');

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

    $destination = AlertDestination::factory()->create([
        'workspace_id' => $workspaceId,
        'is_enabled' => true,
    ]);

    $rule = AlertRule::factory()->create([
        'workspace_id' => $workspaceId,
    ]);

    $deliveryA = AlertDelivery::factory()->create([
        'workspace_id' => $workspaceId,
        'managed_environment_id' => (int) $tenantA->getKey(),
        'alert_rule_id' => (int) $rule->getKey(),
        'alert_destination_id' => (int) $destination->getKey(),
        'status' => AlertDelivery::STATUS_SENT,
    ]);

    $deliveryB = AlertDelivery::factory()->create([
        'workspace_id' => $workspaceId,
        'managed_environment_id' => (int) $tenantB->getKey(),
        'alert_rule_id' => (int) $rule->getKey(),
        'alert_destination_id' => (int) $destination->getKey(),
        'status' => AlertDelivery::STATUS_SENT,
    ]);

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

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

    $component = Livewire::withHeaders(['referer' => AlertDeliveryResource::getUrl(panel: 'admin')])
        ->test(ListAlertDeliveries::class)
        ->filterTable('status', AlertDelivery::STATUS_SENT);

    expect(data_get(session()->get($component->instance()->getTableFiltersSessionKey()), 'managed_environment_id.value'))
        ->toBeNull();
    expect(data_get(session()->get($component->instance()->getTableFiltersSessionKey()), 'status.value'))
        ->toBe(AlertDelivery::STATUS_SENT);

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

    Livewire::withHeaders(['referer' => AlertDeliveryResource::getUrl(panel: 'admin')])
        ->test(ListAlertDeliveries::class)
        ->assertSet('tableFilters.managed_environment_id.value', null)
        ->assertSet('tableFilters.status.value', AlertDelivery::STATUS_SENT)
        ->assertCanSeeTableRecords([$deliveryA, $deliveryB]);
});

it('includes tenantless test deliveries in the list', function (): void {
    [$user] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);

    $workspaceId = (int) session()->get(WorkspaceContext::SESSION_KEY);

    $destination = AlertDestination::factory()->create([
        'workspace_id' => $workspaceId,
        'is_enabled' => true,
    ]);

    $testDelivery = AlertDelivery::factory()->test()->create([
        'workspace_id' => $workspaceId,
        'alert_destination_id' => $destination->getKey(),
        'status' => AlertDelivery::STATUS_SENT,
    ]);

    Livewire::test(ListAlertDeliveries::class)
        ->assertCanSeeTableRecords([$testDelivery]);
});

it('composes status and created date filters for alert deliveries', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);

    $workspaceId = (int) session()->get(WorkspaceContext::SESSION_KEY);

    $destination = AlertDestination::factory()->create([
        'workspace_id' => $workspaceId,
        'is_enabled' => true,
    ]);

    $rule = AlertRule::factory()->create([
        'workspace_id' => $workspaceId,
    ]);

    $matching = AlertDelivery::factory()->create([
        'workspace_id' => $workspaceId,
        'managed_environment_id' => (int) $tenant->getKey(),
        'alert_rule_id' => (int) $rule->getKey(),
        'alert_destination_id' => (int) $destination->getKey(),
        'status' => AlertDelivery::STATUS_SENT,
        'created_at' => now()->subDay(),
    ]);

    $wrongStatus = AlertDelivery::factory()->create([
        'workspace_id' => $workspaceId,
        'managed_environment_id' => (int) $tenant->getKey(),
        'alert_rule_id' => (int) $rule->getKey(),
        'alert_destination_id' => (int) $destination->getKey(),
        'status' => AlertDelivery::STATUS_FAILED,
        'created_at' => now()->subDay(),
    ]);

    $outsideWindow = AlertDelivery::factory()->create([
        'workspace_id' => $workspaceId,
        'managed_environment_id' => (int) $tenant->getKey(),
        'alert_rule_id' => (int) $rule->getKey(),
        'alert_destination_id' => (int) $destination->getKey(),
        'status' => AlertDelivery::STATUS_SENT,
        'created_at' => now()->subDays(10),
    ]);

    $component = Livewire::test(ListAlertDeliveries::class)
        ->filterTable('status', AlertDelivery::STATUS_SENT)
        ->set('tableFilters.created_at.from', now()->subDays(2)->toDateString())
        ->set('tableFilters.created_at.until', now()->toDateString())
        ->assertCanSeeTableRecords([$matching])
        ->assertCanNotSeeTableRecords([$wrongStatus, $outsideWindow]);

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

it('clears alert delivery filters back to the full entitled list', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);

    $workspaceId = (int) session()->get(WorkspaceContext::SESSION_KEY);

    $destination = AlertDestination::factory()->create([
        'workspace_id' => $workspaceId,
        'is_enabled' => true,
    ]);

    $rule = AlertRule::factory()->create([
        'workspace_id' => $workspaceId,
    ]);

    $queued = AlertDelivery::factory()->create([
        'workspace_id' => $workspaceId,
        'managed_environment_id' => (int) $tenant->getKey(),
        'alert_rule_id' => (int) $rule->getKey(),
        'alert_destination_id' => (int) $destination->getKey(),
        'status' => AlertDelivery::STATUS_QUEUED,
        'created_at' => now()->subDays(7),
    ]);

    $sent = AlertDelivery::factory()->create([
        'workspace_id' => $workspaceId,
        'managed_environment_id' => (int) $tenant->getKey(),
        'alert_rule_id' => (int) $rule->getKey(),
        'alert_destination_id' => (int) $destination->getKey(),
        'status' => AlertDelivery::STATUS_SENT,
        'created_at' => now()->subDay(),
    ]);

    $component = Livewire::test(ListAlertDeliveries::class)
        ->filterTable('status', AlertDelivery::STATUS_SENT)
        ->set('tableFilters.created_at.from', now()->subDays(2)->toDateString())
        ->set('tableFilters.created_at.until', now()->toDateString())
        ->assertCanSeeTableRecords([$sent])
        ->assertCanNotSeeTableRecords([$queued]);

    $component
        ->set('tableFilters.status.value', null)
        ->set('tableFilters.created_at.from', null)
        ->set('tableFilters.created_at.until', null)
        ->assertCanSeeTableRecords([$queued, $sent]);
});
