<?php

use App\Filament\Resources\TenantResource\Pages\CreateTenant;
use App\Filament\Resources\TenantResource\Pages\ViewTenant;
use App\Models\Tenant;
use App\Models\TenantPermission;
use App\Models\User;
use App\Services\Graph\GraphClientInterface;
use App\Services\Graph\GraphResponse;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;

uses(RefreshDatabase::class);

test('tenant can be created via filament and verified successfully', function () {
    app()->bind(GraphClientInterface::class, fn () => new class implements GraphClientInterface
    {
        public function listPolicies(string $policyType, array $options = []): GraphResponse
        {
            return new GraphResponse(true, []);
        }

        public function getPolicy(string $policyType, string $policyId, array $options = []): GraphResponse
        {
            return new GraphResponse(true, []);
        }

        public function getOrganization(array $options = []): GraphResponse
        {
            return new GraphResponse(true, ['value' => [['id' => $options['tenant'] ?? 'tenant']]], 200);
        }

        public function applyPolicy(string $policyType, string $policyId, array $payload, array $options = []): GraphResponse
        {
            return new GraphResponse(true, []);
        }

        public function getServicePrincipalPermissions(array $options = []): GraphResponse
        {
            // Return all required permissions as granted
            return new GraphResponse(true, [
                'permissions' => collect(config('intune_permissions.permissions', []))
                    ->pluck('key')
                    ->toArray(),
            ]);
        }

        public function request(string $method, string $path, array $options = []): GraphResponse
        {
            return new GraphResponse(true, []);
        }
    });

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

    $contextTenant = Tenant::create([
        'tenant_id' => 'tenant-context',
        'name' => 'Context Tenant',
    ]);
    $user->tenants()->syncWithoutDetaching([
        $contextTenant->getKey() => ['role' => 'owner'],
    ]);
    Filament::setTenant($contextTenant, true);

    Livewire::test(CreateTenant::class)
        ->fillForm([
            'name' => 'Contoso',
            'environment' => 'other',
            'tenant_id' => 'tenant-guid',
            'domain' => 'contoso.com',
            'app_client_id' => 'client-123',
            'app_notes' => 'Test tenant',
        ])
        ->call('create')
        ->assertHasNoFormErrors();

    $tenant = Tenant::query()->where('tenant_id', 'tenant-guid')->first();
    expect($tenant)->not->toBeNull();

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

    $tenant->refresh();

    expect($tenant->app_status)->toBe('ok');

    $this->assertDatabaseHas('audit_logs', [
        'tenant_id' => $tenant->id,
        'action' => 'tenant.config.verified',
        'status' => 'success',
    ]);

    $this->assertDatabaseHas('tenant_permissions', [
        'tenant_id' => $tenant->id,
        'status' => 'granted',
    ]);
});

test('verify configuration records error when graph fails', function () {
    app()->bind(GraphClientInterface::class, fn () => new class implements GraphClientInterface
    {
        public function listPolicies(string $policyType, array $options = []): GraphResponse
        {
            return new GraphResponse(true, []);
        }

        public function getPolicy(string $policyType, string $policyId, array $options = []): GraphResponse
        {
            return new GraphResponse(true, []);
        }

        public function getOrganization(array $options = []): GraphResponse
        {
            return new GraphResponse(false, [], 401, ['auth failed']);
        }

        public function applyPolicy(string $policyType, string $policyId, array $payload, array $options = []): GraphResponse
        {
            return new GraphResponse(true, []);
        }

        public function getServicePrincipalPermissions(array $options = []): GraphResponse
        {
            // Return error for permissions check
            return new GraphResponse(false, [], 403, ['Permission denied']);
        }

        public function request(string $method, string $path, array $options = []): GraphResponse
        {
            return new GraphResponse(true, []);
        }
    });

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

    $tenant = Tenant::create([
        'tenant_id' => 'tenant-error',
        'name' => 'Error Tenant',
    ]);
    $user->tenants()->syncWithoutDetaching([
        $tenant->getKey() => ['role' => 'owner'],
    ]);

    Filament::setTenant($tenant, true);

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

    $tenant->refresh();

    expect($tenant->app_status)->toBe('error');

    $this->assertDatabaseHas('audit_logs', [
        'tenant_id' => $tenant->id,
        'action' => 'tenant.config.verified',
        'status' => 'error',
    ]);

    $this->assertDatabaseHas('tenant_permissions', [
        'tenant_id' => $tenant->id,
        'status' => 'error',
    ]);
});

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

    $tenant = Tenant::create([
        'tenant_id' => 'tenant-ui',
        'name' => 'UI Tenant',
    ]);
    $user->tenants()->syncWithoutDetaching([
        $tenant->getKey() => ['role' => 'owner'],
    ]);

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

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

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

    $response = $this->get(route('filament.admin.resources.tenants.view', array_merge(filamentTenantRouteParams($tenant), ['record' => $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 = Tenant::create([
        'tenant_id' => 'tenant-ui-list',
        'name' => 'UI Tenant List',
        'app_client_id' => 'client-123',
    ]);

    $user->tenants()->syncWithoutDetaching([
        $tenant->getKey() => ['role' => 'owner'],
    ]);

    $response = $this->get(route('filament.admin.resources.tenants.index', filamentTenantRouteParams($tenant)));

    $response->assertOk();
    $response->assertSee('Open in Entra');
});

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

    $tenant = Tenant::create([
        'tenant_id' => 'tenant-ui-deactivate',
        'name' => 'UI Tenant Deactivate',
    ]);
    $user->tenants()->syncWithoutDetaching([
        $tenant->getKey() => ['role' => 'owner'],
    ]);

    Filament::setTenant($tenant, true);

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

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