<?php

declare(strict_types=1);

use App\Filament\Resources\ManagedEnvironmentResource;
use App\Filament\Resources\ManagedEnvironmentResource\Pages\EditManagedEnvironment;
use App\Filament\Resources\ManagedEnvironmentResource\Pages\ListManagedEnvironments;
use App\Filament\Resources\ManagedEnvironmentResource\Pages\ViewManagedEnvironment;
use App\Models\ManagedEnvironment;
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceSlot;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Actions\ActionGroup;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;

uses(RefreshDatabase::class);

function tenantActionSurfaceSearchTitles($results): array
{
    return collect($results)->map(fn ($result): string => (string) $result->title)->values()->all();
}

it('keeps onboarding lifecycle actions consistent across list, view, and edit surfaces', function (): void {
    $tenant = ManagedEnvironment::factory()->onboarding()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner', ensureDefaultMicrosoftProviderConnection: false);

    createOnboardingDraft([
        'workspace' => $tenant->workspace,
        'tenant' => $tenant,
        'started_by' => $user,
        'updated_by' => $user,
        'state' => [
            'entra_tenant_id' => (string) $tenant->managed_environment_id,
            'tenant_name' => (string) $tenant->name,
        ],
    ]);

    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);

    Livewire::actingAs($user)
        ->test(ListManagedEnvironments::class)
        ->assertTableActionVisible('related_onboarding', $tenant)
        ->assertTableActionHidden('archive', $tenant)
        ->assertTableActionHidden('restore', $tenant);

    Filament::setTenant(null, true);

    Livewire::actingAs($user)
        ->test(ViewManagedEnvironment::class, ['record' => $tenant->getRouteKey()])
        ->assertActionHidden('archive')
        ->assertActionHidden('restore');

    expect(collect(ManagedEnvironmentResource::tenantViewContextEntries($tenant))->pluck('key')->all())
        ->toContain('related_onboarding');

    Livewire::actingAs($user)
        ->test(EditManagedEnvironment::class, ['record' => $tenant->getRouteKey()])
        ->assertActionHidden('archive')
        ->assertActionHidden('restore');

    expect(collect(ManagedEnvironmentResource::tenantEditContextEntries($tenant))->pluck('key')->all())
        ->toContain('related_onboarding');
});

it('keeps active lifecycle actions consistent across list, view, and edit surfaces', function (): void {
    $tenant = ManagedEnvironment::factory()->active()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner', ensureDefaultMicrosoftProviderConnection: false);

    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);

    Livewire::actingAs($user)
        ->test(ListManagedEnvironments::class)
        ->assertTableActionVisible('archive', $tenant)
        ->assertTableActionHidden('restore', $tenant)
        ->assertTableActionHidden('related_onboarding', $tenant);

    Filament::setTenant(null, true);

    Livewire::actingAs($user)
        ->test(ViewManagedEnvironment::class, ['record' => $tenant->getRouteKey()])
        ->assertActionVisible('archive')
        ->assertActionHidden('restore');

    expect(collect(ManagedEnvironmentResource::tenantViewContextEntries($tenant))->pluck('key')->all())
        ->not->toContain('related_onboarding');

    Livewire::actingAs($user)
        ->test(EditManagedEnvironment::class, ['record' => $tenant->getRouteKey()])
        ->assertActionVisible('archive')
        ->assertActionHidden('restore');

    expect(collect(ManagedEnvironmentResource::tenantEditContextEntries($tenant))->pluck('key')->all())
        ->not->toContain('related_onboarding');
});

