@props([
    'id',
    'name',
    'users' => [],
    'selected' => null,
    'placeholder' => 'Start typing your username',
    'emptyLabel' => 'Not selected',
    'includeEmpty' => true,
    'inputClass' => '',
])

@php
    $userItems = collect($users)
        ->map(function ($user): array {
            $name = trim((string) ($user->name ?? ''));
            $email = trim((string) ($user->email ?? ''));
            $jobTitle = trim((string) ($user->job_title ?? ''));
            $metaParts = array_values(array_filter([$jobTitle, $email], fn (string $value): bool => $value !== ''));

            return [
                'id' => (int) ($user->id ?? 0),
                'name' => $name,
                'meta' => implode(' · ', $metaParts),
                'search' => mb_strtolower(trim($name.' '.$jobTitle.' '.$email)),
            ];
        })
        ->filter(fn (array $item): bool => $item['id'] > 0 && $item['name'] !== '')
        ->sortBy('name', SORT_NATURAL | SORT_FLAG_CASE)
        ->values()
        ->all();

    $selectedValue = old($name, $selected);
    $selectedId = ($selectedValue === null || $selectedValue === '')
        ? ''
        : (string) ((int) $selectedValue);

    $selectedItem = collect($userItems)->first(
        fn (array $item): bool => (string) $item['id'] === $selectedId
    );

    $selectedLabel = $selectedItem['name'] ?? '';
@endphp

<div
    {{ $attributes->merge(['class' => 'relative']) }}
    data-user-search-select
    data-include-empty="{{ $includeEmpty ? '1' : '0' }}"
    data-empty-label="{{ $emptyLabel }}"
>
    <input type="hidden" name="{{ $name }}" value="{{ $selectedId }}" data-user-search-value>

    <input
        id="{{ $id }}"
        type="text"
        value="{{ $selectedLabel }}"
        placeholder="{{ $placeholder }}"
        autocomplete="off"
        data-user-search-input
        class="mt-1 w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 {{ $inputClass }}"
    >

    <div
        class="absolute z-40 mt-1 hidden w-full overflow-hidden rounded-md border border-slate-200 bg-white shadow-lg"
        data-user-search-menu
    >
        <ul class="max-h-60 overflow-auto py-1" data-user-search-list></ul>
    </div>

    <script type="application/json" data-user-search-json>@json($userItems, JSON_UNESCAPED_UNICODE)</script>
</div>

