<script lang="ts">
import { onDestroy, onMount } from 'svelte';
import { beforeNavigate } from '$app/navigation';
import { Editor } from '@tiptap/core';
import StarterKit from '@tiptap/starter-kit';
import { m } from '$lib/paraglide/messages.js';
import type { components } from '$lib/generated/api';
import GeschichteSidebar from '$lib/geschichte/GeschichteSidebar.svelte';
import { toPersonOption, type PersonOption } from '$lib/person/personOption';

type GeschichteView = components['schemas']['GeschichteView'];
type Person = components['schemas']['Person'];

interface Props {
	geschichte?: GeschichteView | null;
	initialPersons?: Person[];
	/** Must reject when the save failed — the editor keeps its dirty state then. */
	onSubmit: (payload: {
		title: string;
		body: string;
		status: 'DRAFT' | 'PUBLISHED';
		personIds: string[];
	}) => Promise<void>;
	submitting?: boolean;
}

let { geschichte = null, initialPersons = [], onSubmit, submitting = false }: Props = $props();

// Initial-state snapshot from incoming props. The editor owns these values
// after mount; the parent should re-mount the component with a different
// `geschichte` to reset (consistent with how form components in this codebase
// behave — see DocumentEdit page).
let title = $state(geschichte?.title ?? '');
let body = $state(geschichte?.body ?? '');
let status: 'DRAFT' | 'PUBLISHED' = $state(geschichte?.status ?? 'DRAFT');
let selectedPersons: PersonOption[] = $state(
	geschichte?.persons ? Array.from(geschichte.persons).map(toPersonOption) : initialPersons
);

let dirty = $state(false);
let titleTouched = $state(false);

const titleEmpty = $derived(title.trim().length === 0);
const isDraft = $derived(status === 'DRAFT');
const showTitleError = $derived(titleEmpty && titleTouched);

let editorEl: HTMLDivElement;
let editor: Editor | null = null;
let toolbarVersion = $state(0);

onMount(() => {
	editor = new Editor({
		element: editorEl,
		content: body,
		extensions: [
			StarterKit.configure({
				heading: { levels: [2, 3] },
				code: false,
				codeBlock: false,
				blockquote: false,
				strike: false,
				horizontalRule: false,
				hardBreak: false
			})
		],
		editorProps: {
			attributes: {
				role: 'textbox',
				'aria-multiline': 'true',
				'aria-label': m.geschichte_editor_body_placeholder(),
				class:
					'prose max-w-none focus:outline-none min-h-[260px] font-serif text-base leading-relaxed'
			}
		},
		onUpdate({ editor: ed }) {
			body = ed.getHTML();
			dirty = true;
		},
		onSelectionUpdate() {
			toolbarVersion++;
		},
		onTransaction() {
			toolbarVersion++;
		}
	});
});

onDestroy(() => {
	editor?.destroy();
});

beforeNavigate(({ cancel }) => {
	if (dirty && !submitting) {
		const ok = window.confirm(m.geschichte_editor_unsaved_changes());
		if (!ok) cancel();
	}
});

function handleTitleBlur() {
	titleTouched = true;
}

function handleTitleInput() {
	dirty = true;
}

async function save(nextStatus: 'DRAFT' | 'PUBLISHED') {
	titleTouched = true;
	if (titleEmpty) return;
	try {
		await onSubmit({
			title: title.trim(),
			body,
			status: nextStatus,
			personIds: selectedPersons.map((p) => p.id!).filter(Boolean)
		});
		dirty = false;
	} catch {
		// onSubmit signalled failure — keep dirty so the unsaved guard stays armed
	}
}

function isActive(name: string, attrs?: Record<string, unknown>): boolean {
	void toolbarVersion;
	return editor?.isActive(name, attrs) ?? false;
}

function exec(action: () => void) {
	if (!editor) return;
	action();
	editor.commands.focus();
}
</script>