it('keeps draft lifecycle actions consistent across list, view, and edit surfaces', function (): void {
    $tenant = ManagedEnvironment::factory()->draft()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner', ensureDefaultMicrosoftProviderConnection: false);

    createOnboardingDraft([
        'workspace' => $tenant->workspace,
        'tenant' => $tenant,
        'started_by' => $user,
        'updated_by' => $user,
        'state' => [
            'entra_tenant_id' => (string) $tenant->managed_environment_id,
            'tenant_name' => (string) $tenant->name,
        ],
    ]);

    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);

    Livewire::actingAs($user)
        ->test(ListManagedEnvironments::class)
        ->assertTableActionVisible('related_onboarding', $tenant)
        ->assertTableActionHidden('archive', $tenant)
        ->assertTableActionHidden('restore', $tenant);

    Filament::setTenant(null, true);

    Livewire::actingAs($user)
        ->test(ViewManagedEnvironment::class, ['record' => $tenant->getRouteKey()])
        ->assertActionHidden('archive')
        ->assertActionHidden('restore');

    expect(collect(ManagedEnvironmentResource::tenantViewContextEntries($tenant))->pluck('key')->all())
        ->toContain('related_onboarding');

    Livewire::actingAs($user)
        ->test(EditManagedEnvironment::class, ['record' => $tenant->getRouteKey()])
        ->assertActionHidden('archive')
        ->assertActionHidden('restore');

    expect(collect(ManagedEnvironmentResource::tenantEditContextEntries($tenant))->pluck('key')->all())
        ->toContain('related_onboarding');
});

it('keeps archived lifecycle actions consistent across list, view, and edit surfaces', function (): void {
    $tenant = ManagedEnvironment::factory()->archived()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner', ensureDefaultMicrosoftProviderConnection: false);

    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);

    Livewire::actingAs($user)
        ->test(ListManagedEnvironments::class)
        ->assertTableActionVisible('restore', $tenant)
        ->assertTableActionHidden('archive', $tenant);

    Filament::setTenant(null, true);

    Livewire::actingAs($user)
        ->test(ViewManagedEnvironment::class, ['record' => $tenant->getRouteKey()])
        ->assertActionVisible('restore')
        ->assertActionHidden('archive');

    Livewire::actingAs($user)
        ->test(EditManagedEnvironment::class, ['record' => $tenant->getRouteKey()])
        ->assertActionVisible('restore')
        ->assertActionHidden('archive');
});

it('keeps managed environment registry out of global search across lifecycles', function (): void {
    $active = ManagedEnvironment::factory()->active()->create(['name' => 'Surface Search Active']);
    [$user, $active] = createUserWithTenant(tenant: $active, role: 'owner', ensureDefaultMicrosoftProviderConnection: false);

    $draft = ManagedEnvironment::factory()->draft()->create([
        'workspace_id' => (int) $active->workspace_id,
        'name' => 'Surface Search Draft',
    ]);
    $onboarding = ManagedEnvironment::factory()->onboarding()->create([
        'workspace_id' => (int) $active->workspace_id,
        'name' => 'Surface Search Onboarding',
    ]);
    $archived = ManagedEnvironment::factory()->archived()->create([
        'workspace_id' => (int) $active->workspace_id,
        'name' => 'Surface Search Archived',
    ]);

    createUserWithTenant(tenant: $draft, user: $user, role: 'owner', ensureDefaultMicrosoftProviderConnection: false);
    createUserWithTenant(tenant: $onboarding, user: $user, role: 'owner', ensureDefaultMicrosoftProviderConnection: false);
    createUserWithTenant(tenant: $archived, user: $user, role: 'owner', ensureDefaultMicrosoftProviderConnection: false);

    $this->actingAs($user);

    Filament::setCurrentPanel('admin');
    Filament::setTenant(null, true);
    Filament::bootCurrentPanel();

    session()->put(WorkspaceContext::SESSION_KEY, (int) $active->workspace_id);

    expect(tenantActionSurfaceSearchTitles(ManagedEnvironmentResource::getGlobalSearchResults('Surface Search')))
        ->toBeEmpty()
        ->and(ManagedEnvironmentResource::canGloballySearch())->toBeFalse();
});