@once
    <script>
        (() => {
            if (window.__crmUserSearchSelectBooted) {
                return;
            }
            window.__crmUserSearchSelectBooted = true;

            const rootSelector = '[data-user-search-select]';

            const normalize = (value) => (String(value ?? '').trim().toLocaleLowerCase());

            const initInstance = (root) => {
                if (!(root instanceof HTMLElement) || root.dataset.userSearchReady === '1') {
                    return;
                }
                root.dataset.userSearchReady = '1';

                const hiddenInput = root.querySelector('[data-user-search-value]');
                const textInput = root.querySelector('[data-user-search-input]');
                const menu = root.querySelector('[data-user-search-menu]');
                const list = root.querySelector('[data-user-search-list]');
                const dataNode = root.querySelector('[data-user-search-json]');

                if (!hiddenInput || !textInput || !menu || !list || !dataNode) {
                    return;
                }

                let users = [];
                try {
                    users = JSON.parse(dataNode.textContent || '[]');
                } catch (_error) {
                    users = [];
                }

                const includeEmpty = root.dataset.includeEmpty === '1';
                const emptyLabel = root.dataset.emptyLabel || 'Not selected';
                let activeIndex = -1;
                let options = [];

                const openMenu = () => {
                    menu.classList.remove('hidden');
                };

                const closeMenu = () => {
                    menu.classList.add('hidden');
                    activeIndex = -1;
                };

                const buildOptions = (query) => {
                    const normalizedQuery = normalize(query);
                    const filteredUsers = users.filter((user) => {
                        if (normalizedQuery === '') {
                            return true;
                        }

                        return normalize(user.search || `${user.name} ${user.meta}`).includes(normalizedQuery);
                    });

                    const mapped = filteredUsers.slice(0, 100).map((user) => ({
                        id: String(user.id),
                        name: String(user.name || ''),
                        meta: String(user.meta || ''),
                    }));

                    if (includeEmpty) {
                        mapped.unshift({
                            id: '',
                            name: emptyLabel,
                            meta: '',
                        });
                    }

                    return mapped;
                };

                const selectOption = (option) => {
                    hiddenInput.value = option.id;
                    textInput.value = option.id === '' ? '' : option.name;
                    closeMenu();
                    hiddenInput.dispatchEvent(new Event('change', { bubbles: true }));
                    textInput.dispatchEvent(new Event('change', { bubbles: true }));
                };

                const render = () => {
                    options = buildOptions(textInput.value);
                    list.innerHTML = '';

                    if (options.length === 0) {
                        const empty = document.createElement('li');
                        empty.className = 'px-3 py-2 text-xs text-slate-500';
                        empty.textContent = 'Nothing found';
                        list.appendChild(empty);
                        return;
                    }

                    options.forEach((option, index) => {
                        const button = document.createElement('button');
                        button.type = 'button';
                        button.className = 'block w-full px-3 py-2 text-left transition hover:bg-slate-100';
                        if (index === activeIndex) {
                            button.classList.add('bg-slate-100');
                        }

                        const title = document.createElement('div');
                        title.className = 'text-sm text-slate-800';
                        title.textContent = option.name;
                        button.appendChild(title);

                        if (option.meta) {
                            const meta = document.createElement('div');
                            meta.className = 'mt-0.5 text-xs text-slate-500';
                            meta.textContent = option.meta;
                            button.appendChild(meta);
                        }

                        button.addEventListener('mousedown', (event) => {
                            event.preventDefault();
                        });

                        button.addEventListener('click', () => {
                            selectOption(option);
                        });

                        list.appendChild(button);
                    });
                };

                const applyExactMatchIfPossible = () => {
                    const typed = normalize(textInput.value);
                    if (typed === '') {
                        if (includeEmpty) {
                            hiddenInput.value = '';
                        }
                        return;
                    }

                    const match = users.find((user) => normalize(user.name) === typed);
                    if (!match) {
                        return;
                    }

                    hiddenInput.value = String(match.id);
                    textInput.value = String(match.name || '');
                };

                textInput.addEventListener('focus', () => {
                    activeIndex = -1;
                    openMenu();
                    render();
                });

                textInput.addEventListener('input', () => {
                    hiddenInput.value = '';
                    activeIndex = -1;
                    openMenu();
                    render();
                });

                textInput.addEventListener('keydown', (event) => {
                    if (menu.classList.contains('hidden') && (event.key === 'ArrowDown' || event.key === 'ArrowUp')) {
                        openMenu();
                        render();
                    }

                    if (event.key === 'Escape') {
                        closeMenu();
                        return;
                    }

                    if (event.key === 'ArrowDown') {
                        event.preventDefault();
                        if (options.length === 0) {
                            render();
                        }
                        activeIndex = Math.min(activeIndex + 1, options.length - 1);
                        render();
                        return;
                    }

                    if (event.key === 'ArrowUp') {
                        event.preventDefault();
                        if (options.length === 0) {
                            render();
                        }
                        activeIndex = Math.max(activeIndex - 1, 0);
                        render();
                        return;
                    }

                    if (event.key === 'Enter' && !menu.classList.contains('hidden')) {
                        event.preventDefault();
                        if (options.length === 0) {
                            return;
                        }

                        const option = options[activeIndex] || options[0];
                        if (option) {
                            selectOption(option);
                        }
                    }
                });

                textInput.addEventListener('blur', () => {
                    window.setTimeout(() => {
                        if (root.contains(document.activeElement)) {
                            return;
                        }

                        applyExactMatchIfPossible();
                        closeMenu();
                    }, 120);
                });

                document.addEventListener('click', (event) => {
                    if (!root.contains(event.target)) {
                        closeMenu();
                    }
                });

                render();
            };

            const scan = (scope) => {
                const container = scope instanceof HTMLElement || scope instanceof Document
                    ? scope
                    : document;

                if (container instanceof HTMLElement && container.matches(rootSelector)) {
                    initInstance(container);
                }

                container.querySelectorAll(rootSelector).forEach(initInstance);
            };

            if (document.readyState === 'loading') {
                document.addEventListener('DOMContentLoaded', () => scan(document));
            } else {
                scan(document);
            }

            const observer = new MutationObserver((mutations) => {
                mutations.forEach((mutation) => {
                    mutation.addedNodes.forEach((node) => {
                        if (!(node instanceof HTMLElement)) {
                            return;
                        }

                        scan(node);
                    });
                });
            });

            observer.observe(document.documentElement, {
                childList: true,
                subtree: true,
            });
        })();
    </script>
@endonce
