<?php

declare(strict_types=1);

use App\Filament\Resources\ManagedEnvironmentResource;
use App\Models\ManagedEnvironment;
use App\Services\Tenants\TenantActionPolicySurface;
use App\Support\Tenants\TenantActionSurface;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

it('does not expose archive as a lifecycle action for draft and onboarding tenants', function (\Closure $tenantFactory): void {
    $tenant = $tenantFactory();

    expect(app(TenantActionPolicySurface::class)->lifecycleActionForTenant($tenant))
        ->toBeNull();
})->with([
    'draft' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->draft()->create()],
    'onboarding' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->onboarding()->create()],
]);

it('returns archive only for active tenants and restore only for archived tenants', function (
    \Closure $tenantFactory,
    string $expectedKey,
    string $expectedLabel,
): void {
    $tenant = $tenantFactory();
    $descriptor = app(TenantActionPolicySurface::class)->lifecycleActionForTenant($tenant);

    expect($descriptor)
        ->not->toBeNull()
        ->and($descriptor?->key)->toBe($expectedKey)
        ->and($descriptor?->label)->toBe($expectedLabel)
        ->and($descriptor?->requiresConfirmation)->toBeTrue();
})->with([
    'active' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->active()->create(), 'archive', 'Archive'],
    'archived' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->archived()->create(), 'restore', 'Restore'],
]);

it('returns resume onboarding as the primary action for draft and onboarding tenants with resumable drafts', function (\Closure $tenantFactory): void {
    $tenant = $tenantFactory();
    [$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,
        ],
    ]);

    $catalog = tenantActionCatalog($tenant, TenantActionSurface::TenantIndexRow, $user);

    expect(tenantActionKeys($catalog))
        ->toBe(['view', 'related_onboarding'])
        ->and($catalog[1]->label)->toBe('Resume onboarding');
})->with([
    'draft' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->draft()->create()],
    'onboarding' => [fn (): ManagedEnvironment => ManagedEnvironment::factory()->onboarding()->create()],
]);

it('keeps completed onboarding as a view-only overflow action for active tenants', 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,
        ],
    ]);

    $catalog = tenantActionCatalog($tenant, TenantActionSurface::TenantIndexRow, $user);

    expect(tenantActionKeys($catalog))
        ->toBe(['view', 'archive', 'related_onboarding'])
        ->and($catalog[2]->label)->toBe('View completed onboarding');
});

it('keeps tenant index catalogs within the clickable-row overflow contract', 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,
        ],
    ]);

    $catalog = tenantActionCatalog($tenant, TenantActionSurface::TenantIndexRow, $user);

    $primaryKeys = collect($catalog)
        ->filter(static fn ($action): bool => $action->group === 'primary')
        ->map(static fn ($action): string => $action->key)
        ->values()
        ->all();

    $inspectKeys = collect($catalog)
        ->filter(static fn ($action): bool => $action->group === 'inspect')
        ->map(static fn ($action): string => $action->key)
        ->values()
        ->all();

    $overflowKeys = collect($catalog)
        ->filter(static fn ($action): bool => $action->group === 'overflow')
        ->map(static fn ($action): string => $action->key)
        ->values()
        ->all();

    expect($inspectKeys)->toBe(['view'])
        ->and($primaryKeys)->toBe(['archive'])
        ->and($overflowKeys)->toBe(['related_onboarding'])
        ->and(ManagedEnvironmentResource::actionSurfaceDeclaration()->listRowPrimaryActionLimit())->toBe(1);
});

it('invalidates cached tenant index catalogs when the related onboarding draft lifecycle changes', function (): void {
    $tenant = ManagedEnvironment::factory()->active()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner', ensureDefaultMicrosoftProviderConnection: false);

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

    $initialCatalog = tenantActionCatalog($tenant, TenantActionSurface::TenantIndexRow, $user);

    expect(tenantActionKeys($initialCatalog))->toBe(['view', 'archive', 'related_onboarding'])
        ->and($initialCatalog[2]->group)->toBe('overflow')
        ->and($initialCatalog[2]->label)->toBe('View related onboarding');

    $draft->forceFill([
        'completed_at' => now()->addSecond(),
        'lifecycle_state' => 'completed',
        'updated_at' => now()->addSecond(),
    ])->save();

    $tenant->refresh();

    $updatedCatalog = tenantActionCatalog($tenant, TenantActionSurface::TenantIndexRow, $user);

    expect(tenantActionKeys($updatedCatalog))->toBe(['view', 'archive', 'related_onboarding'])
        ->and($updatedCatalog[2]->group)->toBe('overflow')
        ->and($updatedCatalog[2]->label)->toBe('View completed onboarding');
});

it('uses workflow-accurate onboarding entry labels', function (int $draftCount, string $expectedLabel): void {
    $descriptor = app(TenantActionPolicySurface::class)->onboardingEntryDescriptor($draftCount);

    expect($descriptor->label)->toBe($expectedLabel);
})->with([
    'no drafts' => [0, 'Add environment'],
    'one draft' => [1, 'Resume onboarding'],
    'multiple drafts' => [2, 'Choose onboarding draft'],
]);
