<script lang="ts">
	import { onMount } from 'svelte';
	import { goto } from '$app/navigation';
	import { page } from '$app/stores';
	import { get } from 'svelte/store';
	import LibraryResult from '$lib/components/search/LibraryResult.svelte';
	import SnippetCard from '$lib/components/search/SnippetCard.svelte';
	import SearchInput from '$lib/components/search/SearchInput.svelte';
	import { copyToClipboard } from '$lib/utils/copy-to-clipboard';
	import type { LibrarySearchJsonResult, SnippetJson } from '$lib/server/api/formatters';

	// ---------------------------------------------------------------------------
	// State
	// ---------------------------------------------------------------------------

	let libraryName = $state('');
	let selectedLibraryId = $state<string | null>(null);
	let selectedLibraryTitle = $state<string | null>(null);
	let query = $state('');

	let libraryResults = $state<LibrarySearchJsonResult[]>([]);
	let snippets = $state<SnippetJson[]>([]);
	let totalTokens = $state(0);

	let loadingLibraries = $state(false);
	let loadingSnippets = $state(false);
	let libraryError = $state<string | null>(null);
	let snippetError = $state<string | null>(null);
	let copyLabel = $state('Copy as Markdown');

	// ---------------------------------------------------------------------------
	// Derived
	// ---------------------------------------------------------------------------

	const hasLibraryResults = $derived(libraryResults.length > 0);
	const hasSnippets = $derived(snippets.length > 0);
	const step = $derived<'library' | 'docs'>(selectedLibraryId ? 'docs' : 'library');

	// ---------------------------------------------------------------------------
	// Initialise from URL params on mount
	// ---------------------------------------------------------------------------

	onMount(() => {
		const currentPage = get(page);
		const libParam = currentPage.url.searchParams.get('lib');
		const qParam = currentPage.url.searchParams.get('q');

		if (libParam) {
			selectedLibraryId = libParam;
			// Try to restore library name from id for display.
			selectedLibraryTitle = libParam;
		}
		if (qParam) {
			query = qParam;
		}
		if (libParam && qParam) {
			searchDocs();
		}
	});

	// ---------------------------------------------------------------------------
	// Actions
	// ---------------------------------------------------------------------------

	async function searchLibraries() {
		if (!libraryName.trim()) return;
		loadingLibraries = true;
		libraryError = null;
		libraryResults = [];

		try {
			const res = await fetch(
				`/api/v1/libs/search?libraryName=${encodeURIComponent(libraryName)}&query=${encodeURIComponent(query)}`
			);
			if (!res.ok) {
				const data = await res.json();
				throw new Error(data.error ?? `Request failed (${res.status})`);
			}
			const data = await res.json();
			libraryResults = data.results ?? [];
		} catch (e) {
			libraryError = (e as Error).message;
		} finally {
			loadingLibraries = false;
		}
	}

	async function searchDocs() {
		if (!selectedLibraryId || !query.trim()) return;
		loadingSnippets = true;
		snippetError = null;
		snippets = [];
		totalTokens = 0;

		try {
			const url = new URL('/api/v1/context', window.location.origin);
			url.searchParams.set('libraryId', selectedLibraryId);
			url.searchParams.set('query', query);
			const res = await fetch(url);
			if (!res.ok) {
				const data = await res.json();
				throw new Error(data.error ?? `Request failed (${res.status})`);
			}
			const data = await res.json();
			snippets = data.snippets ?? [];
			totalTokens = data.totalTokens ?? 0;

			// Sync URL state.
			goto(
				`/search?lib=${encodeURIComponent(selectedLibraryId)}&q=${encodeURIComponent(query)}`,
				{ replaceState: true, keepFocus: true }
			);
		} catch (e) {
			snippetError = (e as Error).message;
		} finally {
			loadingSnippets = false;
		}
	}

	function selectLibrary(id: string) {
		const found = libraryResults.find((r) => r.id === id);
		selectedLibraryId = id;
		selectedLibraryTitle = found?.title ?? id;
		libraryResults = [];
		libraryName = '';
	}

	function changeLibrary() {
		selectedLibraryId = null;
		selectedLibraryTitle = null;
		snippets = [];
		totalTokens = 0;
		snippetError = null;
		query = '';
		// Reset URL.
		goto('/search', { replaceState: true, keepFocus: true });
	}

	// ---------------------------------------------------------------------------
	// Copy as Markdown
	// ---------------------------------------------------------------------------

	function buildMarkdown(): string {
		const parts: string[] = [];

		for (const snippet of snippets) {
			if (snippet.type === 'code') {
				const lang = snippet.codeList[0]?.language ?? '';
				const code = snippet.codeList[0]?.code ?? '';
				if (snippet.title) parts.push(`### ${snippet.title}`);
				if (snippet.description) parts.push(`*${snippet.description}*`);
				parts.push(`\`\`\`${lang}\n${code}\n\`\`\``);
			} else {
				if (snippet.breadcrumb) parts.push(`*${snippet.breadcrumb}*`);
				parts.push(snippet.text);
			}
			parts.push('---');
		}

		if (parts.at(-1) === '---') parts.pop();
		return parts.join('\n\n');
	}

	async function handleCopy() {
		const markdown = buildMarkdown();
		const ok = await copyToClipboard(markdown);
		copyLabel = ok ? 'Copied!' : 'Failed to copy';
		setTimeout(() => {
			copyLabel = 'Copy as Markdown';
		}, 2000);
	}
