<script lang="ts">
	import { page } from '$app/stores';
	import { goto } from '$app/navigation';
	import { resolveRoute } from '$app/paths';
	import type { ChatMessage } from '$lib/types';
	import { OverrideLevel } from '$lib/proto/llm_multiverse/v1/common_pb';
	import type { SessionConfig } from '$lib/proto/llm_multiverse/v1/orchestrator_pb';
	import { SessionConfigSchema } from '$lib/proto/llm_multiverse/v1/orchestrator_pb';
	import { create } from '@bufbuild/protobuf';
	import MessageList from '$lib/components/MessageList.svelte';
	import MessageInput from '$lib/components/MessageInput.svelte';
	import OrchestrationProgress from '$lib/components/OrchestrationProgress.svelte';
	import ThinkingSection from '$lib/components/ThinkingSection.svelte';
	import FinalResult from '$lib/components/FinalResult.svelte';
	import SessionSidebar from '$lib/components/SessionSidebar.svelte';
	import ConfigSidebar from '$lib/components/ConfigSidebar.svelte';
	import ThemeToggle from '$lib/components/ThemeToggle.svelte';
	import ConnectionStatus from '$lib/components/ConnectionStatus.svelte';
	import { sessionStore } from '$lib/stores/sessions.svelte';
	import { isNonDefaultConfig } from '$lib/utils/sessionConfig';
	import { createOrchestration } from '$lib/composables/useOrchestration.svelte';

	let messages: ChatMessage[] = $state([]);
	let sessionConfig: SessionConfig = $state(
		create(SessionConfigSchema, { overrideLevel: OverrideLevel.NONE })
	);
	let showConfig = $state(false);
	let showSessionSidebar = $state(false);
	const lineageHref = resolveRoute('/lineage');
	const memoryHref = resolveRoute('/memory');
	const auditHref = resolveRoute('/audit');

	const orchestration = createOrchestration();
	const hasNonDefaultConfig = $derived(isNonDefaultConfig(sessionConfig));

	function navigateToSession(sessionId: string, replace = false) {
		const url = `${resolveRoute('/chat')}?session=${sessionId}`;
		// eslint-disable-next-line svelte/no-navigation-without-resolve
		goto(url, { replaceState: replace });
	}

	$effect(() => {
		const sessionParam = $page.url.searchParams.get('session');
		const session = sessionStore.getOrCreateSession(sessionParam ?? undefined);
		messages = [...session.messages];
		if (!sessionParam || sessionParam !== session.id) {
			navigateToSession(session.id, true);
		}
	});

	function handleNewChat() {
		const session = sessionStore.createSession();
		messages = [];
		orchestration.reset();
		navigateToSession(session.id);
	}

	function handleSelectSession(id: string) {
		sessionStore.switchSession(id);
		const session = sessionStore.activeSession;
		if (session) {
			messages = [...session.messages];
			orchestration.reset();
			navigateToSession(id);
		}
	}

	async function handleSend(content: string) {
		const sessionId = sessionStore.activeSessionId!;
		messages = await orchestration.send(sessionId, content, sessionConfig, messages);
	}

	function handleRetry() {
		const sessionId = sessionStore.activeSessionId!;
		const result = orchestration.retry(sessionId, sessionConfig, messages);
		messages = result.messages;
	}
</script>

