import { env } from '$env/dynamic/private';
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

type ChatRole = 'user' | 'assistant';

type ChatMessage = {
	role?: ChatRole;
	content?: string;
};

type BrainItem = {
	id: string;
	type: string;
	title?: string | null;
	url?: string | null;
	raw_content?: string | null;
	extracted_text?: string | null;
	folder?: string | null;
	tags?: string[] | null;
	summary?: string | null;
	created_at?: string;
};

type BrainAddition = {
	id: string;
	item_id: string;
	content: string;
	created_at: string;
};

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

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

type SearchQueryDecision = {
	queries?: string[];
};

function recentMessages(messages: unknown): Array<{ role: ChatRole; content: string }> {
	if (!Array.isArray(messages)) return [];
	return messages
		.filter((m) => !!m && typeof m === 'object')
		.map((m) => {
			const message = m as ChatMessage;
			return {
				role: (message.role === 'assistant' ? 'assistant' : 'user') as ChatRole,
				content: typeof message.content === 'string' ? message.content.slice(0, 4000) : ''
			};
		})
		.filter((m) => m.content.trim())
		.slice(-12);
}

function lastUserMessage(messages: Array<{ role: ChatRole; content: string }>): string {
	return [...messages].reverse().find((message) => message.role === 'user')?.content?.trim() || '';
}

function toSource(item: BrainItem): SourceLink {
	return {
		id: item.id,
		title: item.title || 'Untitled',
		type: item.type,
		href: `/brain?item=${item.id}`
	};
}

function isConfirmation(text: string): boolean {
	const clean = text.trim().toLowerCase();
	return [
		'yes',
		'yes delete it',
		'delete it',
		'confirm',
		'yes do it',
		'do it',
		'go ahead'
	].includes(clean);
}

function isUndo(text: string): boolean {
	return /^(undo|undo last change|undo that|revert that)$/i.test(text.trim());
}

function wantsNewNoteInstead(text: string): boolean {
	return /create (?:a )?new note/i.test(text) || /make (?:that|it) a new note/i.test(text);
}

function moveTargetFromText(text: string): string | null {
	const match = text.match(/(?:add|move)\s+(?:that|it)\s+to\s+(.+)$/i);
	return match?.[1]?.trim() || null;
}

function wantsDelete(text: string): boolean {
	return /\bdelete\b/i.test(text) && /\b(note|item|that)\b/i.test(text);
}

function isExplicitUpdateRequest(text: string): boolean {
	return /\b(update|edit|change|replace|correct|set)\b/i.test(text);
}

function isListingIntent(text: string): boolean {
	return /\b(what|which|show|list)\b/i.test(text)
		&& /\b(do i have|have i saved|saved|notes|items|books?|pdfs?|links?|documents?|files?)\b/i.test(text);
}

function buildCandidateSummary(items: BrainItem[]): string {
	if (!items.length) return 'No candidates found.';
	return items
		.map((item, index) => {
			const snippet = (item.raw_content || item.extracted_text || item.summary || '')
				.replace(/\s+/g, ' ')
				.slice(0, 220);
			return `${index + 1}. id=${item.id}
title=${item.title || 'Untitled'}
type=${item.type}
folder=${item.folder || ''}
tags=${(item.tags || []).join(', ')}
snippet=${snippet}`;
		})
		.join('\n\n');
}

async function brainSearch(fetchFn: typeof fetch, q: string, limit = 5): Promise<BrainItem[]> {
	const response = await fetchFn('/api/brain/search/hybrid', {
		method: 'POST',
		headers: { 'content-type': 'application/json' },
		body: JSON.stringify({ q, limit })
	});
	if (!response.ok) return [];
	const body = await response.json().catch(() => ({}));
	return Array.isArray(body?.items) ? body.items : [];
}

function normalizeSearchSeed(text: string): string {
	return text
		.trim()
		.replace(/^what\s+(books?|notes?|pdfs?|links?|documents?|files?)\s+do i have saved\s*/i, '$1 ')
		.replace(/^show me\s+(all\s+)?(books?|notes?|pdfs?|links?|documents?|files?)\s*/i, '$2 ')
		.replace(/^list\s+(my\s+)?(books?|notes?|pdfs?|links?|documents?|files?)\s*/i, '$2 ')
		.replace(/^add note\s+/i, '')
		.replace(/^add\s+/i, '')
		.replace(/^save\s+(?:this|that)\s+/i, '')
		.replace(/^what do i have about\s+/i, '')
		.replace(/^what have i saved about\s+/i, '')
		.replace(/^find\s+/i, '')
		.replace(/^search for\s+/i, '')
		.replace(/^answer\s+/i, '')
		.trim();
}

