<?php

namespace App\Modules\HR\Recruitment\Repositories;

use App\Modules\HR\Recruitment\Models\RecruitmentVacancy;
use App\Support\SelectOptionFormatter;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;

class RecruitmentVacancyRepository
{
    /**
     * @param  array<string, mixed>  $data
     */
    public function create(array $data): RecruitmentVacancy
    {
        return RecruitmentVacancy::query()->create($data);
    }

    /**
     * @param  array<string, mixed>  $data
     */
    public function update(RecruitmentVacancy $row, array $data): RecruitmentVacancy
    {
        $row->update($data);

        return $row->fresh(['department', 'position', 'jobRequest']);
    }

    public function softDelete(RecruitmentVacancy $row): void
    {
        $row->delete();
    }

    public function lockForTenant(int $tenantId, int $id): ?RecruitmentVacancy
    {
        return RecruitmentVacancy::query()
            ->where('tenant_id', $tenantId)
            ->whereKey($id)
            ->lockForUpdate()
            ->first();
    }

    /**
     * @param  array{q?: string|null, status?: string|null, department_id?: int|null}  $filters
     */
    public function paginateForTenant(int $tenantId, array $filters = [], int $perPage = 20): LengthAwarePaginator
    {
        $q = RecruitmentVacancy::query()
            ->where('tenant_id', $tenantId)
            ->with(['department', 'position', 'jobRequest'])
            ->withCount([
                'applications',
                'interviews',
                'offerLetters',
                'hirings',
            ])
            ->orderByDesc('id');

        if (! empty($filters['status'])) {
            $q->where('status', $filters['status']);
        }
        if (! empty($filters['department_id'])) {
            $q->where('department_id', (int) $filters['department_id']);
        }
        if (! empty($filters['q'])) {
            $term = '%'.$filters['q'].'%';
            $q->where(function ($builder) use ($term): void {
                $builder->where('title', 'like', $term)
                    ->orWhere('reference_code', 'like', $term);
            });
        }

        return $q->paginate($perPage)->withQueryString();
    }

    /**
     * @return array<int, string>
     */
    public function listForSelect(int $tenantId): array
    {
        return RecruitmentVacancy::query()
            ->where('tenant_id', $tenantId)
            ->orderByDesc('id')
            ->get(['id', 'title', 'reference_code'])
            ->mapWithKeys(fn ($v) => [(int) $v->id => $v->reference_code.' — '.$v->title])
            ->all();
    }

    /**
     * @return list<array{value: string, label: string}>
     */
    public function searchForLookup(int $tenantId, string $query, int $limit = 30, ?int $onlyId = null): array
    {
        $builder = RecruitmentVacancy::query()
            ->where('tenant_id', $tenantId)
            ->orderByDesc('id');

        if ($onlyId !== null) {
            $builder->whereKey($onlyId);
        } else {
            if ($query !== '') {
                $term = '%'.$query.'%';
                $builder->where(function ($q) use ($term): void {
                    $q->where('title', 'like', $term)->orWhere('reference_code', 'like', $term);
                });
            }
            $builder->limit($limit);
        }

        return SelectOptionFormatter::mapRows(
            $builder->get(['id', 'title', 'reference_code']),
            'title',
            'reference_code',
        );
    }

    public function findForShow(int $tenantId, int $id): RecruitmentVacancy
    {
        return RecruitmentVacancy::query()
            ->where('tenant_id', $tenantId)
            ->with(['department', 'position', 'jobRequest', 'createdByUser'])
            ->withCount(['applications', 'interviews', 'offerLetters', 'hirings'])
            ->whereKey($id)
            ->firstOrFail();
    }
}
