import { error } from "@sveltejs/kit";
import { createBobbinClient } from "$lib/api/client";
import { IdentityCache } from "$lib/api/identity";
import {
	getIssue,
	listComments,
	listIssueStates,
	listReactions,
	type RecordView,
	type ReactionRecord
} from "$lib/api/records";
import { didFromUri, rkeyFromUri } from "$lib/api/uri";
import { renderMarkup } from "$lib/markup";
import { buildCommentThreads, type ThreadInput } from "$lib/components/comment/comments";
import { buildReactions, type ReactionGroup } from "$lib/components/reaction/reactions";
import type { PageLoad } from "./$types";

export const load: PageLoad = async (event) => {
	const parent = await event.parent();
	const uri = decodeURIComponent(event.params.aturi);

	if (!uri.startsWith("at://")) error(404, "Issue not found");

	const ctx = createBobbinClient({ serviceUrl: parent.publicConfig.bobbinUrl, fetch: event.fetch });

	const record = await getIssue(ctx, uri).catch(() => null);
	if (!record) error(404, "Issue not found");

	const authorDid = didFromUri(record.uri);
	const identities = new IdentityCache(ctx);
	const markupOpts = {
		repo: `${parent.repo.ownerHandle}/${parent.repo.name}`,
		ref: parent.repo.defaultBranch,
		host: event.url.host
	};

	const [author, states, comments] = await Promise.all([
		identities.resolve(authorDid).catch(() => null),
		listIssueStates(ctx, record.uri, { limit: 1, order: "desc" }).catch(() => null),
		listComments(ctx, record.uri, { order: "asc", limit: 100 }).catch(() => null)
	]);

	const latest = states?.items[0]?.value.state;
	const state = latest?.endsWith(".closed") ? ("closed" as const) : ("open" as const);
	const body = record.value.body ?? "";
	const bodyHtml = body ? await renderMarkup(body, markupOpts) : null;
	const viewerDid = parent.auth?.did;
	const commentItems = comments?.items ?? [];

	// reactions: one listReactions per subject (the issue itself + each comment).
	// bobbin has no batch-by-subject query and enrich can't break counts down by
	// emoji, so we fan out and group client-side. empty subjects come back empty.
	const subjects = [record.uri, ...commentItems.map((item) => item.uri)];
	const reactionPages = await Promise.all(
		subjects.map((subject) =>
			listReactions(ctx, subject, { order: "asc", limit: 100 }).catch(() => null)
		)
	);
	const reactionsBySubject = new Map<string, RecordView<ReactionRecord>[]>();
	subjects.forEach((subject, i) => reactionsBySubject.set(subject, reactionPages[i]?.items ?? []));

	// resolve every reactor's handle once for the whole page (IdentityCache dedups)
	const reactorDids = new Set<string>();
	for (const items of reactionsBySubject.values()) {
		for (const item of items) reactorDids.add(didFromUri(item.uri));
	}
	const reactorHandles = new Map<string, string>();
	await Promise.all(
		[...reactorDids].map(async (did) => {
			const doc = await identities.resolve(did).catch(() => null);
			reactorHandles.set(did, doc?.handle ?? did);
		})
	);
	const reactionsFor = (subject: string): ReactionGroup[] =>
		buildReactions(
			reactionsBySubject.get(subject) ?? [],
			viewerDid,
			(did) => reactorHandles.get(did) ?? did
		);

	const threadInputs: ThreadInput[] = await Promise.all(
		commentItems.map(async (item): Promise<ThreadInput> => {
			const commentDid = didFromUri(item.uri);
			const commentBody = item.value.body?.text ?? "";
			const [doc, commentBodyHtml] = await Promise.all([
				identities.resolve(commentDid).catch(() => null),
				commentBody ? renderMarkup(commentBody, markupOpts) : Promise.resolve(null)
			]);
			return {
				comment: {
					uri: item.uri,
					cid: item.cid,
					rkey: rkeyFromUri(item.uri),
					authorDid: commentDid,
					authorHandle: doc?.handle ?? commentDid,
					createdAt: item.value.createdAt,
					body: commentBody,
					bodyHtml: commentBodyHtml,
					reactions: reactionsFor(item.uri)
				},
				replyTo: item.value.replyTo?.uri ?? null,
				replyToCid: item.value.replyTo?.cid
			};
		})
	);

	return {
		issue: {
			uri: record.uri,
			cid: record.cid,
			rkey: rkeyFromUri(record.uri),
			title: record.value.title,
			body,
			bodyHtml,
			state,
			authorDid,
			authorHandle: author?.handle ?? authorDid,
			createdAt: record.value.createdAt,
			reactions: reactionsFor(record.uri)
		},
		comments: buildCommentThreads(threadInputs),
		markup: markupOpts
	};
};