async function deriveSearchQueries(
	messages: Array<{ role: ChatRole; content: string }>,
	userText: string
): Promise<string[]> {
	const normalized = normalizeSearchSeed(userText);
	const fallback = [normalized || userText.trim()].filter(Boolean);
	if (!env.OPENAI_API_KEY) return fallback;

	const systemPrompt = `You extract concise retrieval queries for a personal knowledge base.

Return ONLY JSON:
{
  "queries": ["query one", "query two"]
}

Rules:
- Return 1 to 3 short search queries.
- Focus on the underlying topic, not chat filler.
- For "what do I have about X", include just X.
- For advice/tips, you may infer a likely broader topic if strongly implied.
- Keep each query short, usually 1 to 5 words.
- Do not include punctuation-heavy sentences.
- Do not include explanatory text.`;

	const response = await fetch('https://api.openai.com/v1/chat/completions', {
		method: 'POST',
		headers: {
			'content-type': 'application/json',
			authorization: `Bearer ${env.OPENAI_API_KEY}`
		},
		body: JSON.stringify({
			model: env.OPENAI_MODEL || 'gpt-5.2',
			response_format: { type: 'json_object' },
			temperature: 0.1,
			max_completion_tokens: 200,
			messages: [
				{ role: 'system', content: systemPrompt },
				...messages.slice(-6),
				{ role: 'user', content: `Search intent: ${userText}` }
			]
		})
	});

	if (!response.ok) return fallback;
	const raw = await response.json().catch(() => null);
	const content = raw?.choices?.[0]?.message?.content;
	if (typeof content !== 'string') return fallback;

	try {
		const parsed = JSON.parse(content) as SearchQueryDecision;
		const queries = Array.isArray(parsed.queries)
			? parsed.queries.map((query) => String(query || '').trim()).filter(Boolean).slice(0, 3)
			: [];
		return queries.length ? queries : fallback;
	} catch {
		return fallback;
	}
}

async function collectCandidates(
	fetchFn: typeof fetch,
	messages: Array<{ role: ChatRole; content: string }>,
	userText: string,
	limit = 8
): Promise<BrainItem[]> {
	const queries = await deriveSearchQueries(messages, userText);
	const merged = new Map<string, BrainItem>();

	for (const query of queries) {
		const items = await brainSearch(fetchFn, query, limit);
		for (const item of items) {
			if (!merged.has(item.id)) merged.set(item.id, item);
		}
	}

	if (!merged.size) {
		for (const item of await brainSearch(fetchFn, userText, limit)) {
			if (!merged.has(item.id)) merged.set(item.id, item);
		}
	}

	return [...merged.values()].slice(0, limit);
}

async function createBrainNote(fetchFn: typeof fetch, content: string, title?: string) {
	const response = await fetchFn('/api/brain/items', {
		method: 'POST',
		headers: { 'content-type': 'application/json' },
		body: JSON.stringify({
			type: 'note',
			raw_content: content,
			title: title?.trim() || undefined
		})
	});
	return {
		ok: response.ok,
		status: response.status,
		body: await response.json().catch(() => ({}))
	};
}

async function updateBrainItem(fetchFn: typeof fetch, itemId: string, body: { raw_content?: string; title?: string }) {
	const response = await fetchFn(`/api/brain/items/${itemId}`, {
		method: 'PATCH',
		headers: { 'content-type': 'application/json' },
		body: JSON.stringify(body)
	});
	return {
		ok: response.ok,
		status: response.status,
		body: await response.json().catch(() => ({}))
	};
}

async function appendToItem(fetchFn: typeof fetch, itemId: string, content: string) {
	const response = await fetchFn(`/api/brain/items/${itemId}/additions`, {
		method: 'POST',
		headers: { 'content-type': 'application/json' },
		body: JSON.stringify({ content, source: 'assistant', kind: 'append' })
	});
	return {
		ok: response.ok,
		status: response.status,
		body: await response.json().catch(() => ({}))
	};
}

async function deleteAddition(fetchFn: typeof fetch, itemId: string, additionId: string) {
	const response = await fetchFn(`/api/brain/items/${itemId}/additions/${additionId}`, {
		method: 'DELETE'
	});
	return response.ok;
}

