<?php

use App\Filament\Resources\EntraGroupSyncRunResource;
use App\Filament\Resources\EntraGroupSyncRunResource\Pages\ListEntraGroupSyncRuns;
use App\Jobs\EntraGroupSyncJob;
use App\Models\EntraGroupSyncRun;
use App\Models\Tenant;
use App\Models\User;
use App\Notifications\RunStatusChangedNotification;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;
use Livewire\Livewire;

uses(RefreshDatabase::class);

test('entra group sync runs are listed for the active tenant', function () {
    $tenant = Tenant::factory()->create();
    $otherTenant = Tenant::factory()->create();

    EntraGroupSyncRun::query()->create([
        'tenant_id' => $tenant->getKey(),
        'selection_key' => 'groups-v1:all',
        'slot_key' => 'slot-a',
        'status' => EntraGroupSyncRun::STATUS_SUCCEEDED,
    ]);

    EntraGroupSyncRun::query()->create([
        'tenant_id' => $otherTenant->getKey(),
        'selection_key' => 'groups-v1:all',
        'slot_key' => 'slot-b',
        'status' => EntraGroupSyncRun::STATUS_SUCCEEDED,
    ]);

    $user = User::factory()->create();
    $user->tenants()->syncWithoutDetaching([
        $tenant->getKey() => ['role' => 'owner'],
        $otherTenant->getKey() => ['role' => 'owner'],
    ]);

    $this->actingAs($user)
        ->get(EntraGroupSyncRunResource::getUrl('index', tenant: $tenant))
        ->assertOk()
        ->assertSee('slot-a')
        ->assertDontSee('slot-b');
});

test('entra group sync run view is forbidden cross-tenant (403)', function () {
    $tenantA = Tenant::factory()->create();
    $tenantB = Tenant::factory()->create();

    $runB = EntraGroupSyncRun::query()->create([
        'tenant_id' => $tenantB->getKey(),
        'selection_key' => 'groups-v1:all',
        'slot_key' => null,
        'status' => EntraGroupSyncRun::STATUS_SUCCEEDED,
    ]);

    $user = User::factory()->create();
    $user->tenants()->syncWithoutDetaching([
        $tenantA->getKey() => ['role' => 'owner'],
        $tenantB->getKey() => ['role' => 'owner'],
    ]);

    $this->actingAs($user)
        ->get(EntraGroupSyncRunResource::getUrl('view', ['record' => $runB], tenant: $tenantA))
        ->assertForbidden();
});

test('sync groups action enqueues job and writes database notification', function () {
    Queue::fake();

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

    $this->actingAs($user);

    $tenant->makeCurrent();
    Filament::setTenant($tenant, true);

    Livewire::test(ListEntraGroupSyncRuns::class)
        ->callAction('sync_groups');

    Queue::assertPushed(EntraGroupSyncJob::class);

    $run = EntraGroupSyncRun::query()->where('tenant_id', $tenant->getKey())->latest('id')->first();
    expect($run)->not->toBeNull();

    $this->assertDatabaseHas('notifications', [
        'notifiable_id' => $user->getKey(),
        'notifiable_type' => $user->getMorphClass(),
        'type' => RunStatusChangedNotification::class,
    ]);

    $notification = $user->notifications()->latest('id')->first();
    expect($notification)->not->toBeNull();
    expect($notification->data['actions'][0]['url'] ?? null)
        ->toBe(EntraGroupSyncRunResource::getUrl('view', ['record' => $run->getKey()], tenant: $tenant));
});
