<?php

namespace App\Modules\HR\Recruitment\Services;

use App\Modules\HR\Employees\Models\Employee;
use App\Modules\HR\Recruitment\Models\RecruitmentHiring;
use App\Modules\HR\Recruitment\Models\RecruitmentOnboardingCase;
use App\Modules\HR\Recruitment\Repositories\RecruitmentOnboardingCaseRepository;
use App\Modules\HR\Recruitment\Repositories\RecruitmentOnboardingTaskRepository;
use App\Modules\HR\Recruitment\Support\OnboardingCaseStatus;
use App\Support\SystemReferenceAssigner;
use App\Support\SystemReferenceGenerator;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

class OnboardingCaseService
{
    public function __construct(
        private readonly RecruitmentOnboardingCaseRepository $cases,
        private readonly RecruitmentOnboardingTaskRepository $tasks,
        private readonly OnboardingBootstrapService $bootstrap,
        private readonly OnboardingProgressService $progress,
        private readonly SystemReferenceAssigner $references,
    ) {}

    public function startFromHiring(RecruitmentHiring $hiring, int $userId): RecruitmentOnboardingCase
    {
        $existing = $this->cases->findByEmployee((int) $hiring->tenant_id, (int) $hiring->employee_id);
        if ($existing !== null) {
            return $existing;
        }

        return $this->createCase([
            'tenant_id' => (int) $hiring->tenant_id,
            'hiring_id' => (int) $hiring->id,
            'employee_id' => (int) $hiring->employee_id,
            'application_id' => $hiring->application_id,
            'candidate_id' => $hiring->candidate_id,
            'vacancy_id' => $hiring->vacancy_id,
            'started_by' => $userId,
        ]);
    }

    public function startFromEmployee(Employee $employee, int $userId): RecruitmentOnboardingCase
    {
        $existing = $this->cases->findByEmployee((int) $employee->tenant_id, (int) $employee->id);
        if ($existing !== null) {
            return $existing;
        }

        return $this->createCase([
            'tenant_id' => (int) $employee->tenant_id,
            'employee_id' => (int) $employee->id,
            'started_by' => $userId,
        ]);
    }

    /** @param  array<string, mixed>  $base */
    private function createCase(array $base): RecruitmentOnboardingCase
    {
        return DB::transaction(function () use ($base) {
            $case = $this->cases->create(array_merge($base, [
                'reference_code' => $this->references->pendingPlaceholder(SystemReferenceGenerator::ONBOARDING),
                'status' => OnboardingCaseStatus::IN_PROGRESS,
                'progress_percent' => 0,
                'started_at' => now(),
            ]));
            $this->references->assign($case, SystemReferenceGenerator::ONBOARDING, 'reference_code');

            foreach ($this->bootstrap->defaultTasks() as $task) {
                $this->tasks->create(array_merge($task, [
                    'tenant_id' => (int) $case->tenant_id,
                    'onboarding_case_id' => (int) $case->id,
                ]));
            }

            return $this->progress->recalculate($case->fresh(), $base['started_by'] ?? null);
        });
    }

    public function assertNotCancelled(RecruitmentOnboardingCase $case): void
    {
        if ($case->status === OnboardingCaseStatus::CANCELLED) {
            throw ValidationException::withMessages([
                'case' => [__('recruitment.onboarding.errors.cancelled')],
            ]);
        }
    }
}
