<script lang="ts">
	import { tick } from 'svelte';
	import { Bot, Brain, SendHorizonal, X } from '@lucide/svelte';

	type ChatRole = 'user' | 'assistant';

	type SourceLink = {
		id: string;
		title: string;
		type: string;
		href: string;
	};

	type Message = {
		role: ChatRole;
		content: string;
		sources?: SourceLink[];
	};

	type AssistantState = {
		lastMutation?: {
			type: 'append' | 'create';
			itemId: string;
			itemTitle: string;
			additionId?: string;
			content: string;
			createdItemId?: string;
		};
		pendingDelete?: {
			itemId: string;
			itemTitle: string;
		};
	};

	interface Props {
		open: boolean;
		onclose: () => void;
	}

	let { open = $bindable(), onclose }: Props = $props();

	const intro =
		'Ask Brain to save a note, add to an existing note, answer from your notes, or delete something. I will reuse the existing Brain workflow when a new item should be created.';

	let messages = $state<Message[]>([{ role: 'assistant', content: intro }]);
	let input = $state('');
	let sending = $state(false);
	let error = $state('');
	let composerEl: HTMLInputElement | null = $state(null);
	let threadEndEl: HTMLDivElement | null = $state(null);
	let assistantState = $state<AssistantState>({});

	async function scrollThreadToBottom(behavior: ScrollBehavior = 'smooth') {
		await tick();
		requestAnimationFrame(() => {
			threadEndEl?.scrollIntoView({ block: 'end', behavior });
		});
	}

	function resetThread() {
		messages = [{ role: 'assistant', content: intro }];
		input = '';
		error = '';
		assistantState = {};
	}

	async function sendMessage(content: string) {
		const clean = content.trim();
		if (!clean) return;

		error = '';
		sending = true;
		const nextMessages = [...messages, { role: 'user' as const, content: clean }];
		messages = nextMessages;
		input = '';
		void scrollThreadToBottom('auto');

		try {
			const response = await fetch('/api/assistant/brain', {
				method: 'POST',
				headers: { 'content-type': 'application/json' },
				body: JSON.stringify({
					messages: nextMessages,
					state: assistantState
				})
			});
			const data = await response.json().catch(() => ({}));
			if (!response.ok) {
				throw new Error(data?.error || data?.reply || 'Brain assistant request failed');
			}

			assistantState = data?.state || {};
			messages = [
				...nextMessages,
				{
					role: 'assistant',
					content: data?.reply || 'Done.',
					sources: Array.isArray(data?.sources) ? data.sources : []
				}
			];
			await scrollThreadToBottom();
		} catch (err) {
			error = err instanceof Error ? err.message : 'Brain assistant request failed';
		} finally {
			sending = false;
			requestAnimationFrame(() => composerEl?.focus());
		}
	}

	function handleSubmit() {
		void sendMessage(input);
	}

	function handleKeydown(event: KeyboardEvent) {
		if (event.key === 'Escape') {
			onclose();
			return;
		}
		if (event.key === 'Enter' && !event.shiftKey) {
			event.preventDefault();
			handleSubmit();
		}
	}

	$effect(() => {
		if (open) {
			requestAnimationFrame(() => composerEl?.focus());
		}
	});

	$effect(() => {
		if (!open) return;
		document.body.classList.add('assistant-open');
		return () => {
			document.body.classList.remove('assistant-open');
		};
	});
</script>

