<script lang="ts">
import { onMount, untrack } from 'svelte';
import { m } from '$lib/paraglide/messages.js';

type CommentReply = {
	id: string;
	authorId: string | null;
	authorName: string;
	content: string;
	createdAt: string;
	updatedAt: string;
};

type Comment = {
	id: string;
	authorId: string | null;
	authorName: string;
	content: string;
	createdAt: string;
	updatedAt: string;
	replies: CommentReply[];
};

type Props = {
	documentId: string;
	annotationId?: string | null;
	initialComments?: Comment[];
	loadOnMount?: boolean;
	canComment: boolean;
	currentUserId: string | null;
	canAdmin: boolean;
	onCountChange?: (count: number) => void;
};

let {
	documentId,
	annotationId = null,
	initialComments = [],
	loadOnMount = false,
	canComment,
	currentUserId,
	canAdmin,
	onCountChange
}: Props = $props();

let comments: Comment[] = $state(untrack(() => [...initialComments]));
let newText: string = $state('');
let replyingTo: string | null = $state(null);
let replyText: string = $state('');
let editingId: string | null = $state(null);
let editText: string = $state('');
let posting: boolean = $state(false);

const commentsBase = $derived(
	annotationId
		? `/api/documents/${documentId}/annotations/${annotationId}/comments`
		: `/api/documents/${documentId}/comments`
);

function timeAgo(iso: string): string {
	const diff = Date.now() - new Date(iso).getTime();
	const minutes = Math.floor(diff / 60000);
	if (minutes < 1) return 'gerade eben';
	if (minutes < 60) return `vor ${minutes} Minute${minutes === 1 ? '' : 'n'}`;
	const hours = Math.floor(minutes / 60);
	if (hours < 24) return `vor ${hours} Stunde${hours === 1 ? '' : 'n'}`;
	const days = Math.floor(hours / 24);
	return `vor ${days} Tag${days === 1 ? '' : 'en'}`;
}

function wasEdited(c: { createdAt: string; updatedAt: string }): boolean {
	return c.updatedAt > c.createdAt;
}

function canModify(c: { authorId: string | null }): boolean {
	return (currentUserId != null && c.authorId === currentUserId) || canAdmin;
}

async function reload() {
	try {
		const res = await fetch(commentsBase);
		if (res.ok) {
			comments = await res.json();
			const total = comments.reduce((s, c) => s + 1 + c.replies.length, 0);
			onCountChange?.(total);
		}
	} catch {
		/* ignore */
	}
}

async function postComment() {
	const text = newText.trim();
	if (!text || posting) return;
	posting = true;
	try {
		const res = await fetch(commentsBase, {
			method: 'POST',
			headers: { 'Content-Type': 'application/json' },
			body: JSON.stringify({ content: text })
		});
		if (res.ok) {
			newText = '';
			await reload();
		}
	} finally {
		posting = false;
	}
}

async function postReply(threadId: string) {
	const text = replyText.trim();
	if (!text || posting) return;
	posting = true;
	try {
		const res = await fetch(`${commentsBase}/${threadId}/replies`, {
			method: 'POST',
			headers: { 'Content-Type': 'application/json' },
			body: JSON.stringify({ content: text })
		});
		if (res.ok) {
			replyText = '';
			replyingTo = null;
			await reload();
		}
	} finally {
		posting = false;
	}
}

async function saveEdit(commentId: string) {
	const text = editText.trim();
	if (!text || posting) return;
	posting = true;
	try {
		const res = await fetch(`/api/documents/${documentId}/comments/${commentId}`, {
			method: 'PATCH',
			headers: { 'Content-Type': 'application/json' },
			body: JSON.stringify({ content: text })
		});
		if (res.ok) {
			editingId = null;
			await reload();
		}
	} finally {
		posting = false;
	}
}

async function deleteComment(commentId: string) {
	if (posting) return;
	posting = true;
	try {
		const res = await fetch(`/api/documents/${documentId}/comments/${commentId}`, {
			method: 'DELETE'
		});
		if (res.ok) {
			await reload();
		}
	} finally {
		posting = false;
	}
}

function startEdit(comment: Comment | CommentReply) {
	editingId = comment.id;
	editText = comment.content;
}

function cancelEdit() {
	editingId = null;
	editText = '';
}

function startReply(threadId: string) {
	replyingTo = threadId;
	replyText = '';
}

function cancelReply() {
	replyingTo = null;
	replyText = '';
}

onMount(() => {
	if (loadOnMount) {
		reload();
	}
});
</script>

