<script lang="ts">
	import { onMount, tick, onDestroy } from "svelte";
	import { goto } from "$app/navigation";
	import { commandBarOpen } from "$lib/stores/commandBar";
	import { allActiveContexts } from "$lib/stores/agenda";
	import { allPages } from "$lib/stores/wiki";
	import { currentScope, scopeSettings } from "$lib/stores/scopeContext";
	import { sidebarCollapsed } from "$lib/stores/sidebarCollapsed";
	import {
		getOrCreateJournalTopic,
		createHistoryEntry,
		createPage,
		upsertContext,
		contextNameExists,
		pageNameExists,
		createEvent,
	} from "$lib/db/repositories";
	import { newId, today } from "$lib/db/helpers";
	import { authFetch } from "$lib/auth/apiClient";
	import { searchResultsLimit } from "$lib/stores/settings";

	const contextsQuery = allActiveContexts();
	const pagesQuery = allPages();

	let query = $state("");
	let inputEl = $state<HTMLInputElement>();
	let selectedIndex = $state(0);
	let recentContextIds = $state<string[]>([]);
	let isMac = $state(false);

	// Server FTS results
	interface ServerResult {
		id: string;
		type: "nav-history" | "nav-wiki";
		icon: string;
		label: string;
		badge: string;
		action: () => void;
	}
	let serverResults = $state<ServerResult[]>([]);
	let isOffline = $state(false);
	let searchTimer: ReturnType<typeof setTimeout> | null = null;

	$effect(() => {
		const q = query.trim();
		if (q.length < 2 || q.startsWith("/")) {
			serverResults = [];
			isOffline = false;
			if (searchTimer) clearTimeout(searchTimer);
			return;
		}
		if (searchTimer) clearTimeout(searchTimer);
		searchTimer = setTimeout(async () => {
			try {
				const limit = $searchResultsLimit;
				const res = await authFetch(`/api/search?q=${encodeURIComponent(q)}&limit=${limit}`);
				if (!res.ok) throw new Error(`HTTP ${res.status}`);
				const data = await res.json() as {
					history: { id: string; topicId: string; contextId: string; date: string; snippet: string }[];
					pages: { id: string; title: string; snippet: string }[];
				};
				const localPageIds = new Set(
					($pagesQuery ?? [])
						.filter((p) => p.title.toLowerCase().includes(q.toLowerCase()))
						.map((p) => p.id),
				);
				const combined: ServerResult[] = [
					...data.history.map((h) => {
						const isJournal = h.topicId === 'daily-log-journal';
						const targetContextId = isJournal ? 'daily-log' : h.contextId;
						return {
							id: `hist-${h.id}`,
							type: "nav-history" as const,
							icon: isJournal ? "📓" : "📋",
							label: h.snippet.replace(/<[^>]+>/g, ""),
							badge: isJournal ? `JOURNAL ${h.date}` : `MEETING ${h.date}`,
							action: () => {
								closeBar();
								goto(`/context/${targetContextId}?date=${h.date}`);
							},
						};
					}),
					...data.pages
						.filter((p) => !localPageIds.has(p.id))
						.map((p) => ({
							id: `page-fts-${p.id}`,
							type: "nav-wiki" as const,
							icon: "📄",
							label: p.title,
							badge: "WIKI",
							action: () => {
								closeBar();
								goto(`/wiki/${p.id}`);
							},
						})),
				];
				serverResults = combined;
				isOffline = false;
			} catch {
				isOffline = true;
				serverResults = [];
			}
		}, 250);
	});

	onMount(() => {
		isMac = navigator.platform.toUpperCase().indexOf("MAC") >= 0;
	});

	// Subscribe to the store to handle focus
	$effect(() => {
		if ($commandBarOpen) {
			query = "";
			selectedIndex = 0;
			loadRecentContexts();
			tick().then(() => inputEl?.focus());
			// Prevent body scroll when open
			document.body.style.overflow = "hidden";
		} else {
			document.body.style.overflow = "";
		}
	});

	onDestroy(() => {
		if (typeof document !== "undefined") {
			document.body.style.overflow = "";
		}
	});

	function loadRecentContexts() {
		try {
			const stored = sessionStorage.getItem("recentContexts");
			if (stored) {
				recentContextIds = JSON.parse(stored);
			} else {
				recentContextIds = [];
			}
		} catch {
			recentContextIds = [];
		}
	}

	function getContextIcon(type: string) {
		switch (type) {
			case "meeting":
				return "📅";
			case "project":
				return "📋";
			case "person":
				return "👤";
			case "company":
				return "🏢";
			default:
				return "📁";
		}
	}

	function getSubtype(type: string): string {
		switch (type) {
			case "meeting":
				return "MEETING";
			case "project":
				return "PROJEKT";
			case "person":
				return "PERSON";
			case "company":
				return "FIRMA";
			default:
				return "KONTEXT";
		}
	}

	function promptIfEmpty(current: string, label: string): string {
		if (current) return current;
		return window.prompt(`${label}:`) ?? "";
	}

	const results = $derived.by(() => {
		const q = query.trim().toLowerCase();

		if (q.startsWith("/")) {
			// Action mode
			const parts = q.split(" ");
			const cmd = parts[0];
			const text = parts.slice(1).join(" ").trim();

			const actions = [];

			// Show scope-dynamic /note only when not narrowed to /pnote or /bnote
			if ("/note".startsWith(cmd) && !"/pnote".startsWith(cmd) && !"/bnote".startsWith(cmd)) {
				actions.push({
					id: "cmd-note",
					type: "action",
					icon: "📝",
					label: text
						? `Notiz (${$currentScope === "private" ? "Privat" : "Firma"}): "${text}"`
						: `Neu: Notiz (${$currentScope === "private" ? "Privat" : "Firma"})`,
					badge: "BEFEHL",
					action: async () => {
						const t = promptIfEmpty(text, "Titel der Notiz");
						if (!t) return;
						const isPrivateScope = $currentScope === "private";
						await executeNoteCommand(t, isPrivateScope);
					},
				});
			}

			if ("/pnote".startsWith(cmd) && cmd.length > 1) {
				actions.push({
					id: "cmd-pnote",
					type: "action",
					icon: "📝",
					label: text
						? `Notiz (Privat): "${text}"`
						: "Neu: Notiz (Privat)",
					badge: "BEFEHL",
					action: async () => {
						const t = promptIfEmpty(text, "Titel der Notiz");
						if (!t) return;
						await executeNoteCommand(t, true);
					},
				});
			}

			if ("/bnote".startsWith(cmd) && cmd.length > 1) {
				actions.push({
					id: "cmd-bnote",
					type: "action",
					icon: "📝",
					label: text
						? `Notiz (Firma): "${text}"`
						: "Neu: Notiz (Firma)",
					badge: "BEFEHL",
					action: async () => {
						const t = promptIfEmpty(text, "Titel der Notiz");
						if (!t) return;
						await executeNoteCommand(t, false);
					},
				});
			}

			// Show scope-dynamic /todo only when not narrowed to /ptodo or /btodo
			if ("/todo".startsWith(cmd) && !"/ptodo".startsWith(cmd) && !"/btodo".startsWith(cmd)) {
				actions.push({
					id: "cmd-todo",
					type: "action",
					icon: "⏰",
					label: text
						? `Todo (${$currentScope === "private" ? "Privat" : "Firma"}): "${text}"`
						: `Neu: Todo (${$currentScope === "private" ? "Privat" : "Firma"})`,
					badge: "BEFEHL",
					action: async () => {
						const t = promptIfEmpty(text, "Titel des Todos");
						if (!t) return;
						const isPrivateScope = $currentScope === "private";
						await executeTodoCommand(t, isPrivateScope);
					},
				});
			}

			if ("/ptodo".startsWith(cmd) && cmd.length > 1) {
				actions.push({
					id: "cmd-ptodo",
					type: "action",
					icon: "⏰",
					label: text
						? `Todo (Privat): "${text}"`
						: "Neu: Todo (Privat)",
					badge: "BEFEHL",
					action: async () => {
						const t = promptIfEmpty(text, "Titel des Todos");
						if (!t) return;
						await executeTodoCommand(t, true);
					},
				});
			}

			if ("/btodo".startsWith(cmd) && cmd.length > 1) {
				actions.push({
					id: "cmd-btodo",
					type: "action",
					icon: "⏰",
					label: text
						? `Todo (Firma): "${text}"`
						: "Neu: Todo (Firma)",
					badge: "BEFEHL",
					action: async () => {
						const t = promptIfEmpty(text, "Titel des Todos");
						if (!t) return;
						await executeTodoCommand(t, false);
					},
				});
			}

			if ("/page".startsWith(cmd) && !"/ppage".startsWith(cmd) && !"/bpage".startsWith(cmd)) {
				actions.push({
					id: "cmd-page",
					type: "action",
					icon: "📄",
					label: text
						? `Wiki-Seite (${$currentScope === "private" ? "Privat" : "Firma"}): "${text}"`
						: `Neu: Wiki-Seite (${$currentScope === "private" ? "Privat" : "Firma"})`,
					badge: "BEFEHL",
					action: async () => {
						const t = promptIfEmpty(text, "Titel der Wiki-Seite");
						if (!t) return;
						if (await pageNameExists(t)) {
							alert(`Wiki-Seite "${t}" existiert bereits.`);
							return;
						}
						const isPrivateScope = $currentScope === "private";
						const page = await createPage(t, isPrivateScope);
						closeBar();
						goto(`/wiki/${page.id}`);
					},
				});
			}

			if ("/ppage".startsWith(cmd) && cmd.length > 1) {
				actions.push({
					id: "cmd-ppage",
					type: "action",
					icon: "📄",
					label: text
						? `Wiki-Seite (Privat): "${text}"`
						: `Neu: Wiki-Seite (Privat)`,
					badge: "BEFEHL",
					action: async () => {
						const t = promptIfEmpty(text, "Titel der Wiki-Seite");
						if (!t) return;
						if (await pageNameExists(t)) {
							alert(`Wiki-Seite "${t}" existiert bereits.`);
							return;
						}
						const page = await createPage(t, true);
						closeBar();
						goto(`/wiki/${page.id}`);
					},
				});
			}

			if ("/bpage".startsWith(cmd) && cmd.length > 1) {
				actions.push({
					id: "cmd-bpage",
					type: "action",
					icon: "📄",
					label: text
						? `Wiki-Seite (Firma): "${text}"`
						: `Neu: Wiki-Seite (Firma)`,
					badge: "BEFEHL",
					action: async () => {
						const t = promptIfEmpty(text, "Titel der Wiki-Seite");
						if (!t) return;
						if (await pageNameExists(t)) {
							alert(`Wiki-Seite "${t}" existiert bereits.`);
							return;
						}
						const page = await createPage(t, false);
						closeBar();
						goto(`/wiki/${page.id}`);
					},
				});
			}

			if ("/person".startsWith(cmd)) {
				actions.push({
					id: "cmd-person",
					type: "action",
					icon: "👤",
					label: text ? `Person: "${text}"` : `Neu: Person`,
					badge: "BEFEHL",
					action: async () => {
						const raw = promptIfEmpty(text, "Name der Person");
						if (!raw) return;
						const displayName = raw.replace(/\b\w/g, (c) => c.toUpperCase());
						const fullName = `Person ${displayName}`;
						if (await contextNameExists(fullName, "person")) {
							alert(`Person "${displayName}" existiert bereits.`);
							return;
						}
						const id = newId();
						await upsertContext({ id, name: fullName, type: "person", meta: { fullName: displayName, email: "", phone: "", duSince: "", personSubType: "colleague" } });
						closeBar();
						goto(`/context/${id}`);
					},
				});
			}

			if ("/firma".startsWith(cmd)) {
				actions.push({
					id: "cmd-firma",
					type: "action",
					icon: "🏢",
					label: text ? `Firma: "${text}"` : `Neu: Firma`,
					badge: "BEFEHL",
					action: async () => {
						const t = promptIfEmpty(text, "Name der Firma");
						if (!t) return;
						const fullName = `Firma ${t}`;
						if (await contextNameExists(fullName, "company")) {
							alert(`Firma "${t}" existiert bereits.`);
							return;
						}
						const id = newId();
						await upsertContext({ id, name: fullName, type: "company" });
						closeBar();
						goto(`/context/${id}`);
					},
				});
			}
			if ("/sidebar".startsWith(cmd)) {
				actions.push({
					id: "cmd-sidebar",
					type: "action",
					icon: $sidebarCollapsed ? "▶" : "◀",
					label: $sidebarCollapsed ? "Sidebar einblenden" : "Sidebar ausblenden",
					badge: "BEFEHL",
					action: () => {
						sidebarCollapsed.toggle();
						closeBar();
					},
				});
			}

			if ("/home".startsWith(cmd)) {
				actions.push({
					id: "cmd-home",
					type: "action",
					icon: "🏠",
					label: "Journal (Startseite)",
					badge: "BEFEHL",
					action: () => {
						closeBar();
						goto("/");
					},
				});
			}

			if ("/help".startsWith(cmd)) {
				actions.push({
					id: "cmd-help",
					type: "action",
					icon: "❓",
					label: "Hilfe & Befehle anzeigen",
					badge: "BEFEHL",
					action: () => {
						closeBar();
						goto("/help");
					},
				});
			}

			if ("/jf".startsWith(cmd)) {
				actions.push({
					id: "cmd-jf",
					type: "action",
					icon: "📅",
					label: "Zu Jour-Fix springen...",
					badge: "BEFEHL",
					action: () => {}, // Managed by the next items
				});

				// Add matching JFs
				if (text && $contextsQuery) {
					const jfs = $contextsQuery.filter(
						(c) =>
							c.type === "meeting" &&
							c.name.toLowerCase().includes(text),
					);
					jfs.forEach((jf) => {
						actions.push({
							id: `jf-${jf.id}`,
							type: "nav-context",
							icon: "📅",
							label: jf.name,
							badge: "MEETING",
							action: () => {
								closeBar();
								goto(`/context/${jf.id}`);
							},
						});
					});
				}
			}

			if ("/meeting".startsWith(cmd)) {
				actions.push({
					id: "cmd-meeting",
					type: "action",
					icon: "🤝",
					label: text ? `Meeting: "${text}"` : `Neu: Meeting (Titel eingeben)`,
					badge: "BEFEHL",
					action: async () => {
						const title = promptIfEmpty(text, "Meeting-Titel");
						if (!title) return;
						await createEvent(today(), "00:00", title, []);
						closeBar();
						goto("/");
					},
				});
			}

		return actions;
		}

		if (!q) {
			// Recent mode
			const recents = [];
			if ($contextsQuery) {
				for (const id of recentContextIds) {
					const ctx = $contextsQuery.find((c) => c.id === id);
					if (ctx) {
						recents.push({
							id: `ctx-${ctx.id}`,
							type: "nav-context",
							icon: getContextIcon(ctx.type),
							label: ctx.name,
							badge: getSubtype(ctx.type),
							action: () => {
								closeBar();
								goto(`/context/${ctx.id}`);
							},
						});
					}
				}
			}
			return recents.slice(0, 5);
		}

		// Navigate mode: Search contexts and wiki pages
		const searchResults = [];
		let ctxCount = 0;
		if ($contextsQuery) {
			for (const ctx of $contextsQuery) {
				if (ctx.name.toLowerCase().includes(q) && ctxCount < 3) {
					searchResults.push({
						id: `ctx-${ctx.id}`,
						type: "nav-context",
						icon: getContextIcon(ctx.type),
						label: ctx.name,
						badge: getSubtype(ctx.type),
						action: () => {
							closeBar();
							goto(`/context/${ctx.id}`);
						},
					});
					ctxCount++;
				}
			}
		}

		let pageCount = 0;
		if ($pagesQuery) {
			for (const p of $pagesQuery) {
				if (p.title.toLowerCase().includes(q) && pageCount < 3) {
					searchResults.push({
						id: `page-${p.id}`,
						type: "nav-wiki",
						icon: "📄",
						label: p.title,
						badge: "WIKI",
						action: () => {
							closeBar();
							goto(`/wiki/${p.id}`);
						},
					});
					pageCount++;
				}
			}
		}

		return [...searchResults, ...serverResults].slice(0, 10);
	});

	// Reset selection when query changes
	$effect(() => {
		query; // reference to trigger
		selectedIndex = 0;
	});

	function closeBar() {
		$commandBarOpen = false;
	}

	function handleKeydown(e: KeyboardEvent) {
		if (e.key === "Escape") {
			e.preventDefault();
			closeBar();
			return;
		}

		if (!results || results.length === 0) return;

		if (e.key === "ArrowDown") {
			e.preventDefault();
			selectedIndex = (selectedIndex + 1) % results.length;
			ensureVisible();
		} else if (e.key === "ArrowUp") {
			e.preventDefault();
			selectedIndex =
				(selectedIndex - 1 + results.length) % results.length;
			ensureVisible();
		} else if (e.key === "Enter") {
			e.preventDefault();
			const selected = results[selectedIndex];
			if (selected && selected.action) {
				selected.action();
			}
		}
	}

	function ensureVisible() {
		tick().then(() => {
			const el = document.getElementById(`kano-item-${selectedIndex}`);
			if (el) el.scrollIntoView({ block: "nearest" });
		});
	}

	async function executeNoteCommand(text: string, isPrivate: boolean) {
		const topic = await getOrCreateJournalTopic();
		await createHistoryEntry(
			topic.id,
			today(),
			text,
			null,
			false,
			isPrivate,
		);
		closeBar();
		if (window.location.pathname === "/context/daily-log") {
			// Trigger a reload or just let dexie liveQuery handle it
		} else {
			goto("/context/daily-log");
		}
	}

	async function executeTodoCommand(text: string, isPrivate: boolean) {
		const topic = await getOrCreateJournalTopic();
		await createHistoryEntry(
			topic.id,
			today(),
			text,
			null,
			true,
			isPrivate,
		);
		closeBar();
		if (window.location.pathname !== "/context/daily-log") {
			goto("/context/daily-log");
		}
	}

	function handleBackdropClick(e: MouseEvent) {
		if (e.target === e.currentTarget) {
			closeBar();
		}
	}