<div class="grid grid-cols-1 gap-6 lg:grid-cols-[2fr_1fr]">
	<!-- Editor column -->
	<div class="flex flex-col gap-4">
		<!-- Title -->
		<div>
			<input
				type="text"
				bind:value={title}
				maxlength="255"
				oninput={handleTitleInput}
				onblur={handleTitleBlur}
				placeholder={m.geschichte_editor_title_placeholder()}
				aria-invalid={showTitleError}
				aria-describedby={showTitleError ? 'title-error' : undefined}
				class="block w-full rounded border border-line bg-surface px-3 py-3 font-serif text-2xl font-bold text-ink placeholder:text-ink-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
			/>
			{#if showTitleError}
				<p id="title-error" class="mt-1 text-sm text-danger" role="alert">
					{m.geschichte_editor_title_required()}
				</p>
			{/if}
		</div>

		<!-- Toolbar -->
		<div
			role="toolbar"
			aria-label="Formatierung"
			class="flex flex-wrap items-center gap-1 rounded border border-line bg-surface p-1"
		>
			<button
				type="button"
				onclick={() => exec(() => editor!.chain().focus().toggleBold().run())}
				aria-label={m.geschichte_editor_toolbar_bold()}
				aria-pressed={isActive('bold')}
				title={m.geschichte_editor_toolbar_bold()}
				class="inline-flex h-11 min-w-[44px] items-center justify-center rounded px-2 font-bold text-ink hover:bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring aria-pressed:bg-accent-bg"
			>
				B
			</button>
			<button
				type="button"
				onclick={() => exec(() => editor!.chain().focus().toggleItalic().run())}
				aria-label={m.geschichte_editor_toolbar_italic()}
				aria-pressed={isActive('italic')}
				title={m.geschichte_editor_toolbar_italic()}
				class="inline-flex h-11 min-w-[44px] items-center justify-center rounded px-2 text-ink italic hover:bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring aria-pressed:bg-accent-bg"
			>
				I
			</button>
			<span class="mx-1 h-6 w-px bg-line" aria-hidden="true"></span>
			<button
				type="button"
				onclick={() => exec(() => editor!.chain().focus().toggleHeading({ level: 2 }).run())}
				aria-label={m.geschichte_editor_toolbar_h2()}
				aria-pressed={isActive('heading', { level: 2 })}
				title={m.geschichte_editor_toolbar_h2()}
				class="inline-flex h-11 min-w-[44px] items-center justify-center rounded px-2 text-sm font-bold text-ink hover:bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring aria-pressed:bg-accent-bg"
			>
				H2
			</button>
			<button
				type="button"
				onclick={() => exec(() => editor!.chain().focus().toggleHeading({ level: 3 }).run())}
				aria-label={m.geschichte_editor_toolbar_h3()}
				aria-pressed={isActive('heading', { level: 3 })}
				title={m.geschichte_editor_toolbar_h3()}
				class="inline-flex h-11 min-w-[44px] items-center justify-center rounded px-2 text-sm font-bold text-ink hover:bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring aria-pressed:bg-accent-bg"
			>
				H3
			</button>
			<span class="mx-1 h-6 w-px bg-line" aria-hidden="true"></span>
			<button
				type="button"
				onclick={() => exec(() => editor!.chain().focus().toggleBulletList().run())}
				aria-label={m.geschichte_editor_toolbar_ul()}
				aria-pressed={isActive('bulletList')}
				title={m.geschichte_editor_toolbar_ul()}
				class="inline-flex h-11 min-w-[44px] items-center justify-center rounded px-2 text-ink hover:bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring aria-pressed:bg-accent-bg"
			>
				•
			</button>
			<button
				type="button"
				onclick={() => exec(() => editor!.chain().focus().toggleOrderedList().run())}
				aria-label={m.geschichte_editor_toolbar_ol()}
				aria-pressed={isActive('orderedList')}
				title={m.geschichte_editor_toolbar_ol()}
				class="inline-flex h-11 min-w-[44px] items-center justify-center rounded px-2 text-ink hover:bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring aria-pressed:bg-accent-bg"
			>
				1.
			</button>
		</div>

		<!-- Editor surface -->
		<div
			class="rounded border border-line bg-surface p-4 shadow-sm focus-within:ring-2 focus-within:ring-focus-ring"
		>
			<div bind:this={editorEl} class="min-h-[260px]"></div>
		</div>
	</div>

	<!-- Sidebar -->
	<GeschichteSidebar
		status={status}
		bind:selectedPersons={selectedPersons}
		geschichteId={geschichte?.id}
		items={geschichte?.items ?? []}
	/>
</div>

<!-- Save bar -->
<div
	class="sticky bottom-0 z-10 -mx-4 mt-6 flex flex-col gap-3 border-t border-line bg-surface px-6 py-4 shadow-[0_-2px_8px_rgba(0,0,0,0.06)] sm:flex-row sm:items-center sm:justify-between"
>
	<p class="font-sans text-xs text-ink-3">
		{isDraft
			? m.geschichte_editor_save_hint_draft()
			: m.geschichte_editor_save_hint_published()}
	</p>
	<div class="flex gap-2">
		{#if isDraft}
			<button
				type="button"
				onclick={() => save('DRAFT')}
				disabled={submitting || titleEmpty}
				class="inline-flex h-11 items-center rounded border border-line bg-surface px-4 font-sans text-sm font-medium text-ink hover:bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring disabled:cursor-not-allowed disabled:opacity-50"
			>
				{m.geschichte_editor_save_draft()}
			</button>
			<button
				type="button"
				onclick={() => save('PUBLISHED')}
				disabled={submitting || titleEmpty}
				class="inline-flex h-11 items-center rounded bg-primary px-4 font-sans text-sm font-medium text-primary-fg hover:opacity-90 focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring disabled:cursor-not-allowed disabled:opacity-50"
			>
				{m.geschichte_editor_publish()}
			</button>
		{:else}
			<button
				type="button"
				onclick={() => save('DRAFT')}
				disabled={submitting}
				class="inline-flex h-11 items-center rounded border border-line bg-surface px-4 font-sans text-sm font-medium text-amber-700 hover:bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring disabled:cursor-not-allowed disabled:opacity-50"
			>
				{m.geschichte_editor_unpublish()}
			</button>
			<button
				type="button"
				onclick={() => save('PUBLISHED')}
				disabled={submitting || titleEmpty}
				class="inline-flex h-11 items-center rounded bg-primary px-4 font-sans text-sm font-medium text-primary-fg hover:opacity-90 focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring disabled:cursor-not-allowed disabled:opacity-50"
			>
				{m.geschichte_editor_save()}
			</button>
		{/if}
	</div>
</div>
