<?php

declare(strict_types=1);

namespace App\Services\Import;

use App\DTOs\Import\VacationRowDto;
use App\Enums\ApprovalStatus;
use App\Enums\VacationType;
use App\Models\Employee;
use App\Models\Vacation;
use Carbon\Carbon;
use Illuminate\Support\Str;

class VacationImportTransformer
{
    /**
     * @return array<string, mixed>
     */
    public function toAttributes(VacationRowDto $dto): array
    {
        $employeeId = $this->resolveEmployeeId($dto->employeeNumber);

        return [
            'employee_id' => $employeeId,
            'type' => $this->resolveType($dto->type),
            'start_date' => $this->parseDate($dto->startDate),
            'end_date' => $this->parseDate($dto->endDate),
            'return_date' => $this->parseDate($dto->returnDate),
            'days' => $dto->days,
            'status' => $this->resolveStatus($dto->status),
            'reason' => $dto->reason,
        ];
    }

    /**
     * @return array<int, string>
     */
    public function validate(VacationRowDto $dto): array
    {
        $errors = [];

        if ($dto->employeeNumber === '') {
            $errors[] = 'Employee number is required.';
        } elseif ($this->resolveEmployeeId($dto->employeeNumber) === null) {
            $errors[] = "Employee \"{$dto->employeeNumber}\" was not found.";
        }

        if ($dto->startDate === null) {
            $errors[] = 'Start date is required.';
        }

        if ($dto->endDate === null) {
            $errors[] = 'End date is required.';
        }

        return $errors;
    }

    public function isDuplicate(VacationRowDto $dto): bool
    {
        $employeeId = $this->resolveEmployeeId($dto->employeeNumber);

        if ($employeeId === null) {
            return false;
        }

        $startDate = $this->parseDate($dto->startDate);
        $endDate = $this->parseDate($dto->endDate);

        if ($startDate === null || $endDate === null) {
            return false;
        }

        return Vacation::query()
            ->where('employee_id', $employeeId)
            ->whereDate('start_date', $startDate)
            ->whereDate('end_date', $endDate)
            ->exists();
    }

    private function resolveEmployeeId(string $employeeNumber): ?int
    {
        return Employee::query()
            ->where('employee_number', $employeeNumber)
            ->value('id');
    }

    private function resolveType(?string $value): VacationType
    {
        if ($value === null || trim($value) === '') {
            return VacationType::Annual;
        }

        $normalized = Str::lower(trim($value));

        return VacationType::tryFrom($normalized) ?? VacationType::Annual;
    }

    private function resolveStatus(?string $value): ApprovalStatus
    {
        if ($value === null || trim($value) === '') {
            return ApprovalStatus::Pending;
        }

        $normalized = Str::lower(trim($value));

        return ApprovalStatus::tryFrom($normalized) ?? ApprovalStatus::Pending;
    }

    private function parseDate(?string $value): ?string
    {
        if ($value === null || trim($value) === '') {
            return null;
        }

        try {
            return Carbon::parse($value)->toDateString();
        } catch (\Throwable) {
            return null;
        }
    }
}
