<?php

use App\Enums\DeclarationStatus;
use App\Models\Client;
use App\Models\Declaration;
use App\Models\User;
use App\Models\Workspace;
use Illuminate\Support\Facades\Cache;

function setupWorkerWorkspace(): array
{
    $worker = User::factory()->create();
    $workspace = Workspace::factory()->create();
    $workspace->users()->attach($worker->id, ['role' => 'worker']);
    $client = Client::factory()->create(['workspace_id' => $workspace->id]);
    session(['current_workspace_id' => $workspace->id]);

    return [$worker, $workspace, $client];
}

test('worker sees only their assigned declarations in kpi counts', function () {
    [$worker, $workspace, $client] = setupWorkerWorkspace();

    $otherUser = User::factory()->create();
    $workspace->users()->attach($otherUser->id, ['role' => 'worker']);

    // Assigned to this worker — overdue
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $worker->id,
        'status' => DeclarationStatus::EnCours,
        'due_date' => now()->subDays(3),
    ]);

    // Assigned to this worker — due this week
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $worker->id,
        'status' => DeclarationStatus::EnCours,
        'due_date' => now()->addDays(2),
    ]);

    // Assigned to this worker — en attente client
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $worker->id,
        'status' => DeclarationStatus::EnAttenteClient,
        'due_date' => now()->addDays(10),
    ]);

    // Assigned to OTHER worker (should NOT count)
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $otherUser->id,
        'status' => DeclarationStatus::EnCours,
        'due_date' => now()->subDays(1),
    ]);

    $this->actingAs($worker);
    $response = $this->get(route('dashboard'));

    $response->assertOk();
    $response->assertInertia(fn ($page) => $page
        ->component('Dashboard')
        ->where('stats.overdue', 1)
        ->where('stats.dueThisWeek', 1)
        ->where('stats.enAttenteClient', 1)
        ->where('stats.enCours', 2)
    );
});

test('worker does not see declarations assigned to other team members in kpi counts', function () {
    [$worker, $workspace, $client] = setupWorkerWorkspace();

    $otherWorker = User::factory()->create();
    $workspace->users()->attach($otherWorker->id, ['role' => 'worker']);

    // Only assigned to other worker
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $otherWorker->id,
        'status' => DeclarationStatus::EnCours,
        'due_date' => now()->subDays(5),
    ]);

    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $otherWorker->id,
        'status' => DeclarationStatus::EnAttenteClient,
        'due_date' => now()->addDays(2),
    ]);

    $this->actingAs($worker);
    $response = $this->get(route('dashboard'));

    $response->assertOk();
    $response->assertInertia(fn ($page) => $page
        ->component('Dashboard')
        ->where('stats.overdue', 0)
        ->where('stats.dueThisWeek', 0)
        ->where('stats.enAttenteClient', 0)
        ->where('stats.enCours', 0)
    );
});

test('worker sees only their assigned declarations in the urgent declarations table', function () {
    [$worker, $workspace, $client] = setupWorkerWorkspace();

    $otherWorker = User::factory()->create();
    $workspace->users()->attach($otherWorker->id, ['role' => 'worker']);

    // Assigned to this worker
    $myDeclaration = Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $worker->id,
        'status' => DeclarationStatus::EnCours,
        'due_date' => now()->addDays(2),
    ]);

    // Assigned to other worker
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $otherWorker->id,
        'status' => DeclarationStatus::EnCours,
        'due_date' => now()->addDays(1),
    ]);

    $this->actingAs($worker);
    $response = $this->get(route('dashboard'));

    $response->assertOk();
    $response->assertInertia(fn ($page) => $page
        ->component('Dashboard')
        ->has('declarations', 1)
        ->where('declarations.0.id', $myDeclaration->id)
    );
});

test('worker sees only their assigned declarations in priority alerts', function () {
    [$worker, $workspace, $client] = setupWorkerWorkspace();

    $otherWorker = User::factory()->create();
    $workspace->users()->attach($otherWorker->id, ['role' => 'worker']);

    // Overdue declaration assigned to this worker (generates critical alert)
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $worker->id,
        'status' => DeclarationStatus::EnCours,
        'due_date' => now()->subDays(5),
    ]);

    // Overdue declaration assigned to other worker (should NOT appear)
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $otherWorker->id,
        'status' => DeclarationStatus::EnCours,
        'due_date' => now()->subDays(3),
    ]);

    $this->actingAs($worker);
    $response = $this->get(route('dashboard'));

    $response->assertOk();
    $response->assertInertia(fn ($page) => $page
        ->component('Dashboard')
        ->has('alerts', 1)
        ->where('alerts.0.severity', 'critical')
    );
});

