<?php

namespace App\Modules\HR\Recruitment\Services;

use App\Modules\HR\Recruitment\DTOs\ApplicationWriteData;
use App\Modules\HR\Recruitment\DTOs\CandidateWriteData;
use App\Modules\HR\Recruitment\Models\RecruitmentApplication;
use App\Modules\HR\Recruitment\Models\RecruitmentVacancy;
use App\Modules\HR\Recruitment\Support\VacancyStatus;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

class CareerPortalApplyService
{
    public function __construct(
        private readonly RecruitmentCandidateService $candidates,
        private readonly RecruitmentCandidateCvService $cvs,
        private readonly RecruitmentApplicationService $applications,
    ) {}

    /**
     * @param  array<string, mixed>  $data
     */
    public function apply(RecruitmentVacancy $vacancy, array $data, UploadedFile $cvFile): RecruitmentApplication
    {
        $this->assertVacancyOpen($vacancy);

        return DB::transaction(function () use ($vacancy, $data, $cvFile) {
            $email = (string) $data['email'];
            $candidate = $this->candidates->findByEmail((int) $vacancy->tenant_id, $email);
            if ($candidate === null) {
                $candidate = $this->candidates->store(CandidateWriteData::fromValidated([
                    'first_name' => $data['first_name'],
                    'last_name' => $data['last_name'],
                    'email' => $email,
                    'phone' => $data['phone'] ?? null,
                    'source' => 'career_portal',
                    'nationality' => $data['nationality'] ?? null,
                    'notes' => null,
                ]));
            }

            $cv = $this->cvs->store($candidate, $cvFile, null, true);

            return $this->applications->store(
                ApplicationWriteData::fromValidated([
                    'vacancy_id' => $vacancy->id,
                    'candidate_id' => $candidate->id,
                    'candidate_cv_id' => $cv->id,
                    'source' => 'career_portal',
                    'cover_letter' => $data['cover_letter'] ?? null,
                ]),
                null,
                true,
            );
        });
    }

    private function assertVacancyOpen(RecruitmentVacancy $vacancy): void
    {
        $ok = $vacancy->status === VacancyStatus::OPEN
            && $vacancy->show_on_portal
            && ($vacancy->closes_at === null || $vacancy->closes_at->isFuture() || $vacancy->closes_at->isToday());

        if (! $ok) {
            throw ValidationException::withMessages([
                'vacancy_id' => __('recruitment.career_portal.errors.vacancy_closed'),
            ]);
        }
    }
}