async function deleteItem(fetchFn: typeof fetch, itemId: string) {
	const response = await fetchFn(`/api/brain/items/${itemId}`, { method: 'DELETE' });
	return response.ok;
}

async function getItem(fetchFn: typeof fetch, itemId: string): Promise<BrainItem | null> {
	const response = await fetchFn(`/api/brain/items/${itemId}`);
	if (!response.ok) return null;
	return response.json().catch(() => null);
}

async function decideAction(
	messages: Array<{ role: ChatRole; content: string }>,
	candidates: BrainItem[],
	state: AssistantState,
	listingIntent = false
) {
	const systemPrompt = `You are the Brain assistant inside a personal app.

You help the user save notes naturally, append thoughts to existing items, answer questions from saved notes, and choose whether to create a new note.

Return ONLY JSON with this shape:
{
  "action": "append_existing" | "create_new_note" | "update_existing" | "answer" | "list_items" | "delete_target",
  "reply": "short reply preview",
  "target_item_id": "optional item id",
  "formatted_content": "text to append or create",
  "create_title": "short AI-generated title when creating a new note",
  "answer": "short answer when action=answer",
  "source_item_ids": ["id1", "id2"],
  "match_confidence": "high" | "low"
}

Rules:
- Use existing items only when the topical match is strong.
- If the match is weak or ambiguous, create a new note.
- The user prefers speed: do not ask which note to use.
- If the user explicitly says update, change, edit, replace, set, or correct, prefer update_existing when one strong existing note clearly matches.
- If the user is asking to list what they have saved, prefer list_items instead of answer.
- For short tips/advice, format as bullets when natural.
- Only fix spelling and grammar. Do not rewrite the meaning.
- For questions, answer briefly and cite up to 3 source ids.
- For list_items, return a concise list-style reply and cite up to 12 source ids.
- For delete requests, choose the most likely target and set action=delete_target.
- Never choose append_existing unless target_item_id is one of the candidate ids.
- Never choose update_existing unless target_item_id is one of the candidate ids.
- If all candidates are weak, set action=create_new_note and match_confidence=low.
- The current assistant state is only for context:
${JSON.stringify(state, null, 2)}
- listing_intent=${listingIntent}
`;

	const response = await fetch('https://api.openai.com/v1/chat/completions', {
		method: 'POST',
		headers: {
			'content-type': 'application/json',
			authorization: `Bearer ${env.OPENAI_API_KEY}`
		},
		body: JSON.stringify({
			model: env.OPENAI_MODEL || 'gpt-5.2',
			response_format: { type: 'json_object' },
			temperature: 0.2,
			max_completion_tokens: 1100,
			messages: [
				{ role: 'system', content: systemPrompt },
				...messages,
				{
					role: 'user',
					content: `Candidate items:\n${buildCandidateSummary(candidates)}`
				}
			]
		})
	});

	if (!response.ok) {
		throw new Error(await response.text());
	}

	const raw = await response.json();
	const content = raw?.choices?.[0]?.message?.content;
	if (typeof content !== 'string') {
		throw new Error('Assistant response was empty.');
	}

	return JSON.parse(content) as {
		action?: 'append_existing' | 'create_new_note' | 'update_existing' | 'answer' | 'list_items' | 'delete_target';
		reply?: string;
		target_item_id?: string;
		formatted_content?: string;
		create_title?: string;
		answer?: string;
		source_item_ids?: string[];
		match_confidence?: 'high' | 'low';
	};
}

