<script lang="ts">
	import { onMount, onDestroy } from 'svelte';
	import { Editor } from '@tiptap/core';
	import StarterKit from '@tiptap/starter-kit';
	import Link from '@tiptap/extension-link';
	import Image from '@tiptap/extension-image';
	import Placeholder from '@tiptap/extension-placeholder';
	import { uploadMedia, casUrl } from '$lib/api';
	import VoiceRecorder from './VoiceRecorder.svelte';

	interface Props {
		onsubmit: (data: { title: string; content: string; html: string }) => Promise<void>;
		disabled?: boolean;
		accessToken?: string;
	}

	let { onsubmit, disabled = false, accessToken }: Props = $props();

	let editorElement: HTMLDivElement | undefined = $state();
	let editor: Editor | undefined = $state();
	let title = $state('');
	let submitting = $state(false);
	let uploading = $state(0);
	let error = $state('');
	let voiceMemoInfo = $state('');

	async function handleImageUpload(file: File): Promise<void> {
		if (!accessToken) {
			error = 'Ikke innlogget — kan ikke laste opp bilder';
			return;
		}
		if (!file.type.startsWith('image/')) return;

		uploading++;
		try {
			const result = await uploadMedia(accessToken, {
				file,
				title: file.name,
				visibility: 'hidden'
			});
			const src = casUrl(result.cas_hash);
			editor?.chain().focus().setImage({
				src,
				alt: file.name,
				title: file.name
			}).run();
			// Add data-node-id to the just-inserted image
			// TipTap Image extension stores src/alt/title as attributes.
			// We extend the node attribute below to include data-node-id.
		} catch (e) {
			error = e instanceof Error ? e.message : 'Feil ved bildeopplasting';
		} finally {
			uploading--;
		}
	}

	/** Handle files from drop or paste events */
	function handleFiles(files: FileList | File[]) {
		for (const file of files) {
			if (file.type.startsWith('image/')) {
				handleImageUpload(file);
			}
		}
	}

	// Extend the Image extension to include data-node-id attribute
	const CasImage = Image.extend({
		addAttributes() {
			return {
				...this.parent?.(),
				'data-node-id': {
					default: null,
					parseHTML: (element: HTMLElement) => element.getAttribute('data-node-id'),
					renderHTML: (attributes: Record<string, unknown>) => {
						if (!attributes['data-node-id']) return {};
						return { 'data-node-id': attributes['data-node-id'] };
					}
				}
			};
		}
	});

	onMount(() => {
		editor = new Editor({
			element: editorElement!,
			extensions: [
				StarterKit.configure({
					heading: { levels: [2, 3] },
					codeBlock: false,
					horizontalRule: false
				}),
				Link.configure({
					openOnClick: false,
					HTMLAttributes: { class: 'text-blue-600 underline' }
				}),
				CasImage.configure({
					inline: false,
					allowBase64: false,
					HTMLAttributes: {
						class: 'max-w-full h-auto rounded'
					}
				}),
				Placeholder.configure({
					placeholder: 'Skriv noe…'
				})
			],
			editorProps: {
				attributes: {
					class: 'prose prose-sm max-w-none focus:outline-none min-h-[80px] px-3 py-2'
				},
				handleDrop: (_view, event, _slice, moved) => {
					if (moved || !event.dataTransfer?.files?.length) return false;
					const imageFiles = Array.from(event.dataTransfer.files).filter(f =>
						f.type.startsWith('image/')
					);
					if (imageFiles.length === 0) return false;
					event.preventDefault();
					handleFiles(imageFiles);
					return true;
				},
				handlePaste: (_view, event) => {
					const files = event.clipboardData?.files;
					if (!files?.length) return false;
					const imageFiles = Array.from(files).filter(f =>
						f.type.startsWith('image/')
					);
					if (imageFiles.length === 0) return false;
					event.preventDefault();
					handleFiles(imageFiles);
					return true;
				}
			},
			onTransaction: () => {
				// Force Svelte reactivity
				editor = editor;
			}
		});
	});

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

	const isEmpty = $derived(!title.trim() && (!editor || editor.isEmpty));

	async function handleSubmit() {
		if (isEmpty || submitting || disabled || uploading > 0) return;

		submitting = true;
		error = '';

		try {
			const content = editor?.getText() ?? '';
			const html = editor?.getHTML() ?? '';
			await onsubmit({ title: title.trim(), content, html });
			// Clear editor on success
			title = '';
			editor?.commands.clearContent();
		} catch (e) {
			error = e instanceof Error ? e.message : 'Noe gikk galt';
		} finally {
			submitting = false;
		}
	}

	function handleKeydown(e: KeyboardEvent) {
		if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {
			e.preventDefault();
			handleSubmit();
		}
	}
</script>

<!-- svelte-ignore a11y_no_static_element_interactions -->
<div class="rounded-lg border border-gray-200 bg-white shadow-sm" onkeydown={handleKeydown}>
	<input
		type="text"
		bind:value={title}
		placeholder="Tittel (valgfritt)"
		disabled={disabled || submitting}
		class="w-full border-b border-gray-100 bg-transparent px-3 py-2 text-sm font-medium text-gray-900 placeholder:text-gray-400 focus:outline-none"
	/>

	<div bind:this={editorElement}></div>

	{#if uploading > 0}
		<p class="px-3 py-1 text-xs text-blue-600">Laster opp {uploading} bilde{uploading > 1 ? 'r' : ''}…</p>
	{/if}

	{#if error}
		<p class="px-3 py-1 text-xs text-red-600">{error}</p>
	{/if}

	{#if voiceMemoInfo}
		<p class="px-3 py-1 text-xs text-green-600">{voiceMemoInfo}</p>
	{/if}

	<div class="flex items-center justify-between border-t border-gray-100 px-3 py-2">
		<div class="flex items-center gap-2">
			<span class="text-xs text-gray-400">
				{#if editor}
					Markdown · Ctrl+B/I · Dra/lim bilder · Ctrl+Enter for å sende
				{/if}
			</span>
			<VoiceRecorder
				{accessToken}
				disabled={disabled || submitting}
				onerror={(msg) => { error = msg; }}
				onrecorded={() => { voiceMemoInfo = 'Talenotat lastet opp — transkriberes i bakgrunnen'; setTimeout(() => { voiceMemoInfo = ''; }, 5000); }}
			/>
		</div>
		<button
			onclick={handleSubmit}
			disabled={isEmpty || submitting || disabled || uploading > 0}
			class="rounded bg-blue-600 px-3 py-1 text-xs font-medium text-white transition-colors hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-40"
		>
			{#if uploading > 0}
				Laster opp…
			{:else if submitting}
				Sender…
			{:else}
				Opprett node
			{/if}
		</button>
	</div>
</div>

<style>
	:global(.tiptap p.is-editor-empty:first-child::before) {
		color: #9ca3af;
		content: attr(data-placeholder);
		float: left;
		height: 0;
		pointer-events: none;
	}

	:global(.tiptap img) {
		max-width: 100%;
		height: auto;
		border-radius: 0.375rem;
		margin: 0.5rem 0;
	}
</style>
