<?php

declare(strict_types=1);

use App\Models\Bonus;
use App\Models\Department;
use App\Models\DisciplinaryReport;
use App\Models\Employee;
use App\Models\EmployeeDocument;
use App\Models\Explanation;
use App\Models\Gift;
use App\Models\Position;
use App\Models\Shift;
use App\Models\SickLeave;
use App\Models\UnpaidLeave;
use App\Models\Vacation;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Notification;

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

it('defines expected employee relationships', function (): void {
    $department = Department::factory()->create();
    $position = Position::factory()->create();
    $shift = Shift::factory()->create();

    $employee = Employee::factory()->create([
        'department_id' => $department->id,
        'position_id' => $position->id,
        'shift_id' => $shift->id,
    ]);

    Vacation::factory()->count(2)->pending()->create([
        'employee_id' => $employee->id,
        'start_date' => '2024-06-01',
        'end_date' => '2024-06-05',
        'days' => 5,
    ]);
    SickLeave::factory()->create([
        'employee_id' => $employee->id,
        'start_date' => '2024-03-01',
        'end_date' => '2024-03-03',
        'days' => 3,
    ]);
    UnpaidLeave::factory()->pending()->create([
        'employee_id' => $employee->id,
        'start_date' => '2024-04-01',
        'end_date' => '2024-04-10',
        'days' => 10,
    ]);
    DisciplinaryReport::factory()->create(['employee_id' => $employee->id]);
    Explanation::factory()->create(['employee_id' => $employee->id]);
    Bonus::factory()->create(['employee_id' => $employee->id]);
    Gift::factory()->create(['employee_id' => $employee->id]);
    EmployeeDocument::factory()->create(['employee_id' => $employee->id]);

    $employee->load([
        'department',
        'position',
        'shift',
        'vacations',
        'sickLeaves',
        'unpaidLeaves',
        'disciplinaryReports',
        'explanations',
        'bonuses',
        'gifts',
        'documents',
    ]);

    expect($employee->department->is($department))->toBeTrue()
        ->and($employee->position->is($position))->toBeTrue()
        ->and($employee->shift->is($shift))->toBeTrue()
        ->and($employee->vacations)->toHaveCount(2)
        ->and($employee->sickLeaves)->toHaveCount(1)
        ->and($employee->unpaidLeaves)->toHaveCount(1)
        ->and($employee->disciplinaryReports)->toHaveCount(1)
        ->and($employee->explanations)->toHaveCount(1)
        ->and($employee->bonuses)->toHaveCount(1)
        ->and($employee->gifts)->toHaveCount(1)
        ->and($employee->documents)->toHaveCount(1);
});

it('generates an employee number on save when number is blank', function (): void {
    $employee = Employee::factory()->create([
        'employee_number' => '',
    ]);

    expect($employee->employee_number)->toBe('EMP-00001');
});

it('does not overwrite an existing employee number on update', function (): void {
    $employee = Employee::factory()->create([
        'employee_number' => 'EMP-CUSTOM',
    ]);

    $employee->update(['full_name' => 'Updated Name']);

    expect($employee->fresh()->employee_number)->toBe('EMP-CUSTOM');
});

it('increments employee numbers sequentially', function (): void {
    $first = Employee::factory()->create(['employee_number' => '']);
    $second = Employee::factory()->create(['employee_number' => '']);

    expect($first->employee_number)->toBe('EMP-00001')
        ->and($second->employee_number)->toBe('EMP-00002');
});

it('enforces a unique employee number', function (): void {
    Employee::factory()->create(['employee_number' => 'EMP-UNIQUE']);

    expect(fn (): Employee => Employee::factory()->create(['employee_number' => 'EMP-UNIQUE']))
        ->toThrow(QueryException::class);
});

it('allows different employees to have distinct employee numbers', function (): void {
    $first = Employee::factory()->create(['employee_number' => 'EMP-00001']);
    $second = Employee::factory()->create(['employee_number' => 'EMP-00002']);

    expect($first->employee_number)->not->toBe($second->employee_number);
});
