<?php

namespace App\Modules\HR\Recruitment\Repositories;

use App\Modules\HR\Recruitment\Models\RecruitmentCandidateCv;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Collection;

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

    public function softDelete(RecruitmentCandidateCv $cv): void
    {
        $cv->delete();
    }

    public function clearPrimaryForCandidate(int $tenantId, int $candidateId): void
    {
        RecruitmentCandidateCv::query()
            ->where('tenant_id', $tenantId)
            ->where('candidate_id', $candidateId)
            ->where('is_primary', true)
            ->update(['is_primary' => false]);
    }

    /**
     * @return Collection<int, RecruitmentCandidateCv>
     */
    public function listForCandidate(int $candidateId): Collection
    {
        return RecruitmentCandidateCv::query()
            ->where('candidate_id', $candidateId)
            ->orderByDesc('is_primary')
            ->orderByDesc('id')
            ->get();
    }

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

        if (! empty($filters['candidate_id'])) {
            $q->where('candidate_id', (int) $filters['candidate_id']);
        }
        if (! empty($filters['q'])) {
            $term = '%'.$filters['q'].'%';
            $q->where(function ($builder) use ($term): void {
                $builder->where('original_name', 'like', $term)
                    ->orWhere('reference_code', 'like', $term)
                    ->orWhereHas('candidate', function ($c) use ($term): void {
                        $c->where('first_name', 'like', $term)
                            ->orWhere('last_name', 'like', $term)
                            ->orWhere('reference_code', 'like', $term);
                    });
            });
        }

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

    /**
     * @return list<array{value: string, label: string}>
     */
    public function searchForLookup(
        int $tenantId,
        string $query,
        int $limit = 30,
        ?int $candidateId = null,
        ?int $onlyId = null,
    ): array {
        if ($onlyId === null && ($candidateId === null || $candidateId <= 0)) {
            return [];
        }

        $builder = RecruitmentCandidateCv::query()
            ->where('tenant_id', $tenantId)
            ->orderByDesc('is_primary')
            ->orderByDesc('id');

        if ($candidateId !== null && $candidateId > 0) {
            $builder->where('candidate_id', $candidateId);
        }

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

        $out = [];
        foreach ($builder->get(['id', 'original_name', 'reference_code', 'is_primary']) as $row) {
            $label = trim((string) $row->original_name);
            if ($label === '') {
                $label = (string) $row->reference_code;
            } elseif (filled($row->reference_code)) {
                $label .= ' ('.$row->reference_code.')';
            }
            if ($row->is_primary) {
                $label .= ' ★';
            }
            $out[] = [
                'value' => (string) $row->id,
                'label' => $label,
            ];
        }

        return $out;
    }
}
