<script lang="ts">
	import { createEventDispatcher } from 'svelte';

	export let id: string | null = null;
	export let value = '';
	export let inputValue = '';
	export let suggestionRequired = false;
	export let emptyAllowed = false;
	export let searchSuggestionFunc: (
		input: string
	) => Promise<{ name: string; value: string }[]> = () => Promise.resolve([]);
	export let invalidMessage: string | null = null;
	export let size: 'xs' | 'sm' | 'md' | 'lg' = 'md';
	export let label: string | null = null;
	export let required = false;

	const dispatch = createEventDispatcher();

	let searchSuggestions: { name: string; value: string }[] = [];
	$: if (!suggestionRequired) value = inputValue;
</script>

<div class="relative">
	<div>
		{#if label}
			<label class="label" for={id}>
				<span class="label-text">
					{label}
					{#if required}
						<span class="text-red-700">*</span>
					{/if}
				</span>
			</label>
		{/if}
		<input
			type="search"
			class="input input-bordered w-full"
			class:input-xs={size === 'xs'}
			class:input-sm={size === 'sm'}
			class:input-md={size === 'md'}
			class:input-lg={size === 'lg'}
			{id}
			{required}
			bind:value={inputValue}
			on:input={(e) => {
				value = '';
				searchSuggestionFunc(inputValue).then((v) => {
					searchSuggestions = v;
					const searchSuggestion = v.find((v) => v.name === inputValue);
					if (searchSuggestion !== undefined) {
						inputValue = searchSuggestion.name;
						value = searchSuggestion.value;
						searchSuggestions = [];
						e.target?.setCustomValidity('');
						dispatch('submit', { input: inputValue, value: value });
					} else if (inputValue === '' && emptyAllowed) {
						dispatch('submit', { input: '', value: '' });
					}
				});
			}}
			on:invalid={(e) => {
				if (invalidMessage != null) e.target?.setCustomValidity(invalidMessage);
			}}
			pattern={suggestionRequired
				? `${value ? inputValue : 'a^' + (emptyAllowed ? '|$^' : '')}`
				: null}
		/>
	</div>

	{#if inputValue && searchSuggestions.length !== 0}
		<ul class="absolute bg-base-200 w-full z-20 menu menu-sm rounded-box">
			{#each searchSuggestions as searchSuggestion}
				<li class="w-full text-left">
					<button
						class="block w-full overflow-hidden text-ellipsis whitespace-nowrap"
						title="{searchSuggestion.name} ({searchSuggestion.value})"
						on:click|preventDefault={() => {
							inputValue = searchSuggestion.name;
							value = searchSuggestion.value;
							searchSuggestions = [];
							dispatch('submit', { input: inputValue, value: value });
						}}>{searchSuggestion.name}</button
					>
				</li>
			{/each}
		</ul>
	{/if}
</div>

<!-- close the search suggestions box when clicking outside -->
{#if inputValue && searchSuggestions.length !== 0}
	<button
		class="absolute top-0 left-0 z-10 w-full h-full cursor-default"
		on:click={() => (searchSuggestions = [])}
	/>
{/if}