test('worker dashboard returns isWorker true in inertia props', function () {
    [$worker, $workspace, $client] = setupWorkerWorkspace();

    $this->actingAs($worker);
    $response = $this->get(route('dashboard'));

    $response->assertOk();
    $response->assertInertia(fn ($page) => $page
        ->component('Dashboard')
        ->where('isWorker', true)
    );
});

test('worker with no assigned declarations gets zero counts and empty arrays', function () {
    [$worker, $workspace, $client] = setupWorkerWorkspace();

    // Declarations exist but assigned to someone else
    $otherUser = User::factory()->create();
    $workspace->users()->attach($otherUser->id, ['role' => 'worker']);

    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $otherUser->id,
        'status' => DeclarationStatus::EnCours,
        'due_date' => now()->subDays(1),
    ]);

    $this->actingAs($worker);
    $response = $this->get(route('dashboard'));

    $response->assertOk();
    $response->assertInertia(fn ($page) => $page
        ->component('Dashboard')
        ->where('stats.overdue', 0)
        ->where('stats.dueThisWeek', 0)
        ->where('stats.enAttenteClient', 0)
        ->where('stats.enCours', 0)
        ->where('declarations', [])
        ->where('alerts', [])
        ->where('isWorker', true)
    );
});

test('worker stat card hrefs include assignee scoping param', function () {
    [$worker, $workspace, $client] = setupWorkerWorkspace();

    $this->actingAs($worker);
    $response = $this->get(route('dashboard'));

    $response->assertOk();
    $response->assertInertia(fn ($page) => $page
        ->component('Dashboard')
        ->has('statCards', 4)
        ->where('statCards.0.href', fn ($href) => str_contains($href, 'assignee='.$worker->id))
        ->where('statCards.1.href', fn ($href) => str_contains($href, 'assignee='.$worker->id))
        ->where('statCards.2.href', fn ($href) => str_contains($href, 'assignee='.$worker->id))
        ->where('statCards.3.href', fn ($href) => str_contains($href, 'assignee='.$worker->id))
    );
});

test('owner and manager dashboard returns isWorker false', function () {
    $ownerUser = User::factory()->create();
    $managerUser = User::factory()->create();
    $workspace = Workspace::factory()->create();
    $workspace->users()->attach($ownerUser->id, ['role' => 'owner']);
    $workspace->users()->attach($managerUser->id, ['role' => 'manager']);
    session(['current_workspace_id' => $workspace->id]);

    // Owner
    $this->actingAs($ownerUser);
    $response = $this->get(route('dashboard'));
    $response->assertOk();
    $response->assertInertia(fn ($page) => $page
        ->component('Dashboard')
        ->where('isWorker', false)
    );

    // Manager
    $this->actingAs($managerUser);
    $response = $this->get(route('dashboard'));
    $response->assertOk();
    $response->assertInertia(fn ($page) => $page
        ->component('Dashboard')
        ->where('isWorker', false)
    );
});

test('user without any workspace gets isWorker false in fallback', function () {
    $user = User::factory()->create();

    // User has no workspace attachments — middleware cannot auto-assign
    $this->actingAs($user);
    $response = $this->get(route('dashboard'));

    $response->assertOk();
    $response->assertInertia(fn ($page) => $page
        ->component('Dashboard')
        ->where('isWorker', false)
        ->where('workspaceName', null)
    );
});

test('cached data is scoped per user with worker cache key including user id', function () {
    [$worker, $workspace, $client] = setupWorkerWorkspace();

    $otherWorker = User::factory()->create();
    $workspace->users()->attach($otherWorker->id, ['role' => 'worker']);

    // Declaration assigned to first worker
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $worker->id,
        'status' => DeclarationStatus::EnCours,
        'due_date' => now()->subDays(1),
    ]);

    // Declaration assigned to second worker
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $otherWorker->id,
        'status' => DeclarationStatus::EnCours,
        'due_date' => now()->subDays(2),
    ]);

    // First worker request
    $this->actingAs($worker);
    $this->get(route('dashboard'))->assertOk();

    $workerCacheKey = "dashboard:{$workspace->id}:{$worker->id}";
    $otherCacheKey = "dashboard:{$workspace->id}:{$otherWorker->id}";

    expect(Cache::has($workerCacheKey))->toBeTrue();
    expect(Cache::has($otherCacheKey))->toBeFalse();

    $workerCached = Cache::get($workerCacheKey);
    expect($workerCached['overdue'])->toBe(1)
        ->and($workerCached['enCours'])->toBe(1);

    // Second worker request
    $this->actingAs($otherWorker);
    $this->get(route('dashboard'))->assertOk();

    expect(Cache::has($otherCacheKey))->toBeTrue();
    $otherCached = Cache::get($otherCacheKey);
    expect($otherCached['overdue'])->toBe(1)
        ->and($otherCached['enCours'])->toBe(1);
});
