<?php

namespace App\Modules\Platform\Lookup\Services;

use App\Modules\HR\Departments\Repositories\DepartmentRepository;
use App\Modules\HR\Employees\Repositories\EmployeeRepository;
use App\Modules\HR\EmploymentStatuses\Repositories\EmploymentStatusRepository;
use App\Modules\HR\Leave\Repositories\LeaveTypeRepository;
use App\Modules\HR\Positions\Repositories\PositionRepository;
use App\Modules\HR\Recruitment\Repositories\RecruitmentApplicationRepository;
use App\Modules\HR\Recruitment\Repositories\RecruitmentCandidateCvRepository;
use App\Modules\HR\Recruitment\Repositories\RecruitmentCandidateRepository;
use App\Modules\HR\Recruitment\Repositories\RecruitmentInterviewRepository;
use App\Modules\HR\Recruitment\Repositories\RecruitmentJobRequestRepository;
use App\Modules\HR\Recruitment\Repositories\RecruitmentOfferLetterRepository;
use App\Modules\HR\Recruitment\Repositories\RecruitmentVacancyRepository;
use App\Modules\HR\Shifts\Repositories\ShiftRepository;
use App\Modules\Inventory\Repositories\ItemCategoryRepository;
use App\Modules\Inventory\Repositories\ItemRepository;
use App\Modules\Inventory\Repositories\WarehouseRepository;
use App\Modules\Platform\Geography\Repositories\GeoCityRepository;
use App\Modules\Platform\Geography\Repositories\GeoCountryRepository;
use App\Modules\Platform\Geography\Repositories\GeoRegionRepository;
use App\Modules\Settings\Rbac\Repositories\TenantUserRepository;
use Illuminate\Support\Facades\Auth;

class LookupSearchService
{
    public function __construct(
        private readonly DepartmentRepository $departments,
        private readonly PositionRepository $positions,
        private readonly EmployeeRepository $employees,
        private readonly EmploymentStatusRepository $employmentStatuses,
        private readonly GeoCountryRepository $countries,
        private readonly GeoRegionRepository $regions,
        private readonly GeoCityRepository $cities,
        private readonly WarehouseRepository $warehouses,
        private readonly ItemCategoryRepository $categories,
        private readonly ItemRepository $items,
        private readonly ShiftRepository $shifts,
        private readonly LeaveTypeRepository $leaveTypes,
        private readonly RecruitmentCandidateRepository $candidates,
        private readonly RecruitmentCandidateCvRepository $candidateCvs,
        private readonly RecruitmentJobRequestRepository $jobRequests,
        private readonly RecruitmentVacancyRepository $vacancies,
        private readonly RecruitmentApplicationRepository $applications,
        private readonly RecruitmentInterviewRepository $interviews,
        private readonly RecruitmentOfferLetterRepository $offerLetters,
        private readonly TenantUserRepository $users,
    ) {}

    /**
     * @return list<array{value: string, label: string}>
     */
    public function search(
        string $type,
        string $query,
        int $limit,
        ?int $selectedId,
        ?int $excludeId,
        ?int $parentId,
    ): array {
        $tenantId = (int) (Auth::user()?->tenant_id ?? 0);

        $results = match ($type) {
            'departments' => $this->departments->searchForLookup(
                $query, $limit, $excludeId, null, $tenantId > 0 ? $tenantId : null,
            ),
            'positions' => $this->positions->searchForLookup(
                $query, $limit, null, $tenantId > 0 ? $tenantId : null, $parentId,
            ),
            'employment_statuses' => $tenantId > 0
                ? $this->employmentStatuses->searchForLookup($tenantId, $query, $limit)
                : [],
            'countries' => $this->countries->searchForLookup($query, $limit),
            'regions' => $tenantId > 0
                ? $this->regions->searchForLookup($tenantId, $query, $limit, $parentId)
                : [],
            'cities' => $tenantId > 0
                ? $this->cities->searchForLookup($tenantId, $query, $limit, $parentId)
                : [],
            'employees' => $tenantId > 0
                ? $this->employees->searchForLookup($tenantId, $query, $limit, $excludeId)
                : [],
            'warehouses' => $tenantId > 0
                ? $this->warehouses->searchForLookup($tenantId, $query, $limit)
                : [],
            'categories' => $tenantId > 0
                ? $this->categories->searchForLookup($tenantId, $query, $limit, $excludeId)
                : [],
            'items' => $tenantId > 0
                ? $this->items->searchForLookup($tenantId, $query, $limit)
                : [],
            'shifts' => $tenantId > 0
                ? $this->shifts->searchForLookup($tenantId, $query, $limit)
                : [],
            'leave_types' => $tenantId > 0
                ? $this->leaveTypes->searchForLookup($tenantId, $query, $limit)
                : [],
            'candidates' => $tenantId > 0
                ? $this->candidates->searchForLookup($tenantId, $query, $limit)
                : [],
            'candidate_cvs' => $tenantId > 0
                ? $this->candidateCvs->searchForLookup($tenantId, $query, $limit, $parentId)
                : [],
            'job_requests' => $tenantId > 0
                ? $this->jobRequests->searchForLookup($tenantId, $query, $limit)
                : [],
            'vacancies' => $tenantId > 0
                ? $this->vacancies->searchForLookup($tenantId, $query, $limit)
                : [],
            'applications' => $tenantId > 0
                ? $this->applications->searchForLookup($tenantId, $query, $limit)
                : [],
            'interviews' => $tenantId > 0
                ? $this->interviews->searchForLookup($tenantId, $query, $limit)
                : [],
            'users' => $tenantId > 0
                ? $this->users->searchForLookup($tenantId, $query, $limit)
                : [],
            'offer_letters' => $tenantId > 0
                ? $this->offerLetters->searchForLookup($tenantId, $query, $limit)
                : [],
            default => [],
        };

        if ($selectedId === null) {
            return $results;
        }

        return $this->mergeSelected($type, $results, $selectedId, $tenantId, $excludeId, $parentId);
    }

