<!--
  EntityPicker — command-palette style modal for selecting items from a list.
  Supports search filtering, keyboard navigation, grouped items, and current-item highlighting.
-->
<script lang="ts">
	import type { EntityPickerItem } from '$lib/types';
	import { IconSearch, IconX } from '$lib/components/icons';
	import { t } from '$lib/i18n';

	interface Props {
		open: boolean;
		items: EntityPickerItem[];
		current?: string;
		placeholder?: string;
		title?: string;
		onselect: (value: string) => void;
		onclose: () => void;
	}

	const {
		open = $bindable(),
		items,
		current = '',
		placeholder,
		title = '',
		onselect,
		onclose
	}: Props = $props();

	let query = $state('');
	let highlightIndex = $state(0);
	let searchInput: HTMLInputElement | undefined = $state(undefined);
	let listEl: HTMLDivElement | undefined = $state(undefined);

	const filtered = $derived.by(() => {
		const q = query.toLowerCase().trim();
		if (!q) return items;
		return items.filter(
			(item) =>
				item.label.toLowerCase().includes(q) ||
				(item.description?.toLowerCase().includes(q) ?? false)
		);
	});

	/** Group filtered items, preserving insertion order. */
	const grouped = $derived.by(() => {
		const groups: { name: string; items: EntityPickerItem[] }[] = [];
		const seen = new Map<string, number>();
		for (const item of filtered) {
			const groupName = item.group ?? '';
			const idx = seen.get(groupName);
			if (idx !== undefined) {
				groups[idx].items.push(item);
			} else {
				seen.set(groupName, groups.length);
				groups.push({ name: groupName, items: [item] });
			}
		}
		return groups;
	});

	/** Flat list of filtered items for keyboard indexing. */
	const flatFiltered = $derived(filtered);

	$effect(() => {
		if (open) {
			query = '';
			highlightIndex = 0;
			// Focus the search input after the modal renders.
			requestAnimationFrame(() => {
				searchInput?.focus();
			});
		}
	});

	// Reset highlight when filter changes.
	$effect(() => {
		// Access filtered.length to create a dependency.
		void filtered.length;
		highlightIndex = 0;
	});

	function scrollHighlightedIntoView() {
		requestAnimationFrame(() => {
			const el = listEl?.querySelector('[data-highlighted="true"]');
			el?.scrollIntoView({ block: 'nearest' });
		});
	}

	function handleKeydown(event: KeyboardEvent) {
		switch (event.key) {
			case 'ArrowDown': {
				event.preventDefault();
				highlightIndex = (highlightIndex + 1) % flatFiltered.length;
				scrollHighlightedIntoView();
				break;
			}
			case 'ArrowUp': {
				event.preventDefault();
				highlightIndex = (highlightIndex - 1 + flatFiltered.length) % flatFiltered.length;
				scrollHighlightedIntoView();
				break;
			}
			case 'Enter': {
				event.preventDefault();
				const item = flatFiltered[highlightIndex];
				if (item && !item.disabled) {
					onselect(item.value);
				}
				break;
			}
			case 'Escape': {
				event.preventDefault();
				onclose();
				break;
			}
		}
	}

	function handleBackdropClick() {
		onclose();
	}

	function handleItemClick(item: EntityPickerItem) {
		if (item.disabled) return;
		onselect(item.value);
	}

	/** Track the flat index across groups for highlight matching. */
	function flatIndexOf(groupIdx: number, itemIdx: number): number {
		let index = 0;
		for (let g = 0; g < groupIdx; g++) {
			index += grouped[g].items.length;
		}
		return index + itemIdx;
	}
</script>

