<?php

declare(strict_types=1);

use App\Filament\Resources\StoredReportResource;
use App\Filament\Widgets\ManagedEnvironment\AdminRolesSummaryWidget;
use App\Jobs\ScanEntraAdminRolesJob;
use App\Models\StoredReport;
use App\Models\ManagedEnvironment;
use App\Support\Auth\Capabilities;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Queue;
use Livewire\Livewire;

uses(RefreshDatabase::class);

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

function createAdminRolesReport(ManagedEnvironment $tenant, ?array $summaryOverrides = null): StoredReport
{
    $totals = array_merge([
        'roles_total' => 8,
        'assignments_total' => 12,
        'high_privilege_assignments' => 5,
    ], $summaryOverrides ?? []);

    return StoredReport::query()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'report_type' => StoredReport::REPORT_TYPE_ENTRA_ADMIN_ROLES,
        'fingerprint' => hash('sha256', (string) now()->timestamp),
        'payload' => [
            'provider_key' => 'microsoft',
            'domain' => 'entra.admin_roles',
            'measured_at' => now()->toIso8601String(),
            'role_definitions' => [],
            'role_assignments' => [],
            'totals' => $totals,
            'high_privilege' => [
                [
                    'role_display_name' => 'Global Administrator',
                    'role_template_id' => '62e90394-69f5-4237-9190-012177145e10',
                    'principal_id' => 'user-1',
                    'principal_display_name' => 'Admin User',
                    'assignment_scope' => '/',
                    'severity' => 'critical',
                ],
            ],
        ],
    ]);
}

// ---------------------------------------------------------------------------
// Widget renders with report data
// ---------------------------------------------------------------------------

it('renders with report data showing timestamp and high-privilege count', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    Filament::setTenant($tenant, true);

    createAdminRolesReport($tenant, [
        'high_privilege_assignments' => 7,
    ]);

    Livewire::actingAs($user)
        ->test(AdminRolesSummaryWidget::class, ['record' => $tenant])
        ->assertSee('Entra admin roles')
        ->assertSee('High-privilege assignments')
        ->assertSee('7')
        ->assertSee('Last scan')
        ->assertSuccessful();
});

it('links report-present state to the canonical stored-report detail route', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    Filament::setTenant($tenant, true);

    $report = createAdminRolesReport($tenant, [
        'high_privilege_assignments' => 7,
    ]);

    $expectedUrl = StoredReportResource::getUrl('view', ['record' => $report], panel: 'admin', tenant: $tenant);

    Livewire::actingAs($user)
        ->test(AdminRolesSummaryWidget::class, ['record' => $tenant])
        ->assertSee('View latest report')
        ->assertSeeHtml('href="'.$expectedUrl.'"')
        ->assertSuccessful();
});

it('does not expose the report drilldown when Entra admin roles view is denied', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    Filament::setTenant($tenant, true);

    createAdminRolesReport($tenant);

    Gate::define(Capabilities::ENTRA_ROLES_VIEW, fn (): bool => false);

    Livewire::actingAs($user)
        ->test(AdminRolesSummaryWidget::class, ['record' => $tenant])
        ->assertDontSee('View latest report')
        ->assertSuccessful();
});

// ---------------------------------------------------------------------------
// Empty state
// ---------------------------------------------------------------------------

it('renders empty state when no report exists', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    Filament::setTenant($tenant, true);

    Livewire::actingAs($user)
        ->test(AdminRolesSummaryWidget::class, ['record' => $tenant])
        ->assertSee('No scan performed yet.')
        ->assertDontSee('Last scan')
        ->assertSuccessful();
});

// ---------------------------------------------------------------------------
// Scan now — dispatches job
// ---------------------------------------------------------------------------

it('dispatches ScanEntraAdminRolesJob when user has ENTRA_ROLES_MANAGE', function (): void {
    Queue::fake();

    [$user, $tenant] = createUserWithTenant(role: 'owner');

    Filament::setTenant($tenant, true);

    Livewire::actingAs($user)
        ->test(AdminRolesSummaryWidget::class, ['record' => $tenant])
        ->call('scanNow')
        ->assertSuccessful();

    Queue::assertPushed(ScanEntraAdminRolesJob::class, function (ScanEntraAdminRolesJob $job) use ($tenant, $user): bool {
        return $job->tenantId === (int) $tenant->getKey()
            && $job->workspaceId === (int) $tenant->workspace_id
            && $job->initiatorUserId === (int) $user->getKey();
    });
});

// ---------------------------------------------------------------------------
// Scan now — RBAC enforcement (readonly cannot scan)
// ---------------------------------------------------------------------------

it('returns 403 when readonly user tries to scan', function (): void {
    Queue::fake();

    [$user, $tenant] = createUserWithTenant(role: 'readonly');

    Filament::setTenant($tenant, true);

    Livewire::actingAs($user)
        ->test(AdminRolesSummaryWidget::class, ['record' => $tenant])
        ->call('scanNow')
        ->assertForbidden();

    Queue::assertNotPushed(ScanEntraAdminRolesJob::class);
});

// ---------------------------------------------------------------------------
// Non-member user sees empty state (no tenant data exposed)
// ---------------------------------------------------------------------------

it('renders empty state for non-member user', function (): void {
    $user = \App\Models\User::factory()->create();
    $tenant = ManagedEnvironment::factory()->create();

    Filament::setTenant($tenant, true);

    Livewire::actingAs($user)
        ->test(AdminRolesSummaryWidget::class, ['record' => $tenant])
        ->assertSee('No scan performed yet.')
        ->assertDontSee('Scan now')
        ->assertSuccessful();
});

// ---------------------------------------------------------------------------
// Widget shows scan button only for users with manage capability
// ---------------------------------------------------------------------------

it('does not show scan button for readonly users', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'readonly');

    Filament::setTenant($tenant, true);

    Livewire::actingAs($user)
        ->test(AdminRolesSummaryWidget::class, ['record' => $tenant])
        ->assertDontSee('Scan now')
        ->assertSuccessful();
});

it('shows scan button for owner users', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    Filament::setTenant($tenant, true);

    Livewire::actingAs($user)
        ->test(AdminRolesSummaryWidget::class, ['record' => $tenant])
        ->assertSee('Scan now')
        ->assertSuccessful();
});

// ---------------------------------------------------------------------------
// Notification on successful scan dispatch
// ---------------------------------------------------------------------------

it('sends success notification after scan dispatch', function (): void {
    Queue::fake();

    [$user, $tenant] = createUserWithTenant(role: 'owner');

    Filament::setTenant($tenant, true);

    Livewire::actingAs($user)
        ->test(AdminRolesSummaryWidget::class, ['record' => $tenant])
        ->call('scanNow')
        ->assertSuccessful();

    $notifications = collect(session('filament.notifications', []));
    $titles = $notifications->pluck('title')->filter()->values()->all();

    expect($titles)->toContain('Entra admin roles scan queued');
});
