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

	export interface IconGridItem {
		value: string;
		icon: string;
		label: string;
		desc?: string;
	}

	interface Props {
		items: IconGridItem[];
		value: string;
		onchange?: (value: string) => void;
		columns?: number;
		placeholder?: string;
		name?: string;
	}

	let { items, value = $bindable(), onchange, columns = 2, placeholder = '', name }: Props =
		$props();

	let open = $state(false);
	let triggerEl: HTMLButtonElement;
	let popupEl: HTMLDivElement;
	let filterQuery = $state('');

	const selectedItem = $derived(items.find((i) => i.value === value));
	const showFilter = $derived(items.length > 9);
	const filteredItems = $derived(
		filterQuery
			? items.filter((i) => {
					const text = `${i.label} ${i.desc || ''}`.toLowerCase();
					return text.includes(filterQuery.toLowerCase());
				})
			: items
	);

	function toggle() {
		if (open) {
			close();
		} else {
			openPopup();
		}
	}

	function openPopup() {
		open = true;
		filterQuery = '';
		requestAnimationFrame(() => positionPopup());
	}

	function close() {
		open = false;
		filterQuery = '';
	}

	function select(item: IconGridItem) {
		value = item.value;
		close();
		onchange?.(item.value);
	}

	function positionPopup() {
		if (!triggerEl || !popupEl) return;
		const rect = triggerEl.getBoundingClientRect();
		const gap = 6;
		const pad = 8;
		const popupW = Math.max(rect.width, 220);
		const spaceBelow = window.innerHeight - rect.bottom - gap - pad;
		const spaceAbove = rect.top - gap - pad;
		const openUp = spaceBelow < 200 && spaceAbove > spaceBelow;
		const available = openUp ? spaceAbove : spaceBelow;

		let left = rect.left;
		if (left + popupW > window.innerWidth - pad) left = window.innerWidth - pad - popupW;
		if (left < pad) left = pad;

		popupEl.style.left = `${left}px`;
		popupEl.style.width = `${popupW}px`;
		popupEl.style.maxHeight = `${available}px`;

		if (openUp) {
			popupEl.style.top = '';
			popupEl.style.bottom = `${window.innerHeight - rect.top + gap}px`;
		} else {
			popupEl.style.top = `${rect.bottom + gap}px`;
			popupEl.style.bottom = '';
		}
	}

	function handleKeydown(e: KeyboardEvent) {
		if (e.key === 'Escape') {
			e.preventDefault();
			close();
		}
	}

	function handleClickOutside(e: MouseEvent) {
		const target = e.target as HTMLElement;
		if (open && !target.closest('.icon-grid-popup') && !target.closest('.icon-grid-trigger')) {
			close();
		}
	}
</script>

<svelte:window onclick={handleClickOutside} onkeydown={handleKeydown} />

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

<button
	type="button"
	class="icon-grid-trigger flex w-full items-center gap-2 rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground transition-colors hover:border-primary focus:outline-none focus:ring-2 focus:ring-ring"
	bind:this={triggerEl}
	onclick={toggle}
>
	{#if selectedItem}
		<span class="flex h-5 w-5 shrink-0 items-center justify-center text-muted-foreground">
			<span class="text-base">{selectedItem.icon}</span>
		</span>
		<span class="flex-1 text-left">{selectedItem.label}</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}
	<div
		class="icon-grid-popup fixed z-50 overflow-y-auto rounded-lg border border-border bg-popover shadow-xl"
		bind:this={popupEl}
		style="animation: iconGridSlideIn 0.15s ease-out"
	>
		{#if showFilter}
			<div class="border-b border-border px-3 py-2">
				<input
					type="text"
					bind:value={filterQuery}
					placeholder={$t('common.search_filter') ?? 'Filter...'}
					class="w-full bg-transparent text-sm text-foreground placeholder:text-muted-foreground focus:outline-none"
					autofocus
				/>
			</div>
		{/if}
		<div
			class="grid gap-1 p-1.5"
			style:grid-template-columns="repeat({columns}, 1fr)"
		>
			{#each filteredItems as item (item.value)}
				<button
					type="button"
					class="flex flex-col items-center gap-1 rounded-md px-2 py-2.5 text-center transition-colors
						{item.value === value
						? 'border-2 border-primary bg-primary/10 text-foreground'
						: 'border-2 border-transparent hover:bg-accent text-foreground'}"
					onclick={() => select(item)}
				>
					<span class="flex h-6 w-6 items-center justify-center">
						<span class="text-lg">{item.icon}</span>
					</span>
					<span class="text-xs font-medium leading-tight">{item.label}</span>
					{#if item.desc}
						<span class="text-[10px] leading-tight text-muted-foreground">{item.desc}</span>
					{/if}
				</button>
			{/each}
			{#if filteredItems.length === 0}
				<div class="col-span-full py-4 text-center text-xs text-muted-foreground">
					{$t('search.no_results', { values: { query: filterQuery } })}
				</div>
			{/if}
		</div>
	</div>
{/if}

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