<?php

namespace App\Modules\HR\Recruitment\Services;

use App\Modules\HR\Recruitment\DTOs\CandidateWriteData;
use App\Modules\HR\Recruitment\Events\RecruitmentCandidateCreated;
use App\Modules\HR\Recruitment\Events\RecruitmentCandidateDeleted;
use App\Modules\HR\Recruitment\Events\RecruitmentCandidateUpdated;
use App\Modules\HR\Recruitment\Models\RecruitmentCandidate;
use App\Modules\HR\Recruitment\Repositories\RecruitmentCandidateRepository;
use App\Modules\HR\Recruitment\Support\RecruitmentTenantId;
use App\Support\SystemReferenceAssigner;
use App\Support\SystemReferenceGenerator;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\Facades\DB;

class RecruitmentCandidateService
{
    public function __construct(
        private readonly RecruitmentCandidateRepository $repository,
        private readonly SystemReferenceAssigner $references,
        private readonly Dispatcher $events,
    ) {}

    public function store(CandidateWriteData $data, ?int $userId = null): RecruitmentCandidate
    {
        $actor = RecruitmentTenantId::actorId($userId);
        $candidate = DB::transaction(function () use ($data, $actor) {
            $row = $this->repository->create(array_merge($data->toArray(), [
                'tenant_id' => RecruitmentTenantId::require(),
                'reference_code' => $this->references->pendingPlaceholder(SystemReferenceGenerator::CANDIDATE),
                'created_by' => $actor,
                'updated_by' => $actor,
            ]));

            return $this->references->assign($row, SystemReferenceGenerator::CANDIDATE, 'reference_code');
        });

        $this->events->dispatch(new RecruitmentCandidateCreated($candidate));

        return $candidate;
    }

    public function update(RecruitmentCandidate $candidate, CandidateWriteData $data, ?int $userId = null): RecruitmentCandidate
    {
        $fresh = $this->repository->update($candidate, array_merge($data->toArray(), [
            'updated_by' => RecruitmentTenantId::actorId($userId),
        ]));
        $this->events->dispatch(new RecruitmentCandidateUpdated($fresh));

        return $fresh;
    }

    public function destroy(RecruitmentCandidate $candidate): void
    {
        $this->repository->softDelete($candidate);
        $this->events->dispatch(new RecruitmentCandidateDeleted($candidate));
    }

    public function findByEmail(int $tenantId, string $email): ?RecruitmentCandidate
    {
        return $this->repository->findByEmail($tenantId, $email);
    }
}
