<?php

declare(strict_types=1);

use App\Filament\Resources\AlertDeliveryResource;
use App\Filament\Resources\AlertDeliveryResource\Pages\ListAlertDeliveries;
use App\Filament\Resources\AlertRuleResource;
use App\Models\AlertDelivery;
use App\Models\AlertDestination;
use App\Models\AlertRule;
use App\Models\ManagedEnvironment;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Services\Auth\WorkspaceCapabilityResolver;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Actions\Action;
use Filament\Facades\Filament;
use Livewire\Features\SupportTesting\Testable;
use Livewire\Livewire;

function getAlertDeliveryEmptyStateAction(Testable $component, string $name): ?Action
{
    foreach ($component->instance()->getTable()->getEmptyStateActions() as $action) {
        if ($action instanceof Action && $action->getName() === $name) {
            return $action;
        }
    }

    return null;
}

function getAlertDeliveryHeaderAction(Testable $component, string $name): ?Action
{
    $instance = $component->instance();
    $instance->cacheInteractsWithHeaderActions();

    foreach ($instance->getCachedHeaderActions() as $action) {
        if ($action instanceof Action && $action->getName() === $name) {
            return $action;
        }
    }

    return null;
}

it('lists only deliveries for entitled tenants', function (): void {
    [$user, $tenantA] = createUserWithTenant(role: 'readonly');

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

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

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

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

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

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

    $this->actingAs($user);

    Livewire::test(ListAlertDeliveries::class)
        ->assertCanSeeTableRecords([$tenantADelivery])
        ->assertCanNotSeeTableRecords([$tenantBDelivery]);
});

it('shows a guided empty state on alert deliveries and links to alert rules', function (): void {
    [$user] = createUserWithTenant(role: 'owner');

    $this->actingAs($user);

    $component = Livewire::test(ListAlertDeliveries::class)
        ->assertTableEmptyStateActionsExistInOrder(['view_alert_rules'])
        ->assertSee('No alert deliveries')
        ->assertSee('Deliveries appear automatically when alert rules fire.');

    $table = $component->instance()->getTable();

    expect($table->getEmptyStateHeading())->toBe('No alert deliveries');
    expect($table->getEmptyStateDescription())->toBe('Deliveries appear automatically when alert rules fire.');
    expect($table->getEmptyStateIcon())->toBe('heroicon-o-bell-alert');

    $action = getAlertDeliveryEmptyStateAction($component, 'view_alert_rules');

    expect($action)->not->toBeNull();
    expect($action?->getLabel())->toBe('View alert rules');
    expect($action?->getUrl())->toBe(AlertRuleResource::getUrl(panel: 'admin'));
    expect(getAlertDeliveryHeaderAction($component, 'view_alert_rules'))->toBeNull();
});

it('keeps alert deliveries header-action free after records exist', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

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

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

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

    $this->actingAs($user);

    $component = Livewire::test(ListAlertDeliveries::class)
        ->assertCanSeeTableRecords([$delivery]);

    expect(getAlertDeliveryHeaderAction($component, 'view_alert_rules'))->toBeNull();
});

it('shows quiet origin navigation on alert deliveries when deep-linked from alerts overview', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    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');
});

it('returns 404 when a member from another workspace tries to view a delivery', function (): void {
    [$user] = createUserWithTenant(role: 'owner');

    $otherWorkspace = Workspace::factory()->create();
    $tenant = ManagedEnvironment::factory()->create([
        'workspace_id' => (int) $otherWorkspace->getKey(),
    ]);
    $rule = AlertRule::factory()->create([
        'workspace_id' => (int) $otherWorkspace->getKey(),
    ]);
    $destination = AlertDestination::factory()->create([
        'workspace_id' => (int) $otherWorkspace->getKey(),
    ]);
    $delivery = AlertDelivery::factory()->create([
        'workspace_id' => (int) $otherWorkspace->getKey(),
        'managed_environment_id' => (int) $tenant->getKey(),
        'alert_rule_id' => (int) $rule->getKey(),
        'alert_destination_id' => (int) $destination->getKey(),
    ]);

    $this->actingAs($user)
        ->get(AlertDeliveryResource::getUrl('view', ['record' => $delivery], panel: 'admin'))
        ->assertNotFound();
});

it('returns 403 for members missing alerts view capability on deliveries index', function (): void {
    $workspace = Workspace::factory()->create();
    $user = User::factory()->create();

    WorkspaceMembership::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'user_id' => (int) $user->getKey(),
        'role' => 'readonly',
    ]);

    $resolver = \Mockery::mock(WorkspaceCapabilityResolver::class);
    $resolver->shouldReceive('isMember')->andReturnTrue();
    $resolver->shouldReceive('can')->andReturnFalse();
    app()->instance(WorkspaceCapabilityResolver::class, $resolver);

    session()->put(\App\Support\Workspaces\WorkspaceContext::SESSION_KEY, (int) $workspace->getKey());

    $this->actingAs($user)
        ->get(AlertDeliveryResource::getUrl(panel: 'admin'))
        ->assertForbidden();
});

it('keeps persisted alert delivery filters inside the workspace-wide alert delivery scope', 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;

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

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

    $tenantADelivery = 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,
    ]);

    $tenantBDelivery = 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($tenantA, true);

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

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

it('does not preselect the tenant filter when a tenant context exists on the workspace-wide alert delivery list', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

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

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

it('keeps alert deliveries workspace-wide when only remembered environment context exists', 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;

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

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

    $tenantADelivery = 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,
    ]);

    $tenantBDelivery = 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,
    ]);

    Filament::setTenant(null, true);
    app(WorkspaceContext::class)->rememberLastEnvironmentId($workspaceId, (int) $tenantA->getKey());

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => $workspaceId]);

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