<?php

namespace App\Modules\HR\Recruitment\Repositories;

use App\Modules\HR\Recruitment\Models\RecruitmentCandidate;
use App\Support\Lists\ListQuery;
use App\Support\SelectOptionFormatter;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Http\Request;

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

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

        return $candidate->fresh(['cvs']);
    }

    public function softDelete(RecruitmentCandidate $candidate): void
    {
        $candidate->delete();
    }

    public function findByEmail(int $tenantId, string $email): ?RecruitmentCandidate
    {
        return RecruitmentCandidate::query()
            ->where('tenant_id', $tenantId)
            ->whereRaw('LOWER(email) = ?', [mb_strtolower($email)])
            ->first();
    }

    /**
     * @param  array{q?: string|null, source?: string|null}  $filters
     */
    public function paginateForTenant(int $tenantId, array $filters = [], int $perPage = 20): LengthAwarePaginator
    {
        $q = RecruitmentCandidate::query()
            ->where('tenant_id', $tenantId)
            ->withCount('cvs')
            ->orderByDesc('id');

        if (! empty($filters['q'])) {
            $term = '%'.$filters['q'].'%';
            $q->where(function ($builder) use ($term): void {
                $builder->where('first_name', 'like', $term)
                    ->orWhere('last_name', 'like', $term)
                    ->orWhere('email', 'like', $term)
                    ->orWhere('reference_code', 'like', $term)
                    ->orWhere('phone', 'like', $term);
            });
        }
        if (! empty($filters['source'])) {
            $q->where('source', $filters['source']);
        }

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

    public function paginateForIndex(int $tenantId, Request $request): LengthAwarePaginator
    {
        $query = RecruitmentCandidate::query()
            ->where('tenant_id', $tenantId)
            ->withCount('cvs');

        ListQuery::applySearch($query, $request->input('q'), ['first_name', 'last_name', 'email', 'reference_code', 'phone']);
        ListQuery::applyEquals($query, 'source', $request->input('source'));
        ListQuery::applySort(
            $query,
            $request->input('sort'),
            $request->input('dir'),
            [
                'reference_code' => 'reference_code',
                'first_name' => 'first_name',
                'last_name' => 'last_name',
                'source' => 'source',
            ],
            'id',
            'desc',
        );

        return ListQuery::paginate($query, $request);
    }

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

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

        $options = [];
        foreach ($builder->get(['id', 'first_name', 'last_name', 'reference_code']) as $row) {
            $options[] = [
                'value' => (string) $row->id,
                'label' => SelectOptionFormatter::label(
                    trim($row->first_name.' '.$row->last_name),
                    $row->reference_code,
                ),
            ];
        }

        return $options;
    }
}
