<?php

use App\Filament\Resources\ManagedEnvironmentResource\Pages\ViewManagedEnvironment;
use App\Models\OperationRun;
use App\Models\ProviderConnection;
use App\Models\ProviderCredential;
use App\Models\ManagedEnvironment;
use App\Models\ManagedEnvironmentPermission;
use App\Models\User;
use App\Support\ManagedEnvironmentLinks;
use App\Support\OperationRunLinks;
use App\Support\Providers\ProviderReasonCodes;
use App\Support\Verification\VerificationReportSchema;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;
use Livewire\Livewire;

uses(RefreshDatabase::class);

test('verification start enqueues an operation run for a tenant', function () {
    Queue::fake();
    bindFailHardGraphClient();

    $user = User::factory()->create();
    $this->actingAs($user);

    $tenant = ManagedEnvironment::factory()->create([
        'managed_environment_id' => 'tenant-guid',
        'name' => 'Contoso',
        'environment' => 'other',
        'domain' => 'contoso.com',
    ]);
    [$user, $tenant] = createUserWithTenant($tenant, $user, role: 'owner', ensureDefaultMicrosoftProviderConnection: false);
    $this->actingAs($user);
    Filament::setTenant($tenant, true);

    $connection = ProviderConnection::factory()->dedicated()->consentGranted()->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,
        'consent_status' => 'granted',
    ]);

    ProviderCredential::factory()->create([
        'provider_connection_id' => (int) $connection->getKey(),
        'type' => 'client_secret',
        'payload' => [
            'client_id' => 'client-id',
            'client_secret' => 'client-secret',
        ],
    ]);

    Livewire::test(ViewManagedEnvironment::class, ['record' => $tenant->getRouteKey()])
        ->callAction('verify');

    $run = OperationRun::query()
        ->where('managed_environment_id', (int) $tenant->getKey())
        ->where('type', 'provider.connection.check')
        ->latest('id')
        ->first();

    expect($run)->not->toBeNull()
        ->and($run?->status)->toBe('queued')
        ->and($run?->outcome)->toBe('pending')
        ->and($run?->context['provider_connection_id'] ?? null)->toBe((int) $connection->getKey());

    $notificationActionUrls = collect(session('filament.notifications', []))
        ->flatMap(static fn (array $notification): array => is_array($notification['actions'] ?? null)
            ? $notification['actions']
            : [])
        ->pluck('url')
        ->filter(static fn (mixed $url): bool => is_string($url) && trim($url) !== '')
        ->values()
        ->all();

    expect($notificationActionUrls)->toContain(OperationRunLinks::tenantlessView($run));

    Queue::assertPushed(\App\Jobs\ProviderConnectionHealthCheckJob::class, 1);

    $this->assertDatabaseMissing('audit_logs', [
        'managed_environment_id' => $tenant->id,
        'action' => 'tenant.config.verified',
    ]);
});

test('verify configuration creates a blocked run when default connection credentials are missing', function () {
    Queue::fake();

    $user = User::factory()->create();

    $tenant = ManagedEnvironment::factory()->create([
        'managed_environment_id' => 'tenant-error',
        'name' => 'Error ManagedEnvironment',
        'status' => 'active',
    ]);

    [$user, $tenant] = createUserWithTenant(tenant: $tenant, user: $user, role: 'owner', ensureDefaultMicrosoftProviderConnection: false);
    $this->actingAs($user);
    Filament::setTenant($tenant, true);

    $connection = ProviderConnection::factory()->dedicated()->consentGranted()->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,
        'consent_status' => 'granted',
    ]);

    Livewire::test(ViewManagedEnvironment::class, ['record' => $tenant->getRouteKey()])
        ->callAction('verify');

    $run = OperationRun::query()
        ->where('managed_environment_id', (int) $tenant->getKey())
        ->where('type', 'provider.connection.check')
        ->latest('id')
        ->first();

    expect($run)->not->toBeNull()
        ->and($run?->outcome)->toBe('blocked')
        ->and($run?->context['provider_connection_id'] ?? null)->toBe((int) $connection->getKey())
        ->and($run?->context['reason_code'] ?? null)->toBe(ProviderReasonCodes::DedicatedCredentialMissing);

    expect(VerificationReportSchema::isValidReport($run?->context['verification_report'] ?? []))->toBeTrue();

    Queue::assertNothingPushed();
});

test('tenant detail shows required permissions with statuses', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $tenant = ManagedEnvironment::create([
        'managed_environment_id' => 'tenant-ui',
        'name' => 'UI ManagedEnvironment',
    ]);
    [$user, $tenant] = createUserWithTenant($tenant, $user, role: 'owner');
    $this->actingAs($user);

    config(['intune_permissions.granted_stub' => []]);

    $permissions = config('intune_permissions.permissions', []);
    $firstKey = $permissions[0]['key'] ?? 'DeviceManagementConfiguration.ReadWrite.All';

    ManagedEnvironmentPermission::create([
        'managed_environment_id' => $tenant->id,
        'permission_key' => $firstKey,
        'status' => 'ok',
    ]);

    $response = $this->get(ManagedEnvironmentLinks::requiredPermissionsUrl($tenant));

    $response->assertOk();
    $response->assertSee('Actions');
    $response->assertSee($firstKey);
    $response->assertSee('ok');
    $response->assertSee('Missing');
});

test('tenant list shows Open in Entra action', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $tenant = ManagedEnvironment::create([
        'managed_environment_id' => 'tenant-ui-list',
        'name' => 'UI ManagedEnvironment List',
        'app_client_id' => 'client-123',
    ]);

    [$user, $tenant] = createUserWithTenant($tenant, $user, role: 'owner');
    $this->actingAs($user);

    Filament::setCurrentPanel('admin');
    Filament::setTenant(null, true);
    Filament::bootCurrentPanel();
    session([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id]);

    Livewire::actingAs($user)
        ->test(\App\Filament\Resources\ManagedEnvironmentResource\Pages\ListManagedEnvironments::class)
        ->assertTableActionVisible('open_in_entra', $tenant);
});

test('tenant can be archived from the tenant detail action menu', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $tenant = ManagedEnvironment::create([
        'managed_environment_id' => 'tenant-ui-archive',
        'name' => 'UI ManagedEnvironment Archive',
    ]);

    [$user, $tenant] = createUserWithTenant($tenant, $user, role: 'owner');
    $this->actingAs($user);

    Filament::setTenant($tenant, true);

    Livewire::test(ViewManagedEnvironment::class, ['record' => $tenant->getRouteKey()])
        ->mountAction('archive')
        ->setActionData([
            'archive_reason' => 'Archiving this tenant from the detail workflow.',
        ])
        ->callMountedAction()
        ->assertHasNoActionErrors();

    $this->assertSoftDeleted('managed_environments', ['id' => $tenant->id]);
});
