<?php

namespace App\Modules\HR\Recruitment\Repositories;

use App\Modules\HR\Recruitment\DTOs\RecruitmentReportFilters;
use App\Modules\HR\Recruitment\Models\RecruitmentApplication;
use App\Modules\HR\Recruitment\Models\RecruitmentCandidate;
use App\Modules\HR\Recruitment\Models\RecruitmentHiring;
use App\Modules\HR\Recruitment\Models\RecruitmentInterview;
use App\Modules\HR\Recruitment\Models\RecruitmentInterviewScorecard;
use App\Modules\HR\Recruitment\Models\RecruitmentOfferLetter;
use App\Modules\HR\Recruitment\Models\RecruitmentVacancy;
use App\Modules\HR\Recruitment\Support\VacancyStatus;
use Illuminate\Database\Eloquent\Builder;

class RecruitmentReportRepository
{
    public function __construct(
        private readonly RecruitmentReportFilterQuery $filters,
    ) {}

    public function applicationsBase(int $tenantId, RecruitmentReportFilters $f): Builder
    {
        $q = RecruitmentApplication::query()->where('tenant_id', $tenantId);
        $this->filters->applyDate($q, 'applied_at', $f);
        $this->filters->applyRecruiter($q, $f);
        $this->filters->applyStatus($q, $f);
        $this->filters->applyVacancyScope($q, $f, 'vacancy_id');

        return $q;
    }

    public function vacanciesBase(int $tenantId, RecruitmentReportFilters $f): Builder
    {
        $q = RecruitmentVacancy::query()->where('tenant_id', $tenantId);
        $this->filters->applyDate($q, 'created_at', $f);
        $this->filters->applyRecruiter($q, $f);
        $this->filters->applyStatus($q, $f);
        if ($f->departmentId !== null) {
            $q->where('department_id', $f->departmentId);
        }
        if ($f->vacancyId !== null) {
            $q->whereKey($f->vacancyId);
        }

        return $q;
    }

    public function openVacancies(int $tenantId, RecruitmentReportFilters $f): Builder
    {
        $scoped = new RecruitmentReportFilters(
            dateFrom: $f->dateFrom,
            dateTo: $f->dateTo,
            departmentId: $f->departmentId,
            vacancyId: $f->vacancyId,
            recruiterId: $f->recruiterId,
            status: $f->status ?? VacancyStatus::OPEN,
        );

        return $this->vacanciesBase($tenantId, $scoped)
            ->with(['department', 'position'])
            ->orderByDesc('id');
    }

    public function interviewsBase(int $tenantId, RecruitmentReportFilters $f): Builder
    {
        $q = RecruitmentInterview::query()->where('tenant_id', $tenantId);
        $this->filters->applyDate($q, 'scheduled_at', $f);
        $this->filters->applyRecruiter($q, $f);
        $this->filters->applyStatus($q, $f);
        if ($f->vacancyId !== null || $f->departmentId !== null) {
            $q->whereHas('application', fn (Builder $a) => $this->filters->applyVacancyScope($a, $f, 'vacancy_id'));
        }

        return $q;
    }

    public function scorecardsBase(int $tenantId, RecruitmentReportFilters $f): Builder
    {
        $q = RecruitmentInterviewScorecard::query()->where('tenant_id', $tenantId);
        $this->filters->applyDate($q, 'scored_at', $f);
        if ($f->status !== null) {
            $q->where('recommendation', $f->status);
        }
        if ($f->recruiterId !== null) {
            $q->where('scored_by', $f->recruiterId);
        }
        if ($f->vacancyId !== null || $f->departmentId !== null) {
            $q->whereHas('interview.application', fn (Builder $a) => $this->filters->applyVacancyScope($a, $f, 'vacancy_id'));
        }

        return $q;
    }

    public function offersBase(int $tenantId, RecruitmentReportFilters $f): Builder
    {
        $q = RecruitmentOfferLetter::query()->where('tenant_id', $tenantId);
        $this->filters->applyDate($q, 'created_at', $f);
        $this->filters->applyRecruiter($q, $f);
        $this->filters->applyStatus($q, $f);
        if ($f->departmentId !== null) {
            $q->where('department_id', $f->departmentId);
        }
        if ($f->vacancyId !== null) {
            $q->where('vacancy_id', $f->vacancyId);
        }

        return $q;
    }

    public function hiringsBase(int $tenantId, RecruitmentReportFilters $f): Builder
    {
        $q = RecruitmentHiring::query()->where('tenant_id', $tenantId);
        $this->filters->applyDate($q, 'hired_at', $f);
        if ($f->recruiterId !== null) {
            $q->where('hired_by', $f->recruiterId);
        }
        if ($f->vacancyId !== null) {
            $q->where('vacancy_id', $f->vacancyId);
        }
        if ($f->departmentId !== null) {
            $q->whereHas('vacancy', fn (Builder $v) => $v->where('department_id', $f->departmentId));
        }

        return $q->with(['employee', 'vacancy', 'candidate', 'offerLetter']);
    }

    public function candidatesBase(int $tenantId, RecruitmentReportFilters $f): Builder
    {
        $q = RecruitmentCandidate::query()->where('tenant_id', $tenantId);
        $this->filters->applyDate($q, 'created_at', $f);
        $this->filters->applyRecruiter($q, $f);
        if ($f->vacancyId !== null || $f->departmentId !== null) {
            $q->whereHas('applications', fn (Builder $a) => $this->filters->applyVacancyScope($a, $f, 'vacancy_id'));
        }

        return $q;
    }
}