</script>

<svelte:head>
	<title>Search — TrueRef</title>
</svelte:head>

<div class="space-y-6">
	<div>
		<h1 class="text-xl font-semibold text-gray-900">Search Documentation</h1>
		<p class="mt-0.5 text-sm text-gray-500">
			Find libraries and query their indexed documentation.
		</p>
	</div>

	{#if step === 'library'}
		<!-- ------------------------------------------------------------------ -->
		<!-- Step 1: Library search                                              -->
		<!-- ------------------------------------------------------------------ -->
		<div class="rounded-xl border border-gray-200 bg-white p-6 shadow-sm">
			<h2 class="mb-1 text-sm font-semibold text-gray-700">Step 1 — Select a library</h2>
			<p class="mb-4 text-xs text-gray-500">
				Enter a library name to find matching indexed repositories.
			</p>

			<SearchInput
				bind:value={libraryName}
				placeholder="Library name, e.g. react, tailwind..."
				onsubmit={searchLibraries}
				loading={loadingLibraries}
			/>
		</div>

		{#if libraryError}
			<div class="rounded-lg bg-red-50 px-4 py-3">
				<p class="text-sm text-red-700">{libraryError}</p>
			</div>
		{/if}

		{#if loadingLibraries}
			<div class="flex items-center justify-center py-12 text-sm text-gray-400">
				Searching libraries...
			</div>
		{:else if hasLibraryResults}
			<div class="space-y-3">
				{#each libraryResults as result (result.id)}
					<LibraryResult {result} onSelect={selectLibrary} />
				{/each}
			</div>
		{:else if libraryName && !loadingLibraries && libraryResults.length === 0 && !libraryError}
			<!-- Only show empty state after a search was executed -->
		{/if}
	{:else}
		<!-- ------------------------------------------------------------------ -->
		<!-- Step 2: Documentation query                                         -->
		<!-- ------------------------------------------------------------------ -->
		<div class="rounded-xl border border-gray-200 bg-white p-6 shadow-sm">
			<div class="mb-4 flex items-center gap-3">
				<div class="flex min-w-0 flex-1 items-center gap-2">
					<span class="shrink-0 rounded bg-green-100 px-2 py-0.5 text-xs font-medium text-green-700">
						Selected
					</span>
					<span class="truncate font-mono text-sm text-gray-700">{selectedLibraryTitle}</span>
				</div>
				<button
					onclick={changeLibrary}
					class="shrink-0 rounded-lg border border-gray-200 px-3 py-1.5 text-xs text-gray-600 transition-colors hover:bg-gray-50"
				>
					Change
				</button>
			</div>

			<h2 class="mb-1 text-sm font-semibold text-gray-700">Step 2 — Query documentation</h2>
			<p class="mb-4 text-xs text-gray-500">Ask a question about this library.</p>

			<SearchInput
				bind:value={query}
				placeholder="What would you like to know?"
				onsubmit={searchDocs}
				loading={loadingSnippets}
			/>
		</div>

		{#if snippetError}
			<div class="rounded-lg bg-red-50 px-4 py-3">
				<p class="text-sm text-red-700">{snippetError}</p>
			</div>
		{/if}

		{#if loadingSnippets}
			<div class="flex items-center justify-center py-12 text-sm text-gray-400">
				Fetching documentation snippets...
			</div>
		{:else if hasSnippets}
			<!-- Summary bar -->
			<div class="flex items-center justify-between">
				<p class="text-sm text-gray-500">
					{snippets.length} snippet{snippets.length === 1 ? '' : 's'} &middot;
					<span class="font-medium text-gray-700">{totalTokens.toLocaleString()} tokens</span>
				</p>
				<button
					onclick={handleCopy}
					class="rounded-lg border border-gray-200 px-3 py-1.5 text-xs text-gray-600 transition-colors hover:bg-gray-50"
				>
					{copyLabel}
				</button>
			</div>

			<!-- Snippet list -->
			<div class="space-y-4">
				{#each snippets as snippet, i (i)}
					<SnippetCard {snippet} />
				{/each}
			</div>
		{:else if query && !loadingSnippets && snippets.length === 0 && !snippetError}
			<div class="flex flex-col items-center py-16 text-center">
				<p class="text-sm text-gray-500">No snippets found for that query.</p>
				<p class="mt-1 text-xs text-gray-400">Try a different question or select another library.</p>
			</div>
		{/if}
	{/if}
</div>
