<?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 setupAlertWorkspace(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('overdue declarations appear as critical alerts with correct daysOverdue', function () {
    [$user, $workspace, $client] = setupAlertWorkspace();

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

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

    $response->assertOk();
    $response->assertInertia(fn ($page) => $page
        ->component('Dashboard')
        ->has('alerts', 1)
        ->where('alerts.0.severity', 'critical')
        ->where('alerts.0.clientName', $client->company_name)
        ->where('alerts.0.daysValue', 5)
        ->where('alerts.0.daysLabel', 'jours en retard')
        ->has('alerts.0.showUrl')
    );
});

test('approaching deadline declarations appear as warning alerts', function () {
    [$user, $workspace, $client] = setupAlertWorkspace();

    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('alerts', 1)
        ->where('alerts.0.severity', 'warning')
        ->where('alerts.0.daysLabel', 'jours restants')
    );
});

test('en_attente_client over 3 days appears as info alert', function () {
    [$user, $workspace, $client] = setupAlertWorkspace();

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

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

    $response->assertOk();
    $response->assertInertia(fn ($page) => $page
        ->component('Dashboard')
        ->where('alerts.0.severity', 'info')
        ->where('alerts.0.daysLabel', 'jours en attente')
    );
});

test('en_attente_client 3 days or less does not appear as info alert', function () {
    [$user, $workspace, $client] = setupAlertWorkspace();

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

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

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

test('alerts are capped at 20 items', function () {
    [$user, $workspace, $client] = setupAlertWorkspace();

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

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

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

test('alerts are sorted by severity: critical first, then warning, then info', function () {
    [$user, $workspace, $client] = setupAlertWorkspace();

    // Info alert (en_attente_client >3 days)
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'status' => DeclarationStatus::EnAttenteClient,
        'due_date' => now()->addDays(10),
        'updated_at' => now()->subDays(5),
    ]);

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

    // Critical alert (overdue)
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'status' => DeclarationStatus::EnCours,
        'due_date' => now()->subDays(3),
    ]);

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

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

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

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

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

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

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

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

test('empty alerts array when no urgent items exist', function () {
    [$user, $workspace, $client] = setupAlertWorkspace();

    // Declaration far in the future (no alert)
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'status' => DeclarationStatus::EnCours,
        'due_date' => now()->addDays(30),
    ]);

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

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

test('alerts are included in cached dashboard payload', function () {
    [$user, $workspace, $client] = setupAlertWorkspace();

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

    $this->actingAs($user);
    $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)->toHaveKey('alerts')
        ->and($cached['alerts'])->toBeArray()
        ->and($cached['alerts'])->toHaveCount(1)
        ->and($cached['alerts'][0]['severity'])->toBe('critical');
});

test('excluded statuses do not generate alerts', function () {
    [$user, $workspace, $client] = setupAlertWorkspace();

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

    // MiseEnDemeure (excluded) - overdue
    Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'status' => DeclarationStatus::MiseEnDemeure,
        'due_date' => now()->subDays(3),
    ]);

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

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

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