</script>

{#if $commandBarOpen}
	<!-- Backdrop -->
	<div
		class="fixed inset-0 z-[200] flex items-start justify-center bg-black/50 backdrop-blur-sm p-4 pt-[20vh]"
		onclick={handleBackdropClick}
		role="dialog"
		aria-label="Command Bar"
	>
		<!-- Modal -->
		<div
			class="w-full max-w-lg rounded-xl border border-amber-500/30 bg-zinc-800 shadow-2xl overflow-hidden flex flex-col"
		>
			<div class="flex items-center border-b border-[#444] px-4 py-3">
				<span class="mr-3 text-lg text-muted">🔍</span>
				<input
					bind:this={inputEl}
					bind:value={query}
					onkeydown={handleKeydown}
					type="text"
					class="w-full bg-transparent text-lg text-white placeholder-muted outline-none"
					placeholder="Suchen oder Befehl eingeben..."
				/>
				<span
					class="ml-2 text-xs text-muted font-mono rounded bg-zinc-700 px-1.5 py-0.5"
					>ESC</span
				>
			</div>

			{#if results && results.length > 0}
				<div class="max-h-80 overflow-y-auto py-2">
					{#each results as item, i (item.id)}
						<button
							id={`kano-item-${i}`}
							class="w-full flex items-center justify-between px-4 py-3 text-left transition-colors {i ===
							selectedIndex
								? 'bg-zinc-700'
								: 'hover:bg-zinc-700/50'}"
							onmouseover={() => (selectedIndex = i)}
							onclick={() => item.action()}
						>
							<div class="flex items-center truncate">
								<span class="mr-3 text-lg">{item.icon}</span>
								<span class="truncate text-white"
									>{item.label}</span
								>
							</div>
							<div class="ml-4 flex items-center shrink-0">
								<span
									class="text-[10px] font-bold tracking-wider text-muted opacity-80"
									>{item.badge}</span
								>
								{#if i === selectedIndex}
									<span class="ml-3 text-sm text-accent"
										>↵</span
									>
								{/if}
							</div>
						</button>
					{/each}
				</div>
			{:else if query}
				<div class="px-4 py-8 text-center text-muted">
					Keine Ergebnisse für "{query}"
				</div>
			{/if}
		{#if isOffline}
			<div class="px-4 py-1.5 text-[11px] text-zinc-500 border-t border-zinc-700">
				Server nicht erreichbar — nur lokale Ergebnisse
			</div>
		{/if}
		</div>
	</div>
{/if}