{#if open}
	<!-- Backdrop -->
	<!-- svelte-ignore a11y_no_static_element_interactions -->
	<div
		class="entity-picker-backdrop"
		onclick={handleBackdropClick}
		onkeydown={handleKeydown}
	></div>

	<!-- Modal -->
	<!-- svelte-ignore a11y_no_static_element_interactions -->
	<div class="entity-picker-container" onkeydown={handleKeydown}>
		<div class="entity-picker-modal" role="dialog" aria-modal="true" aria-label={title}>
			{#if title}
				<div class="entity-picker-header">
					<h2 class="entity-picker-title">{title}</h2>
					<button
						type="button"
						class="entity-picker-close"
						onclick={onclose}
						aria-label="Close"
					>
						<IconX size={18} />
					</button>
				</div>
			{/if}

			<!-- Search -->
			<div class="entity-picker-search">
				<IconSearch size={16} class="entity-picker-search-icon" />
				<input
					bind:this={searchInput}
					bind:value={query}
					type="text"
					class="entity-picker-search-input"
					placeholder={placeholder ?? $t('entityPicker.search')}
					autocomplete="off"
					spellcheck="false"
				/>
				{#if !title}
					<button
						type="button"
						class="entity-picker-close-inline"
						onclick={onclose}
						aria-label="Close"
					>
						<IconX size={16} />
					</button>
				{/if}
			</div>

			<!-- List -->
			<div class="entity-picker-list" bind:this={listEl}>
				{#if flatFiltered.length === 0}
					<div class="entity-picker-empty">
						{$t('entityPicker.noResults')}
					</div>
				{:else}
					{#each grouped as group, gIdx}
						{#if group.name}
							<div class="entity-picker-group-header">{group.name}</div>
						{/if}
						{#each group.items as item, iIdx}
							{@const flatIdx = flatIndexOf(gIdx, iIdx)}
							{@const isHighlighted = flatIdx === highlightIndex}
							{@const isCurrent = item.value === current}
							<button
								type="button"
								class="entity-picker-item"
								class:entity-picker-item--highlighted={isHighlighted && !item.disabled}
								class:entity-picker-item--current={isCurrent}
								class:entity-picker-item--disabled={item.disabled}
								data-highlighted={isHighlighted}
								onclick={() => handleItemClick(item)}
								onmouseenter={() => { highlightIndex = flatIdx; }}
								disabled={item.disabled}
							>
								{#if item.icon}
									<span class="entity-picker-item-icon">{@html item.icon}</span>
								{/if}
								<span class="entity-picker-item-content">
									<span class="entity-picker-item-label">{item.label}</span>
									{#if item.disabledHint}
										<span class="entity-picker-item-hint">{item.disabledHint}</span>
									{:else if item.description}
										<span class="entity-picker-item-description">{item.description}</span>
									{/if}
								</span>
							</button>
						{/each}
					{/each}
				{/if}
			</div>
		</div>
	</div>
{/if}

<style>
	.entity-picker-backdrop {
		position: fixed;
		inset: 0;
		z-index: 60;
		background: var(--surface-overlay);
		backdrop-filter: blur(4px);
		animation: fade-in var(--transition-normal) forwards;
	}

	.entity-picker-container {
		position: fixed;
		inset: 0;
		z-index: 61;
		display: flex;
		align-items: flex-start;
		justify-content: center;
		padding-top: 12vh;
		pointer-events: none;
	}

	.entity-picker-modal {
		pointer-events: auto;
		width: 90vw;
		max-width: 500px;
		background: var(--surface-card);
		border: 1px solid var(--border-primary);
		border-radius: var(--radius-xl);
		box-shadow: var(--shadow-xl);
		overflow: hidden;
		animation: scale-in var(--transition-normal) forwards;
		display: flex;
		flex-direction: column;
	}

	.entity-picker-header {
		display: flex;
		align-items: center;
		justify-content: space-between;
		padding: var(--space-3) var(--space-4);
		border-bottom: 1px solid var(--border-secondary);
	}

	.entity-picker-title {
		font-size: var(--text-sm);
		font-weight: var(--weight-semibold);
		color: var(--text-primary);
		margin: 0;
	}

	.entity-picker-close {
		display: flex;
		align-items: center;
		justify-content: center;
		width: 28px;
		height: 28px;
		border: none;
		border-radius: var(--radius-md);
		background: transparent;
		color: var(--text-tertiary);
		cursor: pointer;
		transition: background var(--transition-fast), color var(--transition-fast);
	}

	.entity-picker-close:hover {
		background: var(--surface-card-hover);
		color: var(--text-primary);
	}

	.entity-picker-search {
		display: flex;
		align-items: center;
		gap: var(--space-2);
		padding: var(--space-3) var(--space-4);
		border-bottom: 1px solid var(--border-secondary);
	}

	:global(.entity-picker-search-icon) {
		flex-shrink: 0;
		color: var(--text-tertiary);
	}

	.entity-picker-search-input {
		flex: 1;
		border: none;
		outline: none;
		background: transparent;
		font-size: var(--text-sm);
		color: var(--text-primary);
		font-family: var(--font-family-sans);
	}

	.entity-picker-search-input::placeholder {
		color: var(--text-tertiary);
	}

	.entity-picker-close-inline {
		flex-shrink: 0;
		display: flex;
		align-items: center;
		justify-content: center;
		width: 24px;
		height: 24px;
		border: none;
		border-radius: var(--radius-sm);
		background: transparent;
		color: var(--text-tertiary);
		cursor: pointer;
		transition: background var(--transition-fast), color var(--transition-fast);
	}

	.entity-picker-close-inline:hover {
		background: var(--surface-card-hover);
		color: var(--text-primary);
	}

	.entity-picker-list {
		overflow-y: auto;
		max-height: 60vh;
		padding: var(--space-1) 0;
	}

	.entity-picker-empty {
		padding: var(--space-8) var(--space-4);
		text-align: center;
		font-size: var(--text-sm);
		color: var(--text-tertiary);
	}

	.entity-picker-group-header {
		padding: var(--space-2) var(--space-4) var(--space-1);
		font-size: var(--text-xs);
		font-weight: var(--weight-semibold);
		color: var(--text-tertiary);
		text-transform: uppercase;
		letter-spacing: 0.05em;
	}

	.entity-picker-item {
		display: flex;
		align-items: center;
		gap: var(--space-3);
		width: 100%;
		padding: var(--space-2) var(--space-4);
		border: none;
		background: transparent;
		cursor: pointer;
		text-align: left;
		font-family: var(--font-family-sans);
		transition: background var(--transition-fast);
		border-left: 3px solid transparent;
	}

	.entity-picker-item--highlighted {
		background: var(--surface-card-hover);
	}

	.entity-picker-item--current {
		border-left-color: var(--color-brand-500);
	}

	.entity-picker-item-icon {
		flex-shrink: 0;
		width: 20px;
		height: 20px;
		display: flex;
		align-items: center;
		justify-content: center;
		color: var(--text-tertiary);
	}

	.entity-picker-item-content {
		display: flex;
		flex-direction: column;
		gap: 1px;
		min-width: 0;
	}

	.entity-picker-item-label {
		font-size: var(--text-sm);
		font-weight: var(--weight-medium);
		color: var(--text-primary);
		white-space: nowrap;
		overflow: hidden;
		text-overflow: ellipsis;
	}

	.entity-picker-item-description {
		font-size: var(--text-xs);
		color: var(--text-tertiary);
		white-space: nowrap;
		overflow: hidden;
		text-overflow: ellipsis;
	}

	.entity-picker-item--disabled {
		opacity: 0.45;
		cursor: default;
		pointer-events: none;
	}

	.entity-picker-item-hint {
		font-size: var(--text-xs);
		color: var(--text-tertiary);
		font-style: italic;
		white-space: nowrap;
	}
</style>