async function rewriteExistingItemContent(
	messages: Array<{ role: ChatRole; content: string }>,
	target: BrainItem,
	userInstruction: string
): Promise<string> {
	const existing = (target.raw_content || target.extracted_text || '').trim();
	if (!existing) {
		throw new Error('Target item has no editable content.');
	}

	const systemPrompt = `You edit an existing personal note in place.

Return ONLY JSON:
{
  "updated_content": "full updated note body"
}

Rules:
- Apply the user's requested update to the existing note.
- Preserve the note's structure and wording as much as possible.
- Make the smallest correct change needed.
- Do not append a new line when the user clearly wants an existing value updated.
- Only fix spelling and grammar where needed for the changed text.
- Return the full updated note body, not a diff.`;

	const response = await fetch('https://api.openai.com/v1/chat/completions', {
		method: 'POST',
		headers: {
			'content-type': 'application/json',
			authorization: `Bearer ${env.OPENAI_API_KEY}`
		},
		body: JSON.stringify({
			model: env.OPENAI_MODEL || 'gpt-5.2',
			response_format: { type: 'json_object' },
			temperature: 0.1,
			max_completion_tokens: 900,
			messages: [
				{ role: 'system', content: systemPrompt },
				...messages.slice(-8),
				{
					role: 'user',
					content: `Target title: ${target.title || 'Untitled'}\n\nExisting note:\n${existing}\n\nInstruction: ${userInstruction}`
				}
			]
		})
	});

	if (!response.ok) {
		throw new Error(await response.text());
	}

	const raw = await response.json();
	const content = raw?.choices?.[0]?.message?.content;
	if (typeof content !== 'string') {
		throw new Error('Update response was empty.');
	}
	const parsed = JSON.parse(content) as { updated_content?: string };
	const updated = parsed.updated_content?.trim();
	if (!updated) {
		throw new Error('Updated content was empty.');
	}
	return updated;
}

function sourceLinksFromIds(items: BrainItem[], ids: string[] | undefined): SourceLink[] {
	if (!Array.isArray(ids) || !ids.length) return [];
	const map = new Map(items.map((item) => [item.id, item]));
	return ids.map((id) => map.get(id)).filter(Boolean).map((item) => toSource(item as BrainItem));
}

