<?php

use App\Enums\DeclarationStatus;
use App\Mail\DeclarationFileRequestMail;
use App\Models\Declaration;
use App\Models\User;
use App\Models\Workspace;
use Illuminate\Support\Facades\Mail;
use Spatie\Activitylog\Models\Activity;

function setupBulkNotifyTest(string $role = 'owner', int $declarationCount = 3): array
{
    $user = User::factory()->create();
    $workspace = Workspace::factory()->create();

    $workspace->users()->attach($user->id, ['role' => $role, 'permissions' => []]);

    $declarations = Declaration::factory()
        ->forWorkspace($workspace)
        ->count($declarationCount)
        ->create(['status' => DeclarationStatus::EnAttenteClient]);

    session(['current_workspace_id' => $workspace->id]);

    return [$user, $workspace, $declarations];
}

// ── AC1,3,4: Owner/Manager can bulk-notify clients ──────

test('owner can bulk-notify clients — emails queued, activity logged, success flash', function () {
    Mail::fake();

    [$user, $workspace, $declarations] = setupBulkNotifyTest('owner');

    $ids = $declarations->pluck('id')->all();

    $response = $this->actingAs($user)->post(route('declarations.bulk-notify'), [
        'declaration_ids' => $ids,
    ]);

    $response->assertRedirect();
    $response->assertSessionHas('flash', [
        'type' => 'success',
        'message' => '3 notifications envoyées',
    ]);

    Mail::assertQueued(DeclarationFileRequestMail::class, 3);
});

test('manager can bulk-notify clients — same behavior as owner', function () {
    Mail::fake();

    [$user, $workspace, $declarations] = setupBulkNotifyTest('manager');

    $ids = $declarations->pluck('id')->all();

    $response = $this->actingAs($user)->post(route('declarations.bulk-notify'), [
        'declaration_ids' => $ids,
    ]);

    $response->assertRedirect();
    $response->assertSessionHas('flash', [
        'type' => 'success',
        'message' => '3 notifications envoyées',
    ]);

    Mail::assertQueued(DeclarationFileRequestMail::class, 3);
});

// ── AC5: Worker cannot access bulk-notify (consistent with canEdit, canDelete, canNudge) ──

test('worker is forbidden from bulk-notify endpoint', function () {
    Mail::fake();

    $worker = User::factory()->create();
    $workspace = Workspace::factory()->create();

    $workspace->users()->attach($worker->id, ['role' => 'worker', 'permissions' => []]);

    $declaration = Declaration::factory()->forWorkspace($workspace)->create([
        'status' => DeclarationStatus::EnAttenteClient,
        'assigned_to' => $worker->id,
    ]);

    session(['current_workspace_id' => $workspace->id]);

    $response = $this->actingAs($worker)->post(route('declarations.bulk-notify'), [
        'declaration_ids' => [$declaration->id],
    ]);

    $response->assertForbidden();
    Mail::assertNothingQueued();
});

// ── AC3: Rejects declarations not in en_attente_client status ──

test('rejects declarations not in en_attente_client status', function () {
    Mail::fake();

    [$user, $workspace, $declarations] = setupBulkNotifyTest('owner', 2);

    // Change one declaration to a different status
    $declarations[0]->update(['status' => DeclarationStatus::EnCours]);

    $ids = $declarations->pluck('id')->all();

    $response = $this->actingAs($user)->post(route('declarations.bulk-notify'), [
        'declaration_ids' => $ids,
    ]);

    $response->assertRedirect();
    $response->assertSessionHas('flash', [
        'type' => 'success',
        'message' => '1 notifications envoyées',
    ]);

    // Only the one remaining en_attente_client declaration should get an email
    Mail::assertQueued(DeclarationFileRequestMail::class, 1);
});

// ── AC4: Workspace boundary enforcement ──

test('workspace boundary enforcement — declarations from other workspace ignored', function () {
    Mail::fake();

    [$user, $workspace, $declarations] = setupBulkNotifyTest('owner', 1);

    $otherWorkspace = Workspace::factory()->create();
    $otherDeclaration = Declaration::factory()->forWorkspace($otherWorkspace)->create([
        'status' => DeclarationStatus::EnAttenteClient,
    ]);

    $response = $this->actingAs($user)->post(route('declarations.bulk-notify'), [
        'declaration_ids' => [$declarations[0]->id, $otherDeclaration->id],
    ]);

    $response->assertRedirect();

    // Only 1 email (from own workspace), the other is filtered out
    Mail::assertQueued(DeclarationFileRequestMail::class, 1);
});

// ── AC4: Activity log records bulk operation ──

test('activity log records bulk operation with count and actor', function () {
    Mail::fake();

    [$user, $workspace, $declarations] = setupBulkNotifyTest('owner', 2);

    $ids = $declarations->pluck('id')->all();

    $this->actingAs($user)->post(route('declarations.bulk-notify'), [
        'declaration_ids' => $ids,
    ]);

    $activity = Activity::query()
        ->where('subject_type', Workspace::class)
        ->where('subject_id', $workspace->id)
        ->where('causer_id', $user->id)
        ->where('description', 'bulk_client_notification')
        ->first();

    expect($activity)->not->toBeNull();
    expect($activity->properties['count'])->toBe(2);
    expect($activity->properties['declaration_ids'])->toHaveCount(2);
});

// ── Throttle middleware prevents abuse ──

test('throttle middleware prevents abuse — 429 after 5 requests', function () {
    Mail::fake();

    [$user, $workspace, $declarations] = setupBulkNotifyTest('owner', 1);
    $ids = $declarations->pluck('id')->all();

    // Send 5 requests (within the throttle limit)
    for ($i = 0; $i < 5; $i++) {
        $this->actingAs($user)->post(route('declarations.bulk-notify'), [
            'declaration_ids' => $ids,
        ]);
    }

    // 6th request should be throttled
    $response = $this->actingAs($user)->post(route('declarations.bulk-notify'), [
        'declaration_ids' => $ids,
    ]);

    $response->assertStatus(429);
});

// ── Unauthenticated user cannot bulk-notify ──

test('unauthenticated user cannot bulk-notify — redirected to login', function () {
    $response = $this->post(route('declarations.bulk-notify'), [
        'declaration_ids' => [1],
    ]);

    $response->assertRedirect(route('login'));
});

// ── Validation: empty declaration_ids rejected ──

test('validation rejects empty declaration_ids', function () {
    [$user, $workspace] = setupBulkNotifyTest('owner', 0);

    $response = $this->actingAs($user)->post(route('declarations.bulk-notify'), [
        'declaration_ids' => [],
    ]);

    $response->assertSessionHasErrors('declaration_ids');
});
