<?php

declare(strict_types=1);

use App\Models\OperationRun;
use App\Models\ProviderConnection;
use App\Models\ManagedEnvironment;
use App\Services\Onboarding\OnboardingDraftStageResolver;
use App\Support\Onboarding\OnboardingDraftStage;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

it('derives the identify stage when no confirmed tenant identity exists', function (): void {
    $draft = createOnboardingDraft([
        'entra_tenant_id' => '',
        'managed_environment_id' => null,
        'state' => [],
    ]);

    expect(app(OnboardingDraftStageResolver::class)->resolve($draft))
        ->toBe(OnboardingDraftStage::Identify);
});

it('derives the connect provider stage once tenant identity exists', function (): void {
    $draft = createOnboardingDraft([
        'state' => [
            'entra_tenant_id' => '11111111-1111-1111-1111-111111111111',
            'environment_name' => 'Contoso',
        ],
    ]);

    expect(app(OnboardingDraftStageResolver::class)->resolve($draft))
        ->toBe(OnboardingDraftStage::ConnectProvider);
});

it('derives the verify access stage when a provider connection is selected but verification is incomplete', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    $connection = ProviderConnection::factory()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
    ]);

    $draft = createOnboardingDraft([
        'workspace' => $tenant->workspace,
        'tenant' => $tenant,
        'current_step' => 'connection',
        'state' => [
            'entra_tenant_id' => (string) $tenant->managed_environment_id,
            'environment_name' => (string) $tenant->name,
            'provider_connection_id' => (int) $connection->getKey(),
        ],
    ]);

    expect(app(OnboardingDraftStageResolver::class)->resolve($draft))
        ->toBe(OnboardingDraftStage::VerifyAccess);
});

it('derives the connect provider stage when the persisted provider connection no longer exists', function (): void {
    $draft = createOnboardingDraft([
        'current_step' => 'verify',
        'state' => [
            'entra_tenant_id' => '22222222-2222-2222-2222-222222222222',
            'environment_name' => 'Contoso',
            'provider_connection_id' => 42,
        ],
    ]);

    expect(app(OnboardingDraftStageResolver::class)->resolve($draft))
        ->toBe(OnboardingDraftStage::ConnectProvider);
});

it('derives the review stage when verification completed for the selected provider connection', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    $connection = ProviderConnection::factory()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
    ]);

    $draft = createOnboardingDraft([
        'workspace' => $tenant->workspace,
        'tenant' => $tenant,
        'current_step' => 'verify',
        'state' => [
            'entra_tenant_id' => (string) $tenant->managed_environment_id,
            'environment_name' => (string) $tenant->name,
            'provider_connection_id' => (int) $connection->getKey(),
        ],
    ]);

    $run = OperationRun::factory()->create([
        'workspace_id' => (int) $draft->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Succeeded->value,
        'context' => [
            'provider_connection_id' => (int) $connection->getKey(),
        ],
    ]);

    $draft->forceFill([
        'state' => array_merge($draft->state ?? [], [
            'verification_operation_run_id' => (int) $run->getKey(),
        ]),
    ])->save();

    expect(app(OnboardingDraftStageResolver::class)->resolve($draft->fresh()))
        ->toBe(OnboardingDraftStage::Review);
});

it('derives the bootstrap stage when bootstrap choices were already selected but not completed', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    $connection = ProviderConnection::factory()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
    ]);

    $draft = createOnboardingDraft([
        'workspace' => $tenant->workspace,
        'tenant' => $tenant,
        'current_step' => 'bootstrap',
        'state' => [
            'entra_tenant_id' => (string) $tenant->managed_environment_id,
            'environment_name' => (string) $tenant->name,
            'provider_connection_id' => (int) $connection->getKey(),
            'bootstrap_operation_types' => ['inventory_sync'],
        ],
    ]);

    $run = OperationRun::factory()->create([
        'workspace_id' => (int) $draft->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Succeeded->value,
        'context' => [
            'provider_connection_id' => (int) $connection->getKey(),
        ],
    ]);

    $draft->forceFill([
        'state' => array_merge($draft->state ?? [], [
            'verification_operation_run_id' => (int) $run->getKey(),
        ]),
    ])->save();

    expect(app(OnboardingDraftStageResolver::class)->resolve($draft->fresh()))
        ->toBe(OnboardingDraftStage::Bootstrap);
});

it('derives terminal stages from draft lifecycle state', function (string $status, OnboardingDraftStage $expectedStage): void {
    $draft = createOnboardingDraft([
        'status' => $status,
    ]);

    expect(app(OnboardingDraftStageResolver::class)->resolve($draft))
        ->toBe($expectedStage);
})->with([
    ['completed', OnboardingDraftStage::Completed],
    ['cancelled', OnboardingDraftStage::Cancelled],
]);