    /**
     * @param  list<array{value: string, label: string}>  $results
     * @return list<array{value: string, label: string}>
     */
    private function mergeSelected(
        string $type,
        array $results,
        int $selectedId,
        int $tenantId,
        ?int $excludeId,
        ?int $parentId,
    ): array {
        $selectedKey = (string) $selectedId;

        foreach ($results as $row) {
            if ($row['value'] === $selectedKey) {
                return $results;
            }
        }

        $selected = match ($type) {
            'departments' => $this->departments->searchForLookup(
                '', 1, $excludeId, $selectedId, $tenantId > 0 ? $tenantId : null,
            ),
            'positions' => $this->positions->searchForLookup(
                '', 1, $selectedId, $tenantId > 0 ? $tenantId : null, $parentId,
            ),
            'employment_statuses' => $tenantId > 0
                ? $this->employmentStatuses->searchForLookup($tenantId, '', 1, $selectedId)
                : [],
            'countries' => $this->countries->searchForLookup('', 1, $selectedId),
            'regions' => $tenantId > 0
                ? $this->regions->searchForLookup($tenantId, '', 1, $parentId, $selectedId)
                : [],
            'cities' => $tenantId > 0
                ? $this->cities->searchForLookup($tenantId, '', 1, $parentId, $selectedId)
                : [],
            'employees' => $tenantId > 0
                ? $this->employees->searchForLookup($tenantId, '', 1, $excludeId, $selectedId)
                : [],
            'warehouses' => $tenantId > 0
                ? $this->warehouses->searchForLookup($tenantId, '', 1, $selectedId)
                : [],
            'categories' => $tenantId > 0
                ? $this->categories->searchForLookup($tenantId, '', 1, $excludeId, $selectedId)
                : [],
            'items' => $tenantId > 0
                ? $this->items->searchForLookup($tenantId, '', 1, $selectedId)
                : [],
            'shifts' => $tenantId > 0
                ? $this->shifts->searchForLookup($tenantId, '', 1, $selectedId)
                : [],
            'leave_types' => $tenantId > 0
                ? $this->leaveTypes->searchForLookup($tenantId, '', 1, $selectedId)
                : [],
            'candidates' => $tenantId > 0
                ? $this->candidates->searchForLookup($tenantId, '', 1, $selectedId)
                : [],
            'candidate_cvs' => $tenantId > 0
                ? $this->candidateCvs->searchForLookup($tenantId, '', 1, $parentId, $selectedId)
                : [],
            'job_requests' => $tenantId > 0
                ? $this->jobRequests->searchForLookup($tenantId, '', 1, $selectedId)
                : [],
            'vacancies' => $tenantId > 0
                ? $this->vacancies->searchForLookup($tenantId, '', 1, $selectedId)
                : [],
            'applications' => $tenantId > 0
                ? $this->applications->searchForLookup($tenantId, '', 1, $selectedId)
                : [],
            'interviews' => $tenantId > 0
                ? $this->interviews->searchForLookup($tenantId, '', 1, $selectedId)
                : [],
            'users' => $tenantId > 0
                ? $this->users->searchForLookup($tenantId, '', 1, $selectedId)
                : [],
            'offer_letters' => $tenantId > 0
                ? $this->offerLetters->searchForLookup($tenantId, '', 1, $selectedId)
                : [],
            default => [],
        };

        if ($selected === []) {
            return $results;
        }

        return array_merge($selected, $results);
    }
}
