<script lang="ts">
	import type { CityBasic, ComboOption, CountryBasic } from '$lib/types';
	import ChevronDown from './icons/ChevronDown.svelte';
	import ChevronUp from './icons/ChevronUp.svelte';
	import XMark from './icons/XMark.svelte';
	import FuzzySearch from 'fuzzy-search';

	type ComboBoxProps = {
		options: readonly CountryBasic[];
		onSelect: (data: ComboOption | CountryBasic | CityBasic) => void;
		onClear: () => void;
		disabledItems?: number[];
		selectedOptionId: number | null;
	};

	let { options, onSelect, onClear, disabledItems, selectedOptionId }: ComboBoxProps = $props();

	let focused = $state(false);
	let selectSet = $state(false);
	let inputElement: HTMLInputElement;
	let dropdownElement: HTMLUListElement | null = $state(null);
	let emoji: string = $state('');

	const ifOptionSelected = (id: number | null) => {
		let textValue = '';
		if (id) {
			const value = options.find((option) => option.id === id);
			if (value) {
				emoji = 'emoji' in value ? (value.emoji ?? '') : '';
				textValue = 'name' in value ? value.name : '';
				selectSet = true;
			}
		}
		return textValue;
	};

	let filterInput = $state(ifOptionSelected(selectedOptionId));
	let searcher = $state(new FuzzySearch(options, ['name'], { caseSensitive: false, sort: true }));

	$effect(() => {
		searcher = new FuzzySearch(options, ['name'], { caseSensitive: false, sort: true });
	});

	let filteredOptions = $derived(filterInput ? searcher.search(filterInput) : options);

	const handleSelect = (option: ComboOption | CountryBasic | CityBasic) => {
		filterInput = option.name;
		emoji = 'emoji' in option ? (option.emoji ?? '') : '';
		focused = false;
		selectSet = true;
		onSelect(option);
	};

	const handleClear = () => {
		filterInput = '';
		selectSet = false;
		emoji = '';
		onClear();
	};

	const handleClickOutside = (event: MouseEvent) => {
		if (
			inputElement &&
			dropdownElement &&
			!inputElement.contains(event.target as Node) &&
			!dropdownElement.contains(event.target as Node)
		) {
			focused = false;
		}
	};

	$effect(() => {
		if (focused) {
			document.addEventListener('click', handleClickOutside);
		} else {
			document.removeEventListener('click', handleClickOutside);
		}

		return () => {
			document.removeEventListener('click', handleClickOutside);
		};
	});
</script>

<div class="dropdown my-2 w-full py-2">
	<label class="input input-lg w-full !outline-none focus:ring-0">
		<input
			type="text"
			class="w-full focus:ring-0 focus:outline-none"
			onfocus={() => (focused = true)}
			bind:this={inputElement}
			bind:value={filterInput}
			oninput={() => (selectSet = false)}
			placeholder="Type to search"
		/>
		{#if !selectSet}
			<label class="swap swap-rotate" class:swap-active={focused}>
				<div class="swap-off">
					<ChevronDown />
				</div>
				<div class="swap-on">
					<ChevronUp />
				</div>
			</label>
		{:else}
			<label class="relative">
				{#if emoji}
					<span class="absolute -top-0.5 right-5">{emoji}</span>
				{/if}
				<button class="cursor-pointer" onclick={handleClear}><XMark /></button>
			</label>
		{/if}
	</label>
	{#if focused}
		<ul
			bind:this={dropdownElement}
			class={`dropdown-content rounded-box relative z-100 mt-2 max-h-[50vh] w-full gap-1 overflow-y-auto border border-gray-100 bg-white p-2 shadow-md 
			${filteredOptions.length >= 5 ? '' : ''}`}
		>
			{#each filteredOptions as option (option.id)}
				<li class="mb-1">
					<button
						class="btn btn-soft w-full justify-between text-left"
						onclick={() => handleSelect(option)}
					>
						<div class="no-scrollbar overflow-x-auto text-ellipsis whitespace-nowrap">
							{option.name}
						</div>
						<div>
							{(option as CountryBasic)?.emoji ?? ''}
						</div>
					</button>
				</li>
			{/each}
		</ul>
	{/if}
</div>