<div class="flex h-screen overflow-hidden bg-white dark:bg-gray-900">
	<!-- Desktop sidebar: always visible on md+. Mobile: controlled by showSessionSidebar -->
	<div class="hidden md:flex">
		<SessionSidebar onSelectSession={handleSelectSession} onNewChat={handleNewChat} />
	</div>
	<!-- Mobile sidebar drawer -->
	<div class="md:hidden">
		<SessionSidebar
			onSelectSession={handleSelectSession}
			onNewChat={handleNewChat}
			open={showSessionSidebar}
			onClose={() => (showSessionSidebar = false)}
		/>
	</div>

	<div class="flex min-w-0 flex-1 flex-col">
		<header class="flex items-center justify-between border-b border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 px-3 py-3 md:px-4">
			<div class="flex items-center gap-2">
				<!-- Hamburger menu button (mobile only) -->
				<button
					type="button"
					onclick={() => (showSessionSidebar = true)}
					class="flex h-10 w-10 items-center justify-center rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 md:hidden"
					aria-label="Open sessions sidebar"
				>
					<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
						<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
					</svg>
				</button>
				<h1 class="text-lg font-semibold text-gray-900 dark:text-gray-100">Chat</h1>
				<ConnectionStatus />
			</div>
			<div class="flex items-center gap-1 md:gap-2">
			<!-- eslint-disable svelte/no-navigation-without-resolve -- resolveRoute is resolve; plugin does not recognize the alias -->
			<a
				href={lineageHref}
				class="hidden rounded-lg px-2.5 py-1.5 text-sm text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-gray-100 sm:inline-flex"
			>
				Lineage
			</a>
			<a
				href={memoryHref}
				class="hidden rounded-lg px-2.5 py-1.5 text-sm text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-gray-100 sm:inline-flex"
			>
				Memory
			</a>
			<a
				href={auditHref}
				class="hidden rounded-lg px-2.5 py-1.5 text-sm text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-gray-100 sm:inline-flex"
			>
				Audit
			</a>
			<!-- eslint-enable svelte/no-navigation-without-resolve -->
			<ThemeToggle />
			<button
				type="button"
				onclick={() => (showConfig = !showConfig)}
				class="flex min-h-[44px] min-w-[44px] items-center justify-center gap-1 rounded-lg px-2.5 py-1.5 text-sm md:min-h-0 md:min-w-0
					{showConfig ? 'bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300' : 'bg-gray-100 text-gray-700 hover:bg-gray-200 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600'}"
			>
				{#if hasNonDefaultConfig}
					<span class="h-2 w-2 rounded-full bg-amber-500"></span>
				{/if}
				<span class="hidden sm:inline">Config</span>
				<!-- Config icon for mobile when text is hidden -->
				<svg class="h-5 w-5 sm:hidden" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
					<path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 0 1 1.37.49l1.296 2.247a1.125 1.125 0 0 1-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a7.723 7.723 0 0 1 0 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26 1.43l-1.298 2.247a1.125 1.125 0 0 1-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47 6.47 0 0 1-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.94-1.11.94h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 0 1-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 0 1-1.369-.49l-1.297-2.247a1.125 1.125 0 0 1 .26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 0 1 0-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 0 1-.26-1.43l1.297-2.247a1.125 1.125 0 0 1 1.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28Z" />
					<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
				</svg>
			</button>
			</div>
		</header>

		<MessageList {messages} />

		{#if orchestration.isStreaming}
			<OrchestrationProgress state={orchestration.orchestrationState} />
			<ThinkingSection content={orchestration.intermediateResult} />
		{/if}

		{#if orchestration.isStreaming && messages.length > 0 && messages[messages.length - 1].content === ''}
			<div class="flex justify-start px-4 pb-2">
				<div class="flex items-center gap-1.5 rounded-2xl bg-gray-200 dark:bg-gray-700 px-4 py-2.5">
					<span class="h-2 w-2 animate-bounce rounded-full bg-gray-500 dark:bg-gray-400 [animation-delay:0ms]"
					></span>
					<span
						class="h-2 w-2 animate-bounce rounded-full bg-gray-500 dark:bg-gray-400 [animation-delay:150ms]"
					></span>
					<span
						class="h-2 w-2 animate-bounce rounded-full bg-gray-500 dark:bg-gray-400 [animation-delay:300ms]"
					></span>
				</div>
			</div>
		{/if}

		{#if orchestration.finalResult && !orchestration.isStreaming}
			<FinalResult result={orchestration.finalResult} />
		{/if}

		{#if orchestration.error}
			<div class="mx-4 mb-2 flex items-center justify-between gap-3 rounded-lg bg-red-50 dark:bg-red-900/30 px-4 py-2 text-sm text-red-600 dark:text-red-400">
				<span>{orchestration.error}</span>
				{#if orchestration.lastFailedContent}
					<button
						type="button"
						onclick={handleRetry}
						disabled={orchestration.isStreaming}
						class="shrink-0 rounded-md bg-red-100 px-3 py-1 text-xs font-medium text-red-700 hover:bg-red-200 dark:bg-red-800/50 dark:text-red-300 dark:hover:bg-red-800 disabled:opacity-50"
					>
						Retry
					</button>
				{/if}
			</div>
		{/if}

		<MessageInput onSend={handleSend} disabled={orchestration.isStreaming} />
	</div>

	{#if showConfig}
		<ConfigSidebar
			config={sessionConfig}
			onConfigChange={(c) => (sessionConfig = c)}
			onClose={() => (showConfig = false)}
		/>
	{/if}
</div>
