<script lang="ts">
	import { t } from 'svelte-i18n';
	import { search } from '$lib/stores/search.svelte.js';
	import SearchResult from './SearchResult.svelte';
	import { goto } from '$app/navigation';

	let inputEl: HTMLInputElement = $state() as HTMLInputElement;
	let resultsEl: HTMLDivElement = $state() as HTMLDivElement;

	$effect(() => {
		if (search.open && inputEl) {
			requestAnimationFrame(() => inputEl?.focus());
		}
	});

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

	function handleKeydown(e: KeyboardEvent) {
		if (e.key === 'ArrowDown') {
			e.preventDefault();
			search.moveSelection(1);
			scrollActiveIntoView();
		} else if (e.key === 'ArrowUp') {
			e.preventDefault();
			search.moveSelection(-1);
			scrollActiveIntoView();
		} else if (e.key === 'Enter') {
			e.preventDefault();
			const item = search.selectCurrent();
			if (item) {
				if (item.action) {
					item.action();
				} else if (item.type === 'app') {
					window.open(item.url, '_blank', 'noopener,noreferrer');
				} else {
					goto(item.url);
				}
				search.close();
			}
		} else if (e.key === 'Tab') {
			e.preventDefault();
		}
	}

	function scrollActiveIntoView() {
		requestAnimationFrame(() => {
			const el = resultsEl?.querySelector('.search-active');
			el?.scrollIntoView({ block: 'nearest' });
		});
	}

	// Track flat index offset per group for keyboard highlight
	function getFlatIndexOffset(groupIdx: number): number {
		let offset = 0;
		for (let i = 0; i < groupIdx; i++) {
			offset += search.grouped[i].items.length;
		}
		return offset;
	}

	const isMac = $derived(
		typeof navigator !== 'undefined' && navigator.platform?.toLowerCase().includes('mac')
	);
</script>

{#if search.open}
	<div
		class="fixed inset-0 z-50 flex items-start justify-center bg-black/50 pt-[15vh] backdrop-blur-sm"
		onclick={handleBackdropClick}
		role="presentation"
		style="animation: searchFadeIn 0.15s ease-out"
	>
		<!-- Dialog -->
		<div
			class="flex w-full max-w-lg flex-col rounded-[1.4rem] border border-border bg-popover shadow-[var(--shadow-lift)]"
			style="max-height: 60vh; animation: searchSlideDown 0.2s cubic-bezier(0.16, 1, 0.3, 1)"
			role="dialog"
			aria-label={$t('search.placeholder')}
		>
			<!-- Input -->
			<div class="flex items-center gap-2 border-b border-border px-4 py-3">
				<svg
					class="h-5 w-5 shrink-0 text-muted-foreground"
					xmlns="http://www.w3.org/2000/svg"
					viewBox="0 0 24 24"
					fill="none"
					stroke="currentColor"
					stroke-width="2"
					stroke-linecap="round"
					stroke-linejoin="round"
				>
					<circle cx="11" cy="11" r="8" />
					<line x1="21" y1="21" x2="16.65" y2="16.65" />
				</svg>
				<input
					bind:this={inputEl}
					bind:value={search.query}
					type="text"
					placeholder={$t('search.placeholder')}
					class="flex-1 bg-transparent text-sm text-foreground placeholder:text-muted-foreground focus:outline-none"
					onkeydown={handleKeydown}
				/>
				<kbd
					class="hidden rounded border border-border bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground sm:inline"
				>
					ESC
				</kbd>
			</div>

			<!-- Results -->
			<div class="overflow-y-auto p-2" bind:this={resultsEl}>
				{#if search.loading}
					<div class="flex items-center justify-center py-8">
						<div
							class="h-5 w-5 animate-spin rounded-full border-2 border-muted-foreground border-t-primary"
						></div>
					</div>
				{:else if search.error}
					<p class="py-6 text-center text-sm text-destructive">{search.error}</p>
				{:else if search.query.length < 2}
					<p class="py-6 text-center text-sm text-muted-foreground">
						{$t('search.min_chars')}
					</p>
				{:else if search.results.length === 0}
					<p class="py-6 text-center text-sm text-muted-foreground">
						{$t('search.no_results', { values: { query: search.query } })}
					</p>
				{:else}
					{#each search.grouped as group, groupIdx (group.key)}
						<div class="mb-2">
							<p
								class="mb-1 px-3 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground"
							>
								{$t(`search.${group.label}s`) ?? group.label}
							</p>
							{#each group.items as result, itemIdx (result.id)}
								{@const flatIdx = getFlatIndexOffset(groupIdx) + itemIdx}
								<SearchResult
									{result}
									active={flatIdx === search.selectedIdx}
									onselect={() => search.close()}
									onhover={() => (search.selectedIdx = flatIdx)}
								/>
							{/each}
						</div>
					{/each}
				{/if}
			</div>

			<!-- Footer -->
			<div class="border-t border-border px-4 py-1.5 text-[11px] text-muted-foreground">
				<span class="inline-flex items-center gap-3">
					<span>↑↓ {$t('search.nav_hint') ?? 'navigate'}</span>
					<span>↵ {$t('search.select_hint') ?? 'select'}</span>
					<span>esc {$t('search.close_hint') ?? 'close'}</span>
					<span class="ml-auto">{isMac ? '⌘' : 'Ctrl'}+K</span>
				</span>
			</div>
		</div>
	</div>
{/if}

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