<script lang="ts">
	import type { KeyboardEventHandler } from "svelte/elements";
	import Eye from "$icon/eye";
	import Pencil from "$icon/pencil";
	import Button from "./Button.svelte";
	import ButtonGroup from "./ButtonGroup.svelte";
	import Textarea from "./Textarea.svelte";
	import { renderMarkup, type MarkupContext } from "$lib/markup";

	interface Props {
		value?: string;
		markup: MarkupContext;
		tab?: "write" | "preview";
		id?: string;
		name?: string;
		rows?: number;
		placeholder?: string;
		disabled?: boolean;
		previewClass?: string;
		autofocus?: boolean;
		// drop the textarea/preview background so the editor blends into its surroundings
		transparent?: boolean;
	}

	let {
		value = $bindable(""),
		markup,
		tab = $bindable("write"),
		id,
		name,
		rows = 12,
		placeholder,
		disabled = false,
		previewClass = "min-h-40",
		autofocus = false,
		transparent = false
	}: Props = $props();

	const surface = $derived(transparent ? "bg-transparent" : "bg-background-default");

	let previewHtml = $state<string | null>(null);
	let previewing = $state(false);
	let textareaEl = $state<HTMLTextAreaElement>();

	// focus on mount (and when returning to the write tab) if requested
	$effect(() => {
		if (autofocus) textareaEl?.focus();
	});

	$effect(() => {
		if (tab !== "preview") return;
		const source = value;
		if (!source.trim()) {
			previewHtml = null;
			previewing = false;
			return;
		}
		let cancelled = false;
		previewing = true;
		renderMarkup(source, markup)
			.then((html) => {
				if (!cancelled) previewHtml = html;
			})
			.catch(() => {
				if (!cancelled) previewHtml = null;
			})
			.finally(() => {
				if (!cancelled) previewing = false;
			});
		return () => {
			cancelled = true;
		};
	});
	// ctrl/cmd+enter submits the enclosing form, mirroring the old htmx editor
	const handleKeydown: KeyboardEventHandler<HTMLTextAreaElement> = (e) => {
		if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
			e.preventDefault();
			e.currentTarget.form?.requestSubmit();
		}
	};
</script>

<div class="flex flex-col gap-1.5">
	<ButtonGroup class="self-start">
		<Button
			type="button"
			size="sm"
			icon={Pencil}
			variant={tab === "write" ? "default" : "ghost"}
			onclick={() => (tab = "write")}
		>
			Write
		</Button>
		<Button
			type="button"
			size="sm"
			icon={Eye}
			variant={tab === "preview" ? "default" : "ghost"}
			onclick={() => (tab = "preview")}
		>
			Preview
		</Button>
	</ButtonGroup>

	{#if tab === "write"}
		<Textarea
			{id}
			{name}
			{rows}
			resizeable
			{placeholder}
			bind:value
			bind:element={textareaEl}
			{disabled}
			onkeydown={handleKeydown}
			class={transparent ? "max-h-none bg-transparent" : "max-h-none"}
		/>
	{:else if previewHtml}
		<div
			class={`markup rounded border border-border-default ${surface} px-2.5 py-2 ${previewClass}`}
		>
			<!-- eslint-disable-next-line svelte/no-at-html-tags -- sanitised in $lib/markup -->
			{@html previewHtml}
		</div>
	{:else}
		<div
			class={`rounded border border-border-default ${surface} px-2.5 py-2 text-sm text-foreground-subtle italic ${previewClass}`}
		>
			{previewing ? "Rendering…" : "Nothing to preview."}
		</div>
	{/if}
</div>
