<?php

declare(strict_types=1);

use App\Enums\ApprovalStatus;
use App\Enums\VacationType;
use App\Models\Employee;
use App\Models\User;
use App\Models\Vacation;
use App\Notifications\VacationApprovedNotification;
use App\Notifications\VacationSubmittedNotification;
use App\Services\Vacation\VacationService;
use Illuminate\Support\Facades\Notification;

beforeEach(function (): void {
    seedRoles();
    Notification::fake();

    $this->hrManager = createUserWithRole('hr_manager');
    $this->approver = createUserWithRole('administrator');
    $this->employee = Employee::factory()->create();
    $this->service = app(VacationService::class);
});

it('submits a vacation request with calculated days and pending status', function (): void {
    config(['hr.leave_calculation' => 'calendar']);

    $vacation = $this->service->submit([
        'employee_id' => $this->employee->id,
        'type' => VacationType::Annual,
        'start_date' => '2025-01-06',
        'end_date' => '2025-01-10',
        'return_date' => '2025-01-11',
        'reason' => 'Family trip',
    ]);

    expect($vacation)->toBeInstanceOf(Vacation::class)
        ->and($vacation->status)->toBe(ApprovalStatus::Pending)
        ->and($vacation->days)->toBe(5)
        ->and($vacation->employee_id)->toBe($this->employee->id);

    Notification::assertSentTo(
        [$this->hrManager],
        VacationSubmittedNotification::class,
        fn (VacationSubmittedNotification $notification): bool => $notification->vacation->is($vacation),
    );
});

it('approves a vacation and notifies hr managers', function (): void {
    $vacation = Vacation::factory()->pending()->create([
        'employee_id' => $this->employee->id,
        'start_date' => '2025-02-01',
        'end_date' => '2025-02-05',
        'days' => 5,
    ]);

    $this->service->approve($vacation, $this->approver);

    $vacation->refresh();

    expect($vacation->status)->toBe(ApprovalStatus::Approved)
        ->and($vacation->approved_by)->toBe($this->approver->id)
        ->and($vacation->approved_at)->not->toBeNull();

    Notification::assertSentTo(
        [$this->hrManager],
        VacationApprovedNotification::class,
        fn (VacationApprovedNotification $notification): bool => $notification->vacation->is($vacation),
    );
});

it('rejects a vacation without sending approval notifications', function (): void {
    $vacation = Vacation::factory()->pending()->create([
        'employee_id' => $this->employee->id,
        'start_date' => '2025-03-01',
        'end_date' => '2025-03-05',
        'days' => 5,
    ]);

    $this->service->reject($vacation, $this->approver);

    $vacation->refresh();

    expect($vacation->status)->toBe(ApprovalStatus::Rejected)
        ->and($vacation->approved_by)->toBe($this->approver->id)
        ->and($vacation->approved_at)->not->toBeNull();

    Notification::assertNothingSent();
});
