<?php

use App\Filament\Pages\ChooseEnvironment;
use App\Filament\Pages\EnvironmentDashboard;
use App\Filament\Resources\ManagedEnvironmentResource\Pages\ListManagedEnvironments;
use App\Models\ManagedEnvironment;
use App\Support\Auth\UiTooltips;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Http;
use Livewire\Livewire;

uses(RefreshDatabase::class);

beforeEach(function (): void {
    Http::preventStrayRequests();
});

test('readonly users may switch current tenant via ChooseEnvironment', function () {
    [$user, $tenantA] = createUserWithTenant(role: 'readonly', fixtureProfile: 'credential-enabled');

    $tenantB = ManagedEnvironment::factory()->create([
        'status' => 'active',
        'is_current' => false,
    ]);

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

    $tenantB->makeCurrent();

    expect($tenantA->fresh()->is_current)->toBeFalse();
    expect($tenantB->fresh()->is_current)->toBeTrue();

    Livewire::actingAs($user)
        ->test(ChooseEnvironment::class)
        ->call('selectEnvironment', $tenantA->getKey())
        ->assertRedirect(EnvironmentDashboard::getUrl(tenant: $tenantA));
});

test('users cannot switch to a tenant they are not a member of', function () {
    [$user] = createUserWithTenant(role: 'readonly', fixtureProfile: 'credential-enabled');

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

    Livewire::actingAs($user)
        ->test(ChooseEnvironment::class)
        ->call('selectEnvironment', $tenant->getKey())
        ->assertStatus(404);
});

test('readonly users cannot archive tenants', function () {
    [$user, $tenant] = createUserWithTenant(role: 'readonly', fixtureProfile: 'credential-enabled');

    Filament::setTenant($tenant, true);

    expect(Gate::forUser($user)->allows(\App\Support\Auth\Capabilities::TENANT_DELETE, $tenant))->toBeFalse();

    Livewire::actingAs($user)
        ->test(ListManagedEnvironments::class)
        ->assertTableActionDisabled('archive', $tenant)
        ->assertTableActionExists('archive', fn ($action): bool => $action->getTooltip() === UiTooltips::insufficientPermission(), $tenant)
        ->callTableAction('archive', $tenant, [
            'archive_reason' => 'Readonly users should not be able to archive tenants.',
        ]);

    expect($tenant->fresh()->trashed())->toBeFalse();
});

test('readonly users cannot force delete tenants', function () {
    [$user, $tenant] = createUserWithTenant(role: 'readonly', fixtureProfile: 'credential-enabled');

    $tenant->delete();

    Filament::setTenant($tenant, true);

    expect(Gate::forUser($user)->allows(\App\Support\Auth\Capabilities::TENANT_DELETE, $tenant))->toBeFalse();

    Livewire::actingAs($user)
        ->test(ListManagedEnvironments::class)
        ->assertTableActionDisabled('forceDelete', $tenant)
        ->assertTableActionExists('forceDelete', fn ($action): bool => $action->getTooltip() === UiTooltips::insufficientPermission(), $tenant)
        ->callTableAction('forceDelete', $tenant);

    expect(ManagedEnvironment::withTrashed()->find($tenant->getKey()))->not->toBeNull();
});

test('readonly users cannot verify tenant configuration', function () {
    [$user, $tenant] = createUserWithTenant(role: 'readonly', fixtureProfile: 'credential-enabled');

    Filament::setTenant($tenant, true);

    expect(Gate::forUser($user)->allows(\App\Support\Auth\Capabilities::TENANT_MANAGE, $tenant))->toBeFalse();

    Livewire::actingAs($user)
        ->test(ListManagedEnvironments::class)
        ->assertTableActionDisabled('verify', $tenant)
        ->assertTableActionExists('verify', fn ($action): bool => $action->getTooltip() === UiTooltips::insufficientPermission(), $tenant)
        ->callTableAction('verify', $tenant);
});

test('readonly users cannot setup intune rbac', function () {
    [$user, $tenant] = createUserWithTenant(role: 'readonly', fixtureProfile: 'credential-enabled');

    Filament::setTenant($tenant, true);

    expect(Gate::forUser($user)->allows(\App\Support\Auth\Capabilities::TENANT_MANAGE, $tenant))->toBeFalse();

    Livewire::actingAs($user)
        ->test(ListManagedEnvironments::class)
        ->assertTableActionDisabled('setup_rbac', $tenant);
});

test('readonly users cannot edit tenants', function () {
    [$user, $tenant] = createUserWithTenant(role: 'readonly', fixtureProfile: 'credential-enabled');

    Filament::setTenant($tenant, true);

    expect(Gate::forUser($user)->allows(\App\Support\Auth\Capabilities::TENANT_MANAGE, $tenant))->toBeFalse();

    Livewire::actingAs($user)
        ->test(ListManagedEnvironments::class)
        ->assertTableActionDisabled('edit', $tenant)
        ->assertTableActionExists('edit', fn ($action): bool => $action->getTooltip() === UiTooltips::insufficientPermission(), $tenant);
});

test('readonly users cannot open admin consent', function () {
    [$user, $tenant] = createUserWithTenant(role: 'readonly', fixtureProfile: 'credential-enabled');

    Filament::setTenant($tenant, true);

    expect(\App\Filament\Resources\ManagedEnvironmentResource::adminConsentUrl($tenant))->not->toBeNull();
    expect(Gate::forUser($user)->allows(\App\Support\Auth\Capabilities::TENANT_MANAGE, $tenant))->toBeFalse();

    Livewire::actingAs($user)
        ->test(ListManagedEnvironments::class)
        ->assertTableActionDisabled('admin_consent', $tenant)
        ->assertTableActionExists('admin_consent', fn ($action): bool => $action->getTooltip() === UiTooltips::insufficientPermission(), $tenant);
});

test('readonly users cannot start tenant sync from tenant menu', function () {
    [$user, $tenant] = createUserWithTenant(role: 'readonly', fixtureProfile: 'credential-enabled');

    Filament::setTenant($tenant, true);

    expect(Gate::forUser($user)->allows(\App\Support\Auth\Capabilities::TENANT_SYNC, $tenant))->toBeFalse();

    Livewire::actingAs($user)
        ->test(ListManagedEnvironments::class)
        ->assertTableActionDisabled('syncTenant', $tenant)
        ->assertTableActionExists('syncTenant', fn ($action): bool => $action->getTooltip() === UiTooltips::insufficientPermission(), $tenant);
});
