﻿<script lang="ts">
	import { onMount, tick } from "svelte";
	import {MarkdownRenderer, Component, App, type TFile} from "obsidian";
	import {LinkSuggest} from "../LinkSuggest";
	import type {Context} from "../Context.svelte.js";

	// PROPS
	let {
		taskId,
		isUnselected,
		context,
		app,
		content,
		sourcePath,
		onSave
	}: {
		taskId: number,
		isUnselected: boolean,
		context: Context,
		app: App;
		content: string;
		sourcePath: string;
		onSave: (newContent: string) => void
	} = $props();

	// STATE

	let isSelected = $derived(context.isSelected(taskId));
	let isEditing = $state(false);
	let suggest: LinkSuggest | null = null;
	let textPreviewEl: HTMLElement;
	let textEditEl: HTMLTextAreaElement;
	let component = new Component(); // Required by Obsidian to manage render lifecycle
	let isDragging = $derived(context.taskDraggingManager.isDragging);

	onMount(() => {
		if(!isEditing && textPreviewEl) {
			renderMarkdown();
		}
		return () => {
			// Clean up Obsidian component references to prevent memory leaks
			component.unload();
		};
	});
	$effect(() => {
		if (!isEditing && textPreviewEl) {
			renderMarkdown();
		}
	});
	$effect(() => {
		if (context.taskDraggingManager.isDragging) {
			document.body.classList.add('is-dragging-task');
		} else {
			document.body.classList.remove('is-dragging-task');
		}

		// Cleanup function for when component is unmounted
		return () => document.body.classList.remove('is-dragging-task');
	});
	
	function handlePreviewClick(e: PointerEvent) {
		if (isDragging) {
			return;
		}
		context.taskDraggingManager.onPointerUp(e);
		console.log('task text clicked');
		const target = e.target as HTMLElement;

		// Check if the clicked element (or its parent) is an internal link
		const internalLink = target.closest(".internal-link");
		if (internalLink) {
			// Prevent the default "Swap to Edit" behavior
			e.preventDefault(); // TODO: is this line needed?
			e.stopPropagation();

			const href = internalLink.getAttribute("data-href");
			if (href === null) {
				throw new Error('href is null');
			}

			// Open the link using Obsidian's API
			// Whether to open in a new tab or in current one
			// const openInNewLeaf = e.ctrlKey || e.metaKey;
			// app.workspace.openLinkText(href, sourcePath, openInNewLeaf);
			const filepath = context.filePathFromTask(taskId);
			const file = context.app.vault.getAbstractFileByPath(filepath) as TFile;
			context.openOrFocusNote(file);
			return;
		}

		const externalLink = target.closest("a.external-link");
		if (externalLink){
			e.stopPropagation();
			return;
		}
		
		if (context.isSelected(taskId)) {
			toggleEdit();
			e.stopPropagation();
		}
	}

	function handlePreviewMouseOver(e: MouseEvent) {
		if (isDragging) {
			return;
		}
		const target = e.target as HTMLElement;
		const link = target.closest(".internal-link");

		if (link) {
			// Trigger the native hover preview
			app.workspace.trigger("hover-link", {
				event: e,
				source: "preview",
				hoverParent: textPreviewEl,
				targetEl: link,
				linktext: link.getAttribute("data-href"),
				sourcePath: sourcePath
			});
		}
	}
	async function renderMarkdown() {
		textPreviewEl.empty(); // Clear previous render
		await MarkdownRenderer.render(
			app,
			content,
			textPreviewEl,
			sourcePath,
			component
		);
		// After rendering, find all links and disable their native dragging
		const links = textPreviewEl.querySelectorAll('a, .internal-link, .external-link');
		links.forEach(link => {
			link.setAttribute('draggable', 'false');
			// Optional: prevent dragging on the specific link level too
			(link as HTMLElement).ondragstart = (e) => e.preventDefault();
		});
	}

	async function toggleEdit() {
		isEditing = true;
		// Wait for DOM update so textarea exists, then focus
		await tick();
		if (textEditEl) {
			textEditEl.focus();
			suggest = new LinkSuggest(app, textEditEl);
		}
	}

	export function handleBlur() {
		isEditing = false;
		onSave(content); // Persist changes
	}

	function handleKeydown(e: KeyboardEvent) {
		if (e.key === "Enter") {
			e.preventDefault();
			textEditEl.blur(); // Triggers handleBlur
		} else if (e.key === "Tab" && suggest !== null) {
			// another hack to select suggest on tab
			e.preventDefault();
			textEditEl.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'}));
		}
	}
	
</script>


<div
	class="task-text-container"
	class:selected={isSelected}
	class:not-selected={!isSelected}
	onpointerup={handlePreviewClick}
>
	{#if isEditing}
		<textarea
			class="text-edit tasktext"
			class:unselect={isUnselected}
			maxlength="28"
			bind:this={textEditEl}
			bind:value={content}
			onblur={handleBlur}
			onkeydown={handleKeydown}
		></textarea>
	{:else}
		<div
			class="text-preview tasktext"
			class:unselect={isUnselected}
			tabindex="0"
			bind:this={textPreviewEl}
			onpointerup={handlePreviewClick}
			onmouseover={handlePreviewMouseOver}
		>
		</div>
	{/if}
</div>
<!--onkeydown={(e) => e.key === 'Enter' && toggleEdit()}-->

<style>
	.task-text-container {
		width: 160px;
		height: 60px;
		display: flex;
		justify-content: center;
		align-items: center;
		position: absolute;
		padding: 0;
		gap: 0;
	}
	.tasktext {
		margin: 0;
		padding: 0;
		gap: 0;
		border: none;
		/*transform: translate3d(0,20px,0);*/
		width: 160px;
		/*height: 60px;*/
		/*width: 100%;*/
		/*height: 100%;*/
		background: transparent;
		resize: none;
		font-size: 20px;
		font-family: "Segoe UI";
		line-height: 1.5;
		/*border: 4px solid #707070;*/
		/*border-radius: 22px;*/
		outline: none;
		box-shadow: none;
		/*padding: 35px;*/
		position: absolute;
		text-align: center;
		justify-content: center;
		align-items: center;
		color: white;
		overflow: hidden;
	}
	.tasktext.unselect {
		color: color-mix(in srgb, #7E7E7E 100%, #000000 50%);
	}
	.task-text-container.selected .tasktext:hover {
		cursor: text;
	}
	.task-text-container.not-selected .tasktext:hover {
		/*cursor: default;*/
	}

	.text-edit {
		display: flex;
		align-items: center;
		field-sizing: content;
	}
	.text-edit:hover {
		background-color: transparent;
	}
	.text-edit:focus {
		border: none;
		outline: none;
		box-shadow: none;
	}
	.text-preview {
		overflow: visible;
		white-space: pre-wrap;
		word-wrap: break-word;
		p {
			top: 0;
			width: 160px;
			height: 60px;
			line-height: 1.5;
			margin: 0;
			padding: 0;
			gap: 0;
			border: none;
			text-align: center;
			justify-content: center;
			align-items: center;
			/*white-space: pre-wrap;*/
			/*word-wrap: break-word;*/
			overflow: visible;
		}
	}
</style>