{#if open}
	<button class="assistant-backdrop" aria-label="Close assistant" onclick={onclose}></button>

	<div class="assistant-drawer" role="dialog" aria-label="Brain assistant">
		<header class="assistant-head">
			<div class="assistant-title-wrap">
				<div class="assistant-mark">
					<Brain size={16} strokeWidth={1.9} />
				</div>
				<div>
					<div class="assistant-kicker">Assistant</div>
					<div class="assistant-title">Brain chat</div>
				</div>
			</div>

			<div class="assistant-head-actions">
				<button class="assistant-ghost" onclick={resetThread}>Reset</button>
				<button class="assistant-close" onclick={onclose} aria-label="Close assistant">
					<X size={17} strokeWidth={1.9} />
				</button>
			</div>
		</header>

		<div class="assistant-body">
			<section class="thread">
				<div class="thread-spacer" aria-hidden="true"></div>
				{#each messages as message}
					<div class="bubble-row" class:user={message.role === 'user'}>
						{#if message.role === 'assistant'}
							<div class="bubble-icon">
								<Bot size={14} strokeWidth={1.8} />
							</div>
						{/if}
						<div class="bubble-stack" class:user={message.role === 'user'}>
							<div class="bubble" class:user={message.role === 'user'}>
								{message.content}
							</div>

							{#if message.sources?.length}
								<div class="source-list">
									{#each message.sources as source}
										<a class="source-chip" href={source.href}>
											<span>{source.title}</span>
											<small>{source.type}</small>
										</a>
									{/each}
								</div>
							{/if}
						</div>
					</div>
				{/each}
				<div bind:this={threadEndEl}></div>
			</section>

			{#if error}
				<div class="assistant-error">{error}</div>
			{/if}
		</div>

		<footer class="assistant-compose">
			<div class="compose-box">
				<input
					bind:this={composerEl}
					bind:value={input}
					class="compose-input"
					type="text"
					placeholder="Ask Brain to save, find, answer, or delete..."
					onkeydown={handleKeydown}
					disabled={sending}
				/>
				<button class="send-btn" onclick={handleSubmit} disabled={sending || !input.trim()}>
					<SendHorizonal size={15} strokeWidth={2} />
				</button>
			</div>
		</footer>
	</div>
{/if}

<style>
	.assistant-backdrop {
		position: fixed;
		inset: 0;
		background: rgba(33, 23, 14, 0.18);
		backdrop-filter: blur(10px);
		z-index: 80;
		border: none;
	}

	:global(body.assistant-open) {
		overflow: hidden;
		touch-action: none;
	}

	.assistant-drawer {
		position: fixed;
		top: 18px;
		right: 18px;
		bottom: 18px;
		width: min(460px, calc(100vw - 24px));
		background: linear-gradient(180deg, rgba(249, 244, 238, 0.98), rgba(244, 236, 226, 0.98));
		border: 1px solid rgba(35, 26, 17, 0.08);
		border-radius: 28px;
		box-shadow: 0 28px 80px rgba(35, 26, 17, 0.18);
		backdrop-filter: blur(18px);
		display: grid;
		grid-template-rows: auto minmax(0, 1fr) auto;
		z-index: 90;
		overflow: hidden;
	}

	.assistant-head {
		display: flex;
		align-items: center;
		justify-content: space-between;
		padding: 18px 18px 14px;
		border-bottom: 1px solid rgba(35, 26, 17, 0.08);
	}

	.assistant-title-wrap {
		display: flex;
		align-items: center;
		gap: 12px;
	}

	.assistant-mark {
		width: 34px;
		height: 34px;
		border-radius: 12px;
		display: grid;
		place-items: center;
		background: rgba(34, 24, 14, 0.08);
		color: #231a11;
	}

	.assistant-kicker {
		font-size: 0.68rem;
		font-weight: 700;
		letter-spacing: 0.12em;
		text-transform: uppercase;
		color: #8a7866;
	}

	.assistant-title {
		font-size: 1rem;
		font-weight: 700;
		letter-spacing: -0.04em;
		color: #18120c;
	}

	.assistant-head-actions {
		display: flex;
		align-items: center;
		gap: 8px;
	}

	.assistant-ghost,
	.assistant-close,
	.send-btn {
		border: none;
		cursor: pointer;
		font-family: inherit;
	}

	.assistant-ghost {
		padding: 8px 12px;
		border-radius: 999px;
		background: rgba(35, 26, 17, 0.06);
		color: #5d5248;
		font-size: 0.78rem;
		font-weight: 600;
	}

	.assistant-close {
		width: 36px;
		height: 36px;
		border-radius: 999px;
		background: rgba(35, 26, 17, 0.06);
		color: #2c241d;
		display: grid;
		place-items: center;
	}

	.assistant-body {
		min-height: 0;
		padding: 0 10px 10px;
	}

	.thread {
		height: 100%;
		overflow-y: auto;
		padding: 10px 8px 12px;
		-webkit-overflow-scrolling: touch;
	}

	.thread-spacer {
		height: 24px;
	}

	.bubble-row {
		display: flex;
		align-items: flex-start;
		gap: 10px;
		margin-bottom: 14px;
	}

	.bubble-row.user {
		justify-content: flex-end;
	}

	.bubble-icon {
		width: 28px;
		height: 28px;
		border-radius: 999px;
		display: grid;
		place-items: center;
		background: rgba(35, 26, 17, 0.08);
		color: #2d241b;
		flex-shrink: 0;
	}

	.bubble-stack {
		max-width: 78%;
		display: grid;
		gap: 8px;
	}

	.bubble-stack.user {
		justify-items: end;
	}

	.bubble {
		padding: 11px 14px;
		border-radius: 18px;
		background: rgba(255, 252, 248, 0.92);
		border: 1px solid rgba(35, 26, 17, 0.07);
		color: #221a13;
		line-height: 1.55;
		white-space: pre-wrap;
		word-break: break-word;
	}

	.bubble.user {
		background: #1f1812;
		color: #fff8f1;
		border-color: #1f1812;
	}

	.source-list {
		display: grid;
		gap: 8px;
	}

	.source-chip {
		display: flex;
		align-items: center;
		justify-content: space-between;
		gap: 10px;
		padding: 10px 12px;
		border-radius: 14px;
		text-decoration: none;
		background: rgba(255, 252, 248, 0.78);
		border: 1px solid rgba(35, 26, 17, 0.07);
		color: #2c241d;
	}

	.source-chip small {
		color: #8a7866;
		text-transform: uppercase;
		letter-spacing: 0.08em;
		font-size: 0.62rem;
	}

	.assistant-error {
		margin: 0 8px 6px;
		padding: 10px 12px;
		border-radius: 14px;
		background: rgba(150, 34, 22, 0.08);
		color: #8f3428;
		font-size: 0.84rem;
	}

	.assistant-compose {
		padding: 12px 14px 14px;
		border-top: 1px solid rgba(35, 26, 17, 0.08);
		background: rgba(248, 242, 235, 0.84);
	}

	.compose-box {
		display: flex;
		align-items: center;
		gap: 10px;
		padding: 10px 10px 10px 14px;
		border-radius: 18px;
		background: rgba(255, 252, 248, 0.88);
		border: 1px solid rgba(35, 26, 17, 0.08);
	}

	.compose-input {
		flex: 1;
		border: none;
		background: transparent;
		color: #1f1812;
		font-size: 1rem;
		font-family: inherit;
		outline: none;
	}

	.compose-input::placeholder {
		color: #8a7866;
	}

	.send-btn {
		width: 36px;
		height: 36px;
		border-radius: 999px;
		display: grid;
		place-items: center;
		background: #1f1812;
		color: #fff8f1;
	}

	.send-btn:disabled {
		opacity: 0.45;
		cursor: default;
	}

	@media (max-width: 768px) {
		.assistant-drawer {
			top: 12px;
			right: 12px;
			left: 12px;
			bottom: 12px;
			width: auto;
			border-radius: 24px;
		}

		.bubble-stack {
			max-width: 88%;
		}
	}
</style>
