<?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 setupWorkspaceWithRole(string $role = 'owner'): array
{
    $user = User::factory()->create();
    $workspace = Workspace::factory()->create();
    $workspace->users()->attach($user->id, ['role' => $role]);
    $client = Client::factory()->create(['workspace_id' => $workspace->id]);
    session(['current_workspace_id' => $workspace->id]);

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

test('unauthenticated user is redirected to login', function () {
    $response = $this->get(route('dashboard'));

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

test('user without workspace sees admin view', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

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

    $response->assertOk();
    $response->assertInertia(fn ($page) => $page
        ->component('Dashboard')
        ->where('workspaceName', null)
        ->where('stats', null)
        ->where('statCards', [])
        ->where('declarations', [])
    );
});

test('owner sees all workspace declarations in kpi counts', function () {
    [$user, $workspace, $client] = setupWorkspaceWithRole('owner');

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

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

    // Due this week (assigned to current user)
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $user->id,
        'status' => DeclarationStatus::EnCours,
        'due_date' => now()->addDays(3),
    ]);

    // En attente client
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $otherUser->id,
        'status' => DeclarationStatus::EnAttenteClient,
        'due_date' => now()->addDays(10),
    ]);

    // En cours
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $user->id,
        'status' => DeclarationStatus::EnCours,
        'due_date' => now()->addDays(15),
    ]);

    // Ferme (should be excluded)
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'status' => DeclarationStatus::Ferme,
        'due_date' => now()->subDays(1),
    ]);

    // Termine (should be excluded)
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'status' => DeclarationStatus::Termine,
        'due_date' => now()->subDays(1),
    ]);

    // Mise en demeure (should be excluded)
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'status' => DeclarationStatus::MiseEnDemeure,
        'due_date' => now()->subDays(1),
    ]);

    $this->actingAs($user);
    $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', 3)
        ->has('statCards', 4)
        ->where('workspaceName', $workspace->name)
    );
});

test('manager sees all workspace declarations in kpi counts', function () {
    [$user, $workspace, $client] = setupWorkspaceWithRole('manager');

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

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

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

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

test('worker sees only assigned declarations', function () {
    [$user, $workspace, $client] = setupWorkspaceWithRole('worker');

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

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

    // Assigned to other worker (should NOT be visible)
    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($user);
    $response = $this->get(route('dashboard'));

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

test('dashboard data uses cache with correct key and ttl', function () {
    [$user, $workspace, $client] = setupWorkspaceWithRole('owner');

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

    $this->actingAs($user);

    // First request populates cache
    $this->get(route('dashboard'))->assertOk();

    $cacheKey = "dashboard:{$workspace->id}:{$user->id}";
    expect(Cache::has($cacheKey))->toBeTrue();

    $cached = Cache::get($cacheKey);
    expect($cached)->toBeArray()
        ->and($cached)->toHaveKeys(['overdue', 'dueThisWeek', 'enAttenteClient', 'enCours']);
});

test('dashboard excludes archived declarations', function () {
    [$user, $workspace, $client] = setupWorkspaceWithRole('owner');

    // Active declaration
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'status' => DeclarationStatus::EnCours,
        'due_date' => now()->addDays(2),
        'archived_at' => null,
    ]);

    // Archived declaration (should NOT be counted)
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'status' => DeclarationStatus::EnCours,
        'due_date' => now()->addDays(2),
        'archived_at' => now()->subDay(),
    ]);

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

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

test('dashboard returns declarations sorted by due date ascending', function () {
    [$user, $workspace, $client] = setupWorkspaceWithRole('owner');

    $later = Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'status' => DeclarationStatus::EnCours,
        'due_date' => now()->addDays(10),
    ]);

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

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

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

test('dashboard limits declarations to 15 rows', function () {
    [$user, $workspace, $client] = setupWorkspaceWithRole('owner');

    // Create 20 declarations
    for ($i = 0; $i < 20; $i++) {
        Declaration::factory()->create([
            'workspace_id' => $workspace->id,
            'client_id' => $client->id,
            'status' => DeclarationStatus::EnCours,
            'due_date' => now()->addDays($i),
        ]);
    }

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

    $response->assertOk();
    $response->assertInertia(fn ($page) => $page
        ->component('Dashboard')
        ->has('declarations', 15)
    );
});

test('stat cards have correct filter hrefs', function () {
    [$user, $workspace, $client] = setupWorkspaceWithRole('owner');

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

    $response->assertOk();
    $response->assertInertia(fn ($page) => $page
        ->component('Dashboard')
        ->has('statCards', 4)
        ->where('statCards.0.status', 'danger')
        ->where('statCards.1.status', 'warning')
        ->where('statCards.2.status', 'info')
        ->where('statCards.3.status', 'success')
    );
});

test('declaration rows include show url and assignee name', function () {
    [$user, $workspace, $client] = setupWorkspaceWithRole('owner');

    $assignee = User::factory()->create(['name' => 'Ahmed Test']);

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

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

    $response->assertOk();
    $response->assertInertia(fn ($page) => $page
        ->component('Dashboard')
        ->has('declarations', 1)
        ->where('declarations.0.assigneeName', 'Ahmed Test')
        ->where('declarations.0.clientName', $client->company_name)
        ->has('declarations.0.showUrl')
    );
});
