<script lang="ts">
	import { untrack, type Component } from "svelte";
	import type { SvelteHTMLElements } from "svelte/elements";
	import { now as tidNow } from "@atcute/tid";
	import X from "$icon/x";
	import { putComment } from "$lib/api/comment";
	import { getAuth } from "$lib/auth.svelte";
	import Button from "$lib/components/ui/Button.svelte";
	import ErrorAlert from "$lib/components/ui/Error.svelte";
	import MarkdownEditor from "$lib/components/ui/MarkdownEditor.svelte";
	import Spinner from "$lib/components/ui/Spinner.svelte";
	import { renderMarkup, type MarkupContext } from "$lib/markup";
	import type { CommentRecord } from "$lib/api/records";
	import { createAction } from "$lib/action.svelte";
	import type { ThreadInput } from "./comments";

	interface Props {
		subjectUri: string;
		subjectCid?: string;
		// when set, the comment strongRefs this parent comment (threaded reply)
		replyToUri?: string;
		replyToCid?: string;
		authorDid: string;
		authorHandle: string;
		// reused on edit so the record keeps its identity; omitted when composing
		rkey?: string;
		createdAt?: string;
		body?: string;
		markup: MarkupContext;
		rows?: number;
		placeholder?: string;
		submitLabel: string;
		submitIcon: Component<SvelteHTMLElements["svg"]>;
		autofocus?: boolean;
		onsubmitted?: (submitted: ThreadInput) => void;
		oncancel?: () => void;
	}

	let {
		subjectUri,
		subjectCid,
		replyToUri,
		replyToCid,
		authorDid,
		authorHandle,
		rkey,
		createdAt,
		body: initialBody = "",
		markup,
		rows = 6,
		placeholder,
		submitLabel,
		submitIcon,
		autofocus = false,
		onsubmitted,
		oncancel
	}: Props = $props();

	const auth = getAuth();

	let body = $state(untrack(() => initialBody));
	let tab = $state<"write" | "preview">("write");

	const publish = createAction(async (event: SubmitEvent) => {
		event.preventDefault();
		const agent = auth.agent;
		if (!agent || body.trim() === "") return;
		if (!subjectCid) throw new Error("Cannot comment: the subject record is missing a cid.");
		const createdAtValue = createdAt ?? new Date().toISOString();
		const targetRkey = rkey ?? tidNow();
		const record: CommentRecord = {
			$type: "sh.tangled.feed.comment",
			subject: { uri: subjectUri, cid: subjectCid } as CommentRecord["subject"],
			body: { $type: "sh.tangled.markup.markdown", text: body },
			createdAt: createdAtValue
		};
		if (replyToUri && replyToCid) {
			record.replyTo = { uri: replyToUri, cid: replyToCid } as CommentRecord["replyTo"];
		}
		const saved = await putComment(agent, targetRkey, record);
		// render markdown client-side so the optimistic comment matches a real one
		const bodyHtml = await renderMarkup(body, markup).catch(() => null);
		onsubmitted?.({
			comment: {
				uri: saved.uri,
				cid: saved.cid,
				rkey: targetRkey,
				authorDid,
				authorHandle,
				createdAt: createdAtValue,
				body,
				bodyHtml
			},
			replyTo: replyToUri ?? null
		});
		// keep the prefilled body when editing; reset when composing a fresh comment
		if (!rkey) {
			body = "";
			tab = "write";
		}
	});
	const canSubmit = $derived(body.trim() !== "" && !publish.loading);
</script>

<form onsubmit={publish.run} class="flex flex-col gap-2">
	<MarkdownEditor
		name="body"
		{rows}
		{placeholder}
		{markup}
		{autofocus}
		transparent
		bind:value={body}
		bind:tab
		disabled={publish.loading}
	/>

	<ErrorAlert label={publish.error} />

	<div class="flex items-center gap-2">
		<Button
			type="submit"
			variant="primary"
			icon={publish.loading ? Spinner : submitIcon}
			disabled={!canSubmit}
		>
			{submitLabel}
		</Button>
		{#if oncancel}
			<Button
				type="button"
				variant="default"
				icon={X}
				disabled={publish.loading}
				onclick={oncancel}
			>
				Cancel
			</Button>
		{/if}
	</div>
</form>
