<?php

use App\Livewire\Admin\Datacenters;
use App\Livewire\Admin\Provisioning;
use App\Models\Datacenter;
use App\Models\User;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Support\Facades\Auth;
use Livewire\Livewire;

it('grants console access to every operator role but not to customers', function () {
    foreach (['Owner', 'Admin', 'Support', 'Billing', 'Read-only'] as $role) {
        $this->actingAs(operator($role), 'operator')->get(route('admin.overview'))->assertOk();
    }
    // The operator guard itself, not only the default driver, has to be reset:
    // actingAs() caches a user directly on the guard instance it targets, and
    // switching the default guard back to 'web' does not clear it — the last
    // loop iteration's operator would otherwise still answer for
    // Auth::guard('operator') and this customer would inherit their access.
    Auth::guard('operator')->logout();
    $customer = User::factory()->create(); // no role
    $this->actingAs($customer, 'web')->get(route('admin.overview'))->assertForbidden();
});

it('denies console access to a role-less account even if is_admin is set', function () {
    // RBAC is the boundary — the bare legacy flag must never grant access. A
    // User cannot hold a role at all any more, so this is no longer even a
    // question of a role being removed — there is nowhere for one to be.
    $noRole = User::factory()->create(['is_admin' => true]);

    $this->actingAs($noRole)->get(route('admin.overview'))->assertForbidden();
});

it('denies datacenter management to roles without the capability', function () {
    foreach (['Support', 'Billing', 'Read-only'] as $role) {
        Livewire::actingAs(operator($role), 'operator')->test(Datacenters::class)
            ->set('code', 'xy')->set('name', 'X')->call('save')->assertForbidden();
    }
    expect(Datacenter::query()->where('code', 'xy')->exists())->toBeFalse();

    // Admin has the capability.
    Livewire::actingAs(operator('Admin'), 'operator')->test(Datacenters::class)
        ->set('code', 'nbg2')->set('name', 'Nürnberg')->call('save')->assertHasNoErrors();
    expect(Datacenter::query()->where('code', 'nbg2')->exists())->toBeTrue();
});

it('lets Support retry provisioning but not manage datacenters', function () {
    // Support can retry (capability present) — the action runs (no-op on a missing run).
    Livewire::actingAs(operator('Support'), 'operator')->test(Provisioning::class)->call('retry', 'nonexistent-uuid')->assertOk();

    // ...but cannot manage datacenters.
    Livewire::actingAs(operator('Support'), 'operator')->test(Datacenters::class)->call('toggle', 'x')->assertForbidden();
});

it('replays the operator and account checks on every Livewire action', function () {
    // Livewire re-applies only the middleware on this list when an action posts
    // to /livewire/update, and its defaults cover auth but not ours. Without
    // these, the console page would refuse a non-operator while the console's
    // actions still answered them — the page is not where the actions run.
    $persistent = app(\Livewire\Mechanisms\PersistentMiddleware\PersistentMiddleware::class)
        ->getPersistentMiddleware();

    expect($persistent)->toContain(\App\Http\Middleware\EnsureAdmin::class)
        ->and($persistent)->toContain(\App\Http\Middleware\EnsureCustomerActive::class)
        ->and($persistent)->toContain(\App\Http\Middleware\RestrictAdminHost::class);
});
