<?php

declare(strict_types=1);

use App\Filament\Pages\Settings\WorkspaceSettings;
use App\Models\AuditLog;
use App\Models\PlatformUser;
use App\Models\SupportAccessGrant;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Support\Audit\AuditActionId;
use App\Support\Auth\WorkspaceRole;
use App\Support\Workspaces\WorkspaceContext;
use Livewire\Livewire;

function spec276_pending_recovery_request(Workspace $workspace): SupportAccessGrant
{
    return SupportAccessGrant::factory()->pendingRecovery()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'requested_by_platform_user_id' => (int) PlatformUser::factory()->create()->getKey(),
        'reason' => 'Recover workspace ownership for support case',
        'ttl_minutes' => 30,
    ]);
}

function spec276_workspace_member(string $role): array
{
    $workspace = Workspace::factory()->create();
    $user = User::factory()->create();

    WorkspaceMembership::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'user_id' => (int) $user->getKey(),
        'role' => $role,
    ]);

    session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey());

    return [$workspace, $user];
}

it('shows pending recovery requests on workspace settings and allows an owner to approve them', function (): void {
    [$workspace, $owner] = spec276_workspace_member(WorkspaceRole::Owner->value);
    $grant = spec276_pending_recovery_request($workspace);

    $this->actingAs($owner)
        ->get(WorkspaceSettings::getUrl(panel: 'admin'))
        ->assertSuccessful()
        ->assertSee('Support access approval')
        ->assertSee('Recover workspace ownership for support case')
        ->assertSee('Approve recovery access')
        ->assertSee('Deny request');

    Livewire::actingAs($owner)
        ->test(WorkspaceSettings::class)
        ->call('approveSupportAccess')
        ->assertNotified('Recovery access approved');

    expect($grant->fresh()->status)->toBe(SupportAccessGrant::STATUS_ACTIVE)
        ->and($grant->fresh()->approved_by_user_id)->toBe((int) $owner->getKey());

    expect(AuditLog::query()
        ->where('workspace_id', (int) $workspace->getKey())
        ->whereIn('action', [
            AuditActionId::SupportAccessApproved->value,
            AuditActionId::SupportAccessActivated->value,
        ])
        ->count())->toBe(2);
});

it('allows a workspace owner to deny pending recovery support access', function (): void {
    [$workspace, $owner] = spec276_workspace_member(WorkspaceRole::Owner->value);
    $grant = spec276_pending_recovery_request($workspace);

    Livewire::actingAs($owner)
        ->test(WorkspaceSettings::class)
        ->call('denySupportAccess')
        ->assertNotified('Recovery access denied');

    expect($grant->fresh()->status)->toBe(SupportAccessGrant::STATUS_DENIED);

    expect(AuditLog::query()
        ->where('workspace_id', (int) $workspace->getKey())
        ->where('action', AuditActionId::SupportAccessDenied->value)
        ->exists())->toBeTrue();
});

it('forbids non-owner workspace managers from approving recovery support access', function (): void {
    [$workspace, $manager] = spec276_workspace_member(WorkspaceRole::Manager->value);
    $grant = spec276_pending_recovery_request($workspace);

    Livewire::actingAs($manager)
        ->test(WorkspaceSettings::class)
        ->call('approveSupportAccess')
        ->assertForbidden();

    expect($grant->fresh()->status)->toBe(SupportAccessGrant::STATUS_REQUESTED);
});
