<?php

declare(strict_types=1);

use App\DTOs\Import\EmployeeRowDto;
use App\Enums\ImportType;
use App\Models\Department;
use App\Models\Employee;
use App\Models\Position;
use App\Models\Shift;
use App\Services\Import\EmployeeImportTransformer;
use App\Services\Import\ImportService;

beforeEach(function (): void {
    $this->department = Department::factory()->create(['name' => 'Engineering', 'code' => 'ENG']);
    $this->position = Position::factory()->create(['name' => 'Developer']);
    $this->shift = Shift::factory()->create(['name' => 'Day Shift', 'code' => 'DAY']);
    $this->importService = app(ImportService::class);
    $this->transformer = app(EmployeeImportTransformer::class);
});

it('skips duplicate employees during import', function (): void {
    Employee::factory()->create([
        'employee_number' => 'EMP-90001',
        'national_id' => 'TM',
    ]);

    $rows = [[
        'employee_number' => 'EMP-90001',
        'full_name' => 'Duplicate Employee',
        'national_id' => 'TM',
        'department' => 'Engineering',
        'position' => 'Developer',
        'shift' => 'Day Shift',
        'hire_date' => '2024-01-01',
    ]];

    $result = $this->importService->import(ImportType::Employees, $rows);

    expect($result->imported)->toBe(0)
        ->and($result->skipped)->toBe(1)
        ->and($result->failed)->toBe(0)
        ->and(Employee::query()->where('employee_number', 'EMP-90001')->count())->toBe(1);
});

it('imports valid employee rows', function (): void {
    $rows = [[
        'employee_number' => 'EMP-90002',
        'full_name' => 'Jane Smith',
        'gender' => 'female',
        'birth_date' => '1990-01-15',
        'department' => 'Engineering',
        'position' => 'Developer',
        'shift' => 'Day Shift',
        'hire_date' => '2024-03-15',
    ]];

    $result = $this->importService->import(ImportType::Employees, $rows);

    expect($result->imported)->toBe(1)
        ->and($result->skipped)->toBe(0)
        ->and($result->failed)->toBe(0);

    $this->assertDatabaseHas('employees', [
        'employee_number' => 'EMP-90002',
        'full_name' => 'Jane Smith',
        'department_id' => $this->department->id,
    ]);
});

it('imports valid employee rows without an employee number', function (): void {
    $rows = [[
        'full_name' => 'Auto Number Employee',
        'gender' => 'male',
        'birth_date' => '1992-02-20',
        'department' => 'Engineering',
        'position' => 'Developer',
        'shift' => 'Day Shift',
        'hire_date' => '2024-04-01',
    ]];

    $result = $this->importService->import(ImportType::Employees, $rows);

    expect($result->imported)->toBe(1)
        ->and($result->skipped)->toBe(0)
        ->and($result->failed)->toBe(0);

    $employee = Employee::query()->where('full_name', 'Auto Number Employee')->first();

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

it('reports validation errors for invalid employee rows', function (): void {
    $rows = [[
        'employee_number' => '',
        'full_name' => '',
        'department' => 'Unknown Department',
    ]];

    $result = $this->importService->import(ImportType::Employees, $rows);

    expect($result->imported)->toBe(0)
        ->and($result->failed)->toBe(1)
        ->and($result->errors)->not->toBeEmpty();
});

it('validates required fields and unknown references', function (): void {
    $dto = EmployeeRowDto::fromMappedRow([
        'employee_number' => '',
        'full_name' => '',
        'department' => 'Missing Department',
        'position' => 'Missing Position',
        'shift' => 'Missing Shift',
    ]);

    $errors = $this->transformer->validate($dto);

    expect($errors)->toContain('Full name is required.')
        ->and($errors)->toContain('Department "Missing Department" was not found.')
        ->and($errors)->toContain('Position "Missing Position" was not found.')
        ->and($errors)->toContain('Shift "Missing Shift" was not found.');
});

it('detects duplicates by employee number or national id', function (): void {
    Employee::factory()->create([
        'employee_number' => 'EMP-80001',
        'national_id' => 'TM',
    ]);

    $duplicateByNumber = EmployeeRowDto::fromMappedRow([
        'employee_number' => 'EMP-80001',
        'full_name' => 'Someone Else',
    ]);

    $duplicateByNationalId = EmployeeRowDto::fromMappedRow([
        'employee_number' => 'EMP-80002',
        'full_name' => 'Another Person',
        'national_id' => 'TM',
    ]);

    expect($this->transformer->isDuplicate($duplicateByNumber))->toBeTrue()
        ->and($this->transformer->isDuplicate($duplicateByNationalId))->toBeTrue();
});
