<script lang="ts">
	import Search from '@lucide/svelte/icons/search';
	import { Input } from '$lib/components/ui/input';
	import { NovelsDocument, type NovelDto } from '$lib/graphql/__generated__/graphql';
	import { client } from '$lib/graphql/client';

	let searchTerm = $state('');
	let results = $state<NovelDto[]>([]);
	let isOpen = $state(false);
	let fetching = $state(false);
	let searchTimeout: ReturnType<typeof setTimeout> | null = null;
	let containerRef: HTMLDivElement;

	async function fetchResults(term: string) {
		if (!term.trim()) {
			results = [];
			isOpen = false;
			return;
		}

		fetching = true;
		try {
			const result = await client
				.query(NovelsDocument, {
					first: 4,
					where: { name: { contains: term } }
				})
				.toPromise();

			if (result.data?.novels?.edges) {
				results = result.data.novels.edges.map((edge) => edge.node);
				isOpen = results.length > 0;
			} else {
				results = [];
				isOpen = false;
			}
		} catch (error) {
			console.error('Search error:', error);
			results = [];
			isOpen = false;
		} finally {
			fetching = false;
		}
	}

	function handleInput(value: string) {
		searchTerm = value;
		if (searchTimeout) clearTimeout(searchTimeout);
		searchTimeout = setTimeout(() => {
			fetchResults(value);
		}, 300);
	}

	function handleKeydown(event: KeyboardEvent) {
		if (event.key === 'Enter' && searchTerm.trim()) {
			event.preventDefault();
			isOpen = false;
			window.location.href = `/novels?search=${encodeURIComponent(searchTerm.trim())}`;
		} else if (event.key === 'Escape') {
			isOpen = false;
		}
	}

	function handleResultClick() {
		isOpen = false;
		searchTerm = '';
		results = [];
	}

	function handleFocus() {
		if (results.length > 0) {
			isOpen = true;
		}
	}

	function handleClickOutside(event: MouseEvent) {
		if (containerRef && !containerRef.contains(event.target as Node)) {
			isOpen = false;
		}
	}

	function getCoverSrc(novel: NovelDto): string | undefined {
		return novel.coverImage?.newPath ?? novel.coverImage?.originalPath ?? undefined;
	}

	$effect(() => {
		if (typeof window !== 'undefined') {
			document.addEventListener('click', handleClickOutside);
			return () => {
				document.removeEventListener('click', handleClickOutside);
			};
		}
	});
</script>

<div class="relative max-w-xs" bind:this={containerRef}>
	<div class="relative">
		<Search class="absolute left-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
		<Input
			type="search"
			placeholder="Search..."
			class="pl-8"
			value={searchTerm}
			oninput={(e) => handleInput(e.currentTarget.value)}
			onkeydown={handleKeydown}
			onfocus={handleFocus}
		/>
	</div>

	{#if isOpen}
		<div
			class="absolute top-full left-0 right-0 z-50 mt-1 overflow-hidden rounded-md border bg-white shadow-lg dark:bg-gray-900"
		>
			{#if fetching}
				<div class="px-4 py-3 text-sm text-muted-foreground">Searching...</div>
			{:else if results.length === 0}
				<div class="px-4 py-3 text-sm text-muted-foreground">No results found</div>
			{:else}
				{#each results as novel (novel.id)}
					<a
						href="/novels/{novel.id}"
						class="flex items-center gap-3 px-3 py-2 hover:bg-muted transition-colors"
						onclick={handleResultClick}
					>
						{#if getCoverSrc(novel)}
							<img
								src={getCoverSrc(novel)}
								alt=""
								class="h-12 w-9 rounded object-cover flex-shrink-0"
								loading="lazy"
							/>
						{:else}
							<div class="h-12 w-9 rounded bg-muted flex-shrink-0"></div>
						{/if}
						<span class="text-sm font-medium truncate">{novel.name}</span>
					</a>
				{/each}
			{/if}
		</div>
	{/if}
</div>
