<?php

use App\Models\ProviderConnection;
use App\Models\ManagedEnvironment;
use App\Models\ManagedEnvironmentOnboardingSession;
use App\Models\Workspace;
use App\Models\OperationRun;
use App\Support\ManagedEnvironmentLinks;
use App\Support\Providers\ProviderReasonCodes;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

it('stores successful admin consent on provider connection canonical state', function () {
    $tenant = ManagedEnvironment::factory()->create([
        'managed_environment_id' => 'tenant-1',
        'name' => 'Contoso',
    ]);

    $response = $this->get(route('admin.consent.callback', [
        'tenant' => $tenant->managed_environment_id,
        'admin_consent' => 'true',
    ]));

    $response->assertOk();
    $response->assertSeeText('Verification state:');
    $response->assertSeeText('Needs verification');
    $response->assertSee(
        ManagedEnvironmentLinks::viewUrl($tenant),
        false,
    );

    $connection = ProviderConnection::query()
        ->where('managed_environment_id', (int) $tenant->getKey())
        ->where('provider', 'microsoft')
        ->where('entra_tenant_id', $tenant->graphTenantId())
        ->first();

    expect($connection)->not->toBeNull()
        ->and($connection?->is_enabled)->toBeTrue()
        ->and($connection?->consent_status?->value ?? $connection?->consent_status)->toBe('granted')
        ->and($connection?->verification_status?->value ?? $connection?->verification_status)->toBe('unknown')
        ->and($connection?->last_error_reason_code)->toBeNull();

    $this->assertDatabaseHas('audit_logs', [
        'managed_environment_id' => $tenant->id,
        'action' => 'tenant.consent.callback',
        'status' => 'success',
    ]);
});

it('links back to onboarding when tenant is onboarding', function () {
    $tenant = ManagedEnvironment::factory()->create([
        'managed_environment_id' => 'tenant-3',
        'name' => 'Onboarding ManagedEnvironment',
        'status' => ManagedEnvironment::STATUS_ONBOARDING,
    ]);

    $response = $this->get(route('admin.consent.callback', [
        'tenant' => $tenant->managed_environment_id,
        'admin_consent' => 'true',
    ]));

    $response->assertOk();
    $response->assertSee(route('admin.onboarding'), false);
});

it('invalidates resumable onboarding verification state for the same platform connection after a successful callback', function () {
    $tenant = ManagedEnvironment::factory()->create([
        'managed_environment_id' => 'tenant-verify-reset',
        'name' => 'Reset ManagedEnvironment',
        'status' => ManagedEnvironment::STATUS_ONBOARDING,
    ]);

    $connection = ProviderConnection::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'provider' => 'microsoft',
        'entra_tenant_id' => (string) $tenant->managed_environment_id,
        'is_default' => true,
    ]);

    $run = OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'type' => 'provider.connection.check',
    ]);

    $draft = ManagedEnvironmentOnboardingSession::query()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'entra_tenant_id' => (string) $tenant->managed_environment_id,
        'current_step' => 'verify',
        'state' => [
            'provider_connection_id' => (int) $connection->getKey(),
            'verification_operation_run_id' => (int) $run->getKey(),
            'verification_run_id' => (int) $run->getKey(),
            'bootstrap_operation_runs' => [123, 456],
            'bootstrap_operation_types' => ['inventory_sync'],
            'bootstrap_run_ids' => [123, 456],
        ],
    ]);

    $this->get(route('admin.consent.callback', [
        'tenant' => $tenant->managed_environment_id,
        'admin_consent' => 'true',
    ]))->assertOk();

    $draft->refresh();

    expect($draft->state['verification_operation_run_id'] ?? null)->toBeNull()
        ->and($draft->state['verification_run_id'] ?? null)->toBeNull()
        ->and($draft->state['bootstrap_operation_runs'] ?? null)->toBeNull()
        ->and($draft->state['bootstrap_operation_types'] ?? null)->toBeNull()
        ->and($draft->state['bootstrap_run_ids'] ?? null)->toBeNull()
        ->and($draft->state['connection_recently_updated'] ?? null)->toBeTrue();
});

it('creates tenant and provider connection when callback tenant does not exist', function () {
    $workspace = Workspace::factory()->create();

    $response = $this->withSession([
        'environment_onboard_workspace_id' => (int) $workspace->getKey(),
        'environment_onboard_state' => 'state-456',
    ])->get(route('admin.consent.callback', [
        'tenant' => 'new-tenant',
        'state' => 'state-456',
    ]));

    $response->assertOk();

    $tenant = ManagedEnvironment::query()->forTenant('new-tenant')->first();
    expect($tenant)->not->toBeNull();

    $connection = ProviderConnection::query()
        ->where('managed_environment_id', (int) $tenant->id)
        ->where('provider', 'microsoft')
        ->where('entra_tenant_id', $tenant->graphTenantId())
        ->first();

    expect($connection)->not->toBeNull()
        ->and($connection?->is_enabled)->toBeTrue()
        ->and($connection?->consent_status?->value ?? $connection?->consent_status)->toBe('required')
        ->and($connection?->verification_status?->value ?? $connection?->verification_status)->toBe('unknown')
        ->and($connection?->last_error_reason_code)->toBe(ProviderReasonCodes::ProviderConsentMissing);
});

it('records consent callback errors on provider connection canonical state', function () {
    $tenant = ManagedEnvironment::factory()->create([
        'managed_environment_id' => 'tenant-2',
        'name' => 'Fabrikam',
    ]);

    $response = $this->get(route('admin.consent.callback', [
        'tenant' => $tenant->managed_environment_id,
        'error' => 'access_denied',
    ]));

    $response->assertOk();
    $response->assertSeeText('Verification state:');
    $response->assertSeeText('Not verified');

    $connection = ProviderConnection::query()
        ->where('managed_environment_id', (int) $tenant->getKey())
        ->where('provider', 'microsoft')
        ->where('entra_tenant_id', $tenant->graphTenantId())
        ->first();

    expect($connection)->not->toBeNull()
        ->and($connection?->is_enabled)->toBeTrue()
        ->and($connection?->consent_status?->value ?? $connection?->consent_status)->toBe('failed')
        ->and($connection?->verification_status?->value ?? $connection?->verification_status)->toBe('unknown')
        ->and($connection?->last_error_reason_code)->toBe(ProviderReasonCodes::ProviderAuthFailed)
        ->and($connection?->last_error_message)->toBe('access_denied');

    $this->assertDatabaseHas('audit_logs', [
        'managed_environment_id' => $tenant->id,
        'action' => 'tenant.consent.callback',
        'status' => 'failed',
    ]);
});