it('keeps list-row lifecycle actions independent from the selected header tenant context', function (): void {
    $selectedTenant = ManagedEnvironment::factory()->active()->create(['name' => 'Selected Header ManagedEnvironment']);
    [$user, $selectedTenant] = createUserWithTenant(tenant: $selectedTenant, role: 'owner', ensureDefaultMicrosoftProviderConnection: false);

    $onboardingTenant = ManagedEnvironment::factory()->onboarding()->create([
        'workspace_id' => (int) $selectedTenant->workspace_id,
        'name' => 'Independent Onboarding ManagedEnvironment',
    ]);
    $archivedTenant = ManagedEnvironment::factory()->archived()->create([
        'workspace_id' => (int) $selectedTenant->workspace_id,
        'name' => 'Independent Archived ManagedEnvironment',
    ]);

    createUserWithTenant(tenant: $onboardingTenant, user: $user, role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false);
    createUserWithTenant(tenant: $archivedTenant, user: $user, role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false);

    createOnboardingDraft([
        'workspace' => $onboardingTenant->workspace,
        'tenant' => $onboardingTenant,
        'started_by' => $user,
        'updated_by' => $user,
        'state' => [
            'entra_tenant_id' => (string) $onboardingTenant->managed_environment_id,
            'tenant_name' => (string) $onboardingTenant->name,
        ],
    ]);

    session()->put(WorkspaceContext::SESSION_KEY, (int) $selectedTenant->workspace_id);
    Filament::setTenant($selectedTenant, true);

    Livewire::actingAs($user)
        ->test(ListManagedEnvironments::class)
        ->assertTableActionVisible('archive', $selectedTenant)
        ->assertTableActionVisible('related_onboarding', $onboardingTenant)
        ->assertTableActionHidden('archive', $onboardingTenant)
        ->assertTableActionVisible('restore', $archivedTenant)
        ->assertTableActionHidden('archive', $archivedTenant);
});

it('documents the tenant row-click and More-menu contract for lifecycle actions', function (): void {
    $tenant = ManagedEnvironment::factory()->active()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner', ensureDefaultMicrosoftProviderConnection: false);

    createOnboardingDraft([
        'workspace' => $tenant->workspace,
        'tenant' => $tenant,
        'started_by' => $user,
        'updated_by' => $user,
        'status' => 'completed',
        'state' => [
            'entra_tenant_id' => (string) $tenant->managed_environment_id,
            'tenant_name' => (string) $tenant->name,
        ],
    ]);

    $declaration = ManagedEnvironmentResource::actionSurfaceDeclaration();

    expect($declaration->listRowPrimaryActionLimit())->toBe(1)
        ->and((string) ($declaration->slot(ActionSurfaceSlot::ListRowMoreMenu)?->details ?? ''))->toContain('one');

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

    $component = Livewire::actingAs($user)
        ->test(ListManagedEnvironments::class)
        ->assertTableActionVisible('archive', $tenant)
        ->assertTableActionHidden('related_onboarding', $tenant)
        ->assertTableActionVisible('related_onboarding_overflow', $tenant)
        ->assertTableActionHidden('restore', $tenant);

    $table = $component->instance()->getTable();
    $rowActions = $table->getActions();
    $primaryRowActionNames = collect($rowActions)
        ->reject(static fn ($action): bool => $action instanceof ActionGroup)
        ->map(static fn ($action): ?string => $action->getName())
        ->filter()
        ->values()
        ->all();
    $moreGroup = collect($rowActions)->first(static fn ($action): bool => $action instanceof ActionGroup);
    $moreActionNames = collect($moreGroup?->getActions() ?? [])
        ->map(static fn ($action): ?string => $action->getName())
        ->filter()
        ->values()
        ->all();

    $relatedOnboardingIndex = array_search('related_onboarding_overflow', $moreActionNames, true);
    $archiveIndex = array_search('archive', $moreActionNames, true);

    expect($primaryRowActionNames)->not->toContain('view')
        ->and($table->getRecordUrl($tenant))->toBe(ManagedEnvironmentResource::getUrl('view', ['record' => $tenant]))
        ->and($moreActionNames)->toContain('archive')
        ->and($moreActionNames)->toContain('related_onboarding_overflow')
        ->and($relatedOnboardingIndex)->toBe(0)
        ->and($archiveIndex)->toBe(count($moreActionNames) - 1);
});