export const POST: RequestHandler = async ({ request, fetch, cookies }) => {
	if (!cookies.get('platform_session')) {
		return json({ error: 'Unauthorized' }, { status: 401 });
	}
	if (!env.OPENAI_API_KEY) {
		return json({ error: 'Assistant is not configured.' }, { status: 500 });
	}

	const { messages = [], state = {} } = await request.json().catch(() => ({}));
	const chat = recentMessages(messages);
	const userText = lastUserMessage(chat);
	const currentState: AssistantState = state && typeof state === 'object' ? state : {};

	if (!userText) {
		return json({
			reply: 'Tell me what to save, find, answer, or delete.',
			state: currentState,
			sources: []
		});
	}

	if (currentState.pendingDelete && isConfirmation(userText)) {
		const target = currentState.pendingDelete;
		const ok = await deleteItem(fetch, target.itemId);
		if (!ok) {
			return json({ reply: `I couldn't delete "${target.itemTitle}" yet.`, state: currentState, sources: [] }, { status: 500 });
		}
		return json({
			reply: `Deleted "${target.itemTitle}".`,
			state: {},
			sources: []
		});
	}

	if (currentState.lastMutation && isUndo(userText)) {
		if (currentState.lastMutation.type === 'append' && currentState.lastMutation.additionId) {
			const ok = await deleteAddition(fetch, currentState.lastMutation.itemId, currentState.lastMutation.additionId);
			return json({
				reply: ok ? `Undid the change in "${currentState.lastMutation.itemTitle}".` : 'I could not undo that change yet.',
				state: ok ? {} : currentState,
				sources: ok ? [{ id: currentState.lastMutation.itemId, title: currentState.lastMutation.itemTitle, type: 'note', href: `/brain?item=${currentState.lastMutation.itemId}` }] : []
			});
		}
		if (currentState.lastMutation.type === 'create' && currentState.lastMutation.createdItemId) {
			const ok = await deleteItem(fetch, currentState.lastMutation.createdItemId);
			return json({
				reply: ok ? `Removed "${currentState.lastMutation.itemTitle}".` : 'I could not undo that note creation yet.',
				state: ok ? {} : currentState,
				sources: []
			});
		}
		if (currentState.lastMutation.type === 'update' && currentState.lastMutation.previousRawContent !== undefined) {
			const restored = await updateBrainItem(fetch, currentState.lastMutation.itemId, {
				raw_content: currentState.lastMutation.previousRawContent
			});
			return json({
				reply: restored.ok ? `Undid the update in "${currentState.lastMutation.itemTitle}".` : 'I could not undo that update yet.',
				state: restored.ok ? {} : currentState,
				sources: restored.ok ? [{ id: currentState.lastMutation.itemId, title: currentState.lastMutation.itemTitle, type: 'note', href: `/brain?item=${currentState.lastMutation.itemId}` }] : []
			});
		}
	}

	if (currentState.lastMutation && wantsNewNoteInstead(userText)) {
		const content = currentState.lastMutation.content;
		if (currentState.lastMutation.type === 'append' && currentState.lastMutation.additionId) {
			await deleteAddition(fetch, currentState.lastMutation.itemId, currentState.lastMutation.additionId);
		}
		const titleDecision = await decideAction(
			[{ role: 'user', content: `Create a concise title for this note:\n${content}` }],
			[],
			currentState
		).catch(() => ({ create_title: 'New Note' }));
		const created = await createBrainNote(fetch, content, titleDecision.create_title);
		if (!created.ok) {
			return json({ reply: 'I could not create the new note yet.', state: currentState, sources: [] }, { status: 500 });
		}
		const createdItem = created.body as BrainItem;
		return json({
			reply: `Created "${createdItem.title || titleDecision.create_title || 'New note'}".`,
			state: {
				lastMutation: {
					type: 'create',
					itemId: createdItem.id,
					createdItemId: createdItem.id,
					itemTitle: createdItem.title || titleDecision.create_title || 'New note',
					content
				}
			},
			sources: [toSource(createdItem)]
		});
	}

	const retarget = currentState.lastMutation ? moveTargetFromText(userText) : null;
	if (currentState.lastMutation && retarget) {
		if (currentState.lastMutation.type === 'append' && currentState.lastMutation.additionId) {
			await deleteAddition(fetch, currentState.lastMutation.itemId, currentState.lastMutation.additionId);
		} else if (currentState.lastMutation.type === 'create' && currentState.lastMutation.createdItemId) {
			await deleteItem(fetch, currentState.lastMutation.createdItemId);
		}

		const candidates = await collectCandidates(fetch, chat, retarget, 8);
		const target = candidates[0];
		if (!target) {
			const created = await createBrainNote(fetch, currentState.lastMutation.content, retarget);
			if (!created.ok) {
				return json({ reply: 'I could not move that into a new note yet.', state: currentState, sources: [] }, { status: 500 });
			}
			const createdItem = created.body as BrainItem;
			return json({
				reply: `Created "${createdItem.title || retarget}".`,
				state: {
					lastMutation: {
						type: 'create',
						itemId: createdItem.id,
						createdItemId: createdItem.id,
						itemTitle: createdItem.title || retarget,
						content: currentState.lastMutation.content
					}
				},
				sources: [toSource(createdItem)]
			});
		}

		const appended = await appendToItem(fetch, target.id, currentState.lastMutation.content);
		if (!appended.ok) {
			return json({ reply: `I couldn't move that to "${target.title || 'that item'}" yet.`, state: currentState, sources: [] }, { status: 500 });
		}
		return json({
			reply: `Moved it to "${target.title || 'Untitled'}".`,
			state: {
				lastMutation: {
					type: 'append',
					itemId: target.id,
					itemTitle: target.title || 'Untitled',
					additionId: appended.body?.id,
					content: currentState.lastMutation.content
				}
			},
			sources: [toSource(target)]
		});
	}

	const listingIntent = isListingIntent(userText);
	const candidates = await collectCandidates(fetch, chat, userText, listingIntent ? 24 : 8);

	if (isExplicitUpdateRequest(userText) && candidates[0] && (candidates[0].raw_content || candidates[0].extracted_text)) {
		const target = candidates[0];
		try {
			const updatedContent = await rewriteExistingItemContent(chat, target, userText);
			const updated = await updateBrainItem(fetch, target.id, { raw_content: updatedContent });
			if (!updated.ok) {
				return json({ reply: `I couldn't update "${target.title || 'Untitled'}" yet.`, state: currentState, sources: [] }, { status: 500 });
			}
			return json({
				reply: `Updated "${target.title || 'Untitled'}".`,
				state: {
					lastMutation: {
						type: 'update',
						itemId: target.id,
						itemTitle: target.title || 'Untitled',
						content: updatedContent,
						previousRawContent: target.raw_content || target.extracted_text || ''
					}
				},
				sources: [toSource(target)]
			});
		} catch (error) {
			return json(
				{
					reply: `I couldn't update "${target.title || 'Untitled'}" yet.`,
					state: currentState,
					sources: [toSource(target)],
					error: error instanceof Error ? error.message : 'Unknown error'
				},
				{ status: 500 }
			);
		}
	}

	if (wantsDelete(userText) && !currentState.pendingDelete) {
		const target = candidates[0];
		if (!target) {
			return json({ reply: "I couldn't find a note to delete.", state: currentState, sources: [] });
		}
		return json({
			reply: `Delete "${target.title || 'Untitled'}"?`,
			state: {
				...currentState,
				pendingDelete: {
					itemId: target.id,
					itemTitle: target.title || 'Untitled'
				}
			},
			sources: [toSource(target)]
		});
	}

	let decision;
	try {
		decision = await decideAction(chat, candidates, currentState, listingIntent);
	} catch (error) {
		return json(
			{
				reply: 'The Brain assistant did not respond cleanly.',
				state: currentState,
				sources: [],
				error: error instanceof Error ? error.message : 'Unknown error'
			},
			{ status: 500 }
		);
	}

	if (decision.action === 'answer') {
		return json({
			reply: decision.answer || decision.reply || 'I found a few relevant notes.',
			state: currentState,
			sources: sourceLinksFromIds(candidates, decision.source_item_ids)
		});
	}

	if (decision.action === 'list_items') {
		return json({
			reply: decision.answer || decision.reply || 'Here are the matching items I found.',
			state: currentState,
			sources: sourceLinksFromIds(candidates, decision.source_item_ids)
		});
	}

	if (decision.action === 'delete_target' && decision.target_item_id) {
		const target = candidates.find((item) => item.id === decision.target_item_id) || (await getItem(fetch, decision.target_item_id));
		if (!target) {
			return json({ reply: "I couldn't find that note to delete.", state: currentState, sources: [] });
		}
		return json({
			reply: `Delete "${target.title || 'Untitled'}"?`,
			state: {
				...currentState,
				pendingDelete: {
					itemId: target.id,
					itemTitle: target.title || 'Untitled'
				}
			},
			sources: [toSource(target)]
		});
	}

	if (decision.action === 'update_existing' && decision.target_item_id && decision.match_confidence === 'high') {
		const target = candidates.find((item) => item.id === decision.target_item_id) || (await getItem(fetch, decision.target_item_id));
		if (target && (target.raw_content || target.extracted_text)) {
			try {
				const updatedContent = await rewriteExistingItemContent(chat, target, userText);
				const updated = await updateBrainItem(fetch, target.id, { raw_content: updatedContent });
				if (!updated.ok) {
					return json({ reply: `I couldn't update "${target.title || 'Untitled'}" yet.`, state: currentState, sources: [] }, { status: 500 });
				}
				return json({
					reply: `Updated "${target.title || 'Untitled'}".`,
					state: {
						lastMutation: {
							type: 'update',
							itemId: target.id,
							itemTitle: target.title || 'Untitled',
							content: updatedContent,
							previousRawContent: target.raw_content || target.extracted_text || ''
						}
					},
					sources: [toSource(target)]
				});
			} catch (error) {
				return json(
					{
						reply: `I couldn't update "${target.title || 'Untitled'}" yet.`,
						state: currentState,
						sources: [toSource(target)],
						error: error instanceof Error ? error.message : 'Unknown error'
					},
					{ status: 500 }
				);
			}
		}
	}

	const content = decision.formatted_content?.trim() || userText;

	if (decision.action === 'append_existing' && decision.target_item_id && decision.match_confidence === 'high') {
		const target = candidates.find((item) => item.id === decision.target_item_id) || (await getItem(fetch, decision.target_item_id));
		if (!target) {
			// fall through to create below
		} else {
			const appended = await appendToItem(fetch, target.id, content);
			if (!appended.ok) {
				return json({ reply: `I couldn't add that to "${target.title || 'Untitled'}" yet.`, state: currentState, sources: [] }, { status: 500 });
			}
			return json({
				reply: `Added to "${target.title || 'Untitled'}".`,
				state: {
					lastMutation: {
						type: 'append',
						itemId: target.id,
						itemTitle: target.title || 'Untitled',
						additionId: appended.body?.id,
						content
					}
				},
				sources: [toSource(target)]
			});
		}
	}

	const created = await createBrainNote(fetch, content, decision.create_title);
	if (!created.ok) {
		return json({ reply: 'I could not create the note yet.', state: currentState, sources: [] }, { status: 500 });
	}
	const createdItem = created.body as BrainItem;
	return json({
		reply: `Created "${createdItem.title || decision.create_title || 'New note'}".`,
		state: {
			lastMutation: {
				type: 'create',
				itemId: createdItem.id,
				createdItemId: createdItem.id,
				itemTitle: createdItem.title || decision.create_title || 'New note',
				content
			}
		},
		sources: [toSource(createdItem)]
	});
};