<div class="space-y-4">
	{#each comments as thread, ti (thread.id)}
		<div class={ti > 0 ? 'border-t border-line pt-4' : ''}>
			<!-- Root comment -->
			<div>
				{#if editingId === thread.id}
					<div class="flex flex-col gap-2">
						<textarea
							class="w-full resize-none rounded border border-line px-3 py-2 font-serif text-sm text-ink focus:ring-1 focus:ring-accent focus:outline-none"
							rows={3}
							bind:value={editText}
						></textarea>
						<div class="flex items-center gap-3">
							<button
								class="rounded bg-primary px-3 py-1.5 font-sans text-xs font-medium text-white hover:bg-primary/80 disabled:opacity-40"
								disabled={posting}
								onclick={() => saveEdit(thread.id)}
							>
								{m.btn_save()}
							</button>
							<button
								class="font-sans text-xs text-ink-3 transition-colors hover:text-ink"
								onclick={cancelEdit}
							>
								{m.btn_cancel()}
							</button>
						</div>
					</div>
				{:else}
					<div class="flex items-start justify-between gap-2">
						<div class="min-w-0 flex-1">
							<div class="flex flex-wrap items-center gap-2">
								<span class="font-sans text-xs font-semibold text-ink">{thread.authorName}</span>
								<span class="font-sans text-xs text-ink-3">{timeAgo(thread.createdAt)}</span>
								{#if wasEdited(thread)}
									<span class="font-sans text-xs text-ink-3">
										{m.comment_edited_label()}
										{timeAgo(thread.updatedAt)}
									</span>
								{/if}
							</div>
							<p class="mt-1 font-serif text-sm leading-relaxed text-ink-2">{thread.content}</p>
						</div>
						{#if canModify(thread)}
							<div class="flex shrink-0 items-center gap-2">
								<button
									class="font-sans text-xs text-ink-3 transition-colors hover:text-ink"
									onclick={() => startEdit(thread)}
								>
									{m.btn_edit()}
								</button>
								<button
									class="font-sans text-xs text-ink-3 transition-colors hover:text-ink"
									onclick={() => deleteComment(thread.id)}
								>
									{m.btn_delete()}
								</button>
							</div>
						{/if}
					</div>
					<!-- Reply button on root comment only if there are no replies -->
					{#if thread.replies.length === 0 && canComment}
						<div class="mt-1">
							<button
								class="font-sans text-xs font-medium text-accent transition-colors hover:text-ink"
								onclick={() => startReply(thread.id)}
							>
								{m.comment_btn_reply()}
							</button>
						</div>
					{/if}
				{/if}
			</div>

			<!-- Replies -->
			{#each thread.replies as reply, ri (reply.id)}
				<div class="mt-3 ml-6 border-l-2 border-line pl-4">
					{#if editingId === reply.id}
						<div class="flex flex-col gap-2">
							<textarea
								class="w-full resize-none rounded border border-line px-3 py-2 font-serif text-sm text-ink focus:ring-1 focus:ring-accent focus:outline-none"
								rows={3}
								bind:value={editText}
							></textarea>
							<div class="flex items-center gap-3">
								<button
									class="rounded bg-primary px-3 py-1.5 font-sans text-xs font-medium text-white hover:bg-primary/80 disabled:opacity-40"
									disabled={posting}
									onclick={() => saveEdit(reply.id)}
								>
									{m.btn_save()}
								</button>
								<button
									class="font-sans text-xs text-ink-3 transition-colors hover:text-ink"
									onclick={cancelEdit}
								>
									{m.btn_cancel()}
								</button>
							</div>
						</div>
					{:else}
						<div class="flex items-start justify-between gap-2">
							<div class="min-w-0 flex-1">
								<div class="flex flex-wrap items-center gap-2">
									<span class="font-sans text-xs font-semibold text-ink">{reply.authorName}</span>
									<span class="font-sans text-xs text-ink-3">{timeAgo(reply.createdAt)}</span>
									{#if wasEdited(reply)}
										<span class="font-sans text-xs text-ink-3">
											{m.comment_edited_label()}
											{timeAgo(reply.updatedAt)}
										</span>
									{/if}
								</div>
								<p class="mt-1 font-serif text-sm leading-relaxed text-ink-2">{reply.content}</p>
							</div>
							{#if canModify(reply)}
								<div class="flex shrink-0 items-center gap-2">
									<button
										class="font-sans text-xs text-ink-3 transition-colors hover:text-ink"
										onclick={() => startEdit(reply)}
									>
										{m.btn_edit()}
									</button>
									<button
										class="font-sans text-xs text-ink-3 transition-colors hover:text-ink"
										onclick={() => deleteComment(reply.id)}
									>
										{m.btn_delete()}
									</button>
								</div>
							{/if}
						</div>
						<!-- Reply button only on the last reply -->
						{#if ri === thread.replies.length - 1 && canComment}
							<div class="mt-1">
								<button
									class="font-sans text-xs font-medium text-accent transition-colors hover:text-ink"
									onclick={() => startReply(thread.id)}
								>
									{m.comment_btn_reply()}
								</button>
							</div>
						{/if}
					{/if}
				</div>
			{/each}

			<!-- Reply textarea (shown when replyingTo === thread.id) -->
			{#if replyingTo === thread.id}
				<div class="mt-3 ml-6 flex flex-col gap-2">
					<textarea
						class="w-full resize-none rounded border border-line px-3 py-2 font-serif text-sm text-ink focus:ring-1 focus:ring-accent focus:outline-none"
						rows={3}
						placeholder={m.comment_placeholder()}
						bind:value={replyText}
					></textarea>
					<div class="flex items-center gap-3">
						<button
							class="rounded bg-primary px-3 py-1.5 font-sans text-xs font-medium text-white hover:bg-primary/80 disabled:opacity-40"
							disabled={posting}
							onclick={() => postReply(thread.id)}
						>
							{m.comment_btn_post()}
						</button>
						<button
							class="font-sans text-xs text-ink-3 transition-colors hover:text-ink"
							onclick={cancelReply}
						>
							{m.btn_cancel()}
						</button>
					</div>
				</div>
			{/if}
		</div>
	{/each}

	<!-- New top-level comment textarea -->
	{#if canComment}
		<div class={comments.length > 0 ? 'border-t border-line pt-4' : ''}>
			<div class="flex flex-col gap-2">
				<textarea
					class="w-full resize-none rounded border border-line px-3 py-2 font-serif text-sm text-ink focus:ring-1 focus:ring-accent focus:outline-none"
					rows={3}
					placeholder={m.comment_placeholder()}
					bind:value={newText}
				></textarea>
				<div>
					<button
						class="rounded bg-primary px-3 py-1.5 font-sans text-xs font-medium text-white hover:bg-primary/80 disabled:opacity-40"
						disabled={posting || !newText.trim()}
						onclick={postComment}
					>
						{m.comment_btn_post()}
					</button>
				</div>
			</div>
		</div>
	{/if}
</div>
