<script lang="ts">
	import { t } from 'svelte-i18n';
	import { Search } from 'lucide-svelte';

	export interface EntityPickerItem {
		value: string;
		label: string;
		icon?: string | null;
		desc?: string | null;
	}

	interface Props {
		items: EntityPickerItem[];
		value: string;
		onchange?: (value: string) => void;
		placeholder?: string;
		searchPlaceholder?: string;
		allowNone?: boolean;
		noneLabel?: string;
		name?: string;
	}

	let {
		items,
		value = $bindable(),
		onchange,
		placeholder = '',
		searchPlaceholder = '',
		allowNone = false,
		noneLabel = '—',
		name
	}: Props = $props();

	let open = $state(false);
	let query = $state('');
	let highlightIdx = $state(0);
	let listEl = $state<HTMLDivElement>();
	let inputEl = $state<HTMLInputElement>();

	const selectedItem = $derived(items.find((i) => i.value === value));

	const allItems = $derived.by(() => {
		const result: (EntityPickerItem & { _isNone?: boolean })[] = [];
		if (allowNone) {
			result.push({ value: '', label: noneLabel, icon: null, desc: null, _isNone: true });
		}
		result.push(...items);
		return result;
	});

	const filtered = $derived.by(() => {
		if (!query.trim()) return allItems;
		const q = query.toLowerCase().trim();
		return allItems.filter(
			(i) =>
				i.label.toLowerCase().includes(q) || (i.desc && i.desc.toLowerCase().includes(q))
		);
	});

	$effect(() => {
		if (open) {
			// Reset highlight to current value when opened
			const idx = filtered.findIndex((i) => i.value === value);
			highlightIdx = idx >= 0 ? idx : 0;
		}
	});

	function openPicker() {
		query = '';
		highlightIdx = 0;
		open = true;
		requestAnimationFrame(() => inputEl?.focus());
	}

	function closePicker() {
		open = false;
		query = '';
	}

	function selectItem(item: EntityPickerItem) {
		value = item.value;
		closePicker();
		onchange?.(item.value);
	}

	function handleKeydown(e: KeyboardEvent) {
		if (e.key === 'ArrowDown') {
			e.preventDefault();
			highlightIdx = Math.min(highlightIdx + 1, filtered.length - 1);
			scrollHighlightIntoView();
		} else if (e.key === 'ArrowUp') {
			e.preventDefault();
			highlightIdx = Math.max(highlightIdx - 1, 0);
			scrollHighlightIntoView();
		} else if (e.key === 'Enter') {
			e.preventDefault();
			if (filtered[highlightIdx]) {
				selectItem(filtered[highlightIdx]);
			}
		} else if (e.key === 'Escape') {
			e.preventDefault();
			closePicker();
		} else if (e.key === 'Tab') {
			e.preventDefault();
		}
	}

	function scrollHighlightIntoView() {
		requestAnimationFrame(() => {
			const el = listEl?.querySelector('.ep-highlight');
			el?.scrollIntoView({ block: 'nearest' });
		});
	}

	function handleBackdropClick(e: MouseEvent) {
		if (e.target === e.currentTarget) closePicker();
	}

	// Reset highlight when query changes
	$effect(() => {
		// eslint-disable-next-line @typescript-eslint/no-unused-expressions
		query; // track
		highlightIdx = 0;
	});
</script>

{#if name}
	<input type="hidden" {name} {value} />
{/if}

<button
	type="button"
	class="flex w-full items-center gap-2 rounded-xl border border-input bg-background px-3 py-2 text-sm text-foreground transition-colors hover:border-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/30"
	onclick={openPicker}
>
	{#if selectedItem}
		{#if selectedItem.icon}
			<span class="flex h-4 w-4 shrink-0 items-center justify-center text-muted-foreground">
				<span>{selectedItem.icon}</span>
			</span>
		{/if}
		<span class="flex-1 truncate text-left">{selectedItem.label}</span>
	{:else if allowNone && !value}
		<span class="flex-1 text-left text-muted-foreground">{noneLabel}</span>
	{:else if placeholder}
		<span class="flex-1 text-left text-muted-foreground">{placeholder}</span>
	{/if}
	<span class="shrink-0 text-xs text-muted-foreground">&#x25BE;</span>
</button>

{#if open}
	<!-- svelte-ignore a11y_no_static_element_interactions -->
	<div
		class="fixed inset-0 z-50 flex items-start justify-center bg-black/50 pt-[15vh] backdrop-blur-sm"
		onclick={handleBackdropClick}
		onkeydown={() => {}}
		style="animation: epFadeIn 0.15s ease-out"
	>
		<div
			class="flex w-full max-w-md flex-col rounded-[1.4rem] border border-border bg-popover shadow-[var(--shadow-lift)]"
			style="max-height: 60vh; animation: epSlideDown 0.2s cubic-bezier(0.16, 1, 0.3, 1)"
			role="dialog"
			aria-label={searchPlaceholder || 'Select entity'}
		>
			<!-- Search row -->
			<div class="flex items-center gap-2 border-b border-border px-3 py-2.5">
				<Search size={16} class="shrink-0 text-muted-foreground" />
				<input
					bind:this={inputEl}
					bind:value={query}
					type="text"
					placeholder={searchPlaceholder || $t('admin.perm_search_placeholder') || 'Search...'}
					class="flex-1 bg-transparent text-sm text-foreground placeholder:text-muted-foreground focus:outline-none"
					autocomplete="off"
					spellcheck="false"
					onkeydown={handleKeydown}
				/>
			</div>

			<!-- List -->
			<div class="overflow-y-auto py-1" bind:this={listEl}>
				{#if filtered.length === 0}
					<div class="py-6 text-center text-sm text-muted-foreground">—</div>
				{:else}
					{#each filtered as item, i (item.value + (item._isNone ? '_none' : ''))}
						<button
							type="button"
							class="flex w-full items-center gap-3 px-3 py-2 text-left text-sm transition-colors
								{i === highlightIdx ? 'ep-highlight bg-accent' : 'hover:bg-accent/50'}
								{item.value === value && !item._isNone ? 'border-l-[3px] border-l-primary' : 'border-l-[3px] border-l-transparent'}"
							onclick={() => selectItem(item)}
							onmouseenter={() => (highlightIdx = i)}
						>
							{#if item.icon}
								<span
									class="flex h-5 w-5 shrink-0 items-center justify-center text-muted-foreground"
								>
									<span>{item.icon}</span>
								</span>
							{/if}
							<span class="flex-1 truncate text-foreground">{item.label}</span>
							{#if item.desc}
								<span class="shrink-0 truncate text-xs text-muted-foreground" style="max-width: 40%">
									{item.desc}
								</span>
							{/if}
						</button>
					{/each}
				{/if}
			</div>

			<!-- Footer -->
			<div
				class="border-t border-border px-3 py-1.5 text-[11px] text-muted-foreground"
			>
				↑↓ navigate · Enter select · Esc close
			</div>
		</div>
	</div>
{/if}

<style>
	@keyframes epFadeIn {
		from {
			opacity: 0;
		}
		to {
			opacity: 1;
		}
	}
	@keyframes epSlideDown {
		from {
			opacity: 0;
			transform: translateY(-12px) scale(0.98);
		}
		to {
			opacity: 1;
			transform: translateY(0) scale(1);
		}
	}
</style>
