<script lang="ts">
	import type { Entry, Image, Tag } from '$lib/server/db/schema';
	import { enhance } from '$app/forms';
	import { invalidateAll } from '$app/navigation';
	import { slide } from 'svelte/transition';
	import ImageGallery from './ImageGallery.svelte';
	import ImageUpload from './ImageUpload.svelte';
	import TagInput from './TagInput.svelte';
	import { highlightText } from '$lib/utils/highlightText';

	interface EntryWithData extends Entry {
		images: Image[];
		tags: Tag[];
	}

	interface Props {
		entry: EntryWithData;
		availableTags: Tag[];
		searchQuery?: string;
	}

	let { entry, availableTags, searchQuery = '' }: Props = $props();

	// Expand/collapse state
	let expanded = $state(false);

	// Image management state
	let editImagesMode = $state(false);
	let cameraInput: HTMLInputElement;

	// Edit state - use $derived to stay in sync with entry prop
	let editTitle = $state(entry.title || '');
	let editContent = $state(entry.content);
	let editType = $state(entry.type);
	let editDueDate = $state(entry.dueDate || '');
	let editTags = $state<Tag[]>(entry.tags || []);

	// Sync edit state when entry changes (after invalidateAll)
	$effect(() => {
		if (!expanded) {
			editTitle = entry.title || '';
			editContent = entry.content;
			editType = entry.type;
			editDueDate = entry.dueDate || '';
			editTags = entry.tags || [];
		}
	});

	// Debounced auto-save
	let saveTimeout: ReturnType<typeof setTimeout>;
	let isSaving = $state(false);

	// Swipe state
	let swipeOffset = $state(0);
	let isConfirmingDelete = $state(false);
	let touchStartX = 0;
	let isSwiping = $state(false);

	function handleTouchStart(e: TouchEvent) {
		// Ignore if touch started on a button or interactive element
		const target = e.target as HTMLElement;
		if (target.closest('button, input, textarea, select, a, [role="button"]')) {
			return;
		}
		touchStartX = e.touches[0].clientX;
		isSwiping = true;
	}

	function handleTouchMove(e: TouchEvent) {
		if (!isSwiping) return;
		const currentX = e.touches[0].clientX;
		const diff = currentX - touchStartX;
		// Only allow left swipe (negative diff), cap at -100px
		if (diff < 0) {
			swipeOffset = Math.max(diff, -100);
		}
	}

	function handleTouchEnd() {
		isSwiping = false;
		// If swiped far enough, show confirmation
		if (swipeOffset < -60) {
			isConfirmingDelete = true;
			swipeOffset = -100; // Snap to reveal delete area
		} else {
			swipeOffset = 0; // Snap back
		}
	}

	function cancelDelete() {
		isConfirmingDelete = false;
		swipeOffset = 0;
	}

	async function confirmDelete() {
		const formData = new FormData();
		formData.append('id', entry.id);

		await fetch('?/delete', {
			method: 'POST',
			body: formData
		});

		await invalidateAll();
	}

	async function debouncedSave() {
		clearTimeout(saveTimeout);
		saveTimeout = setTimeout(async () => {
			isSaving = true;
			const formData = new FormData();
			formData.append('id', entry.id);
			formData.append('title', editTitle);
			formData.append('content', editContent);
			formData.append('type', editType);

			try {
				await fetch('?/update', {
					method: 'POST',
					body: formData
				});
				// Refresh data so list shows updated values
				await invalidateAll();
			} finally {
				isSaving = false;
			}
		}, 400);
	}

	function handleInput() {
		debouncedSave();
	}

	function toggleExpand() {
		if (expanded) {
			// Collapsing - reset edit state to current entry values
			editTitle = entry.title || '';
			editContent = entry.content;
			editType = entry.type;
		}
		expanded = !expanded;
	}

	function handleKeydown(e: KeyboardEvent) {
		if (e.key === 'Enter' || e.key === ' ') {
			e.preventDefault();
			toggleExpand();
		}
	}

	async function handleDeleteImage(imageId: string) {
		const formData = new FormData();
		formData.append('imageId', imageId);

		await fetch('?/deleteImage', {
			method: 'POST',
			body: formData
		});

		await invalidateAll();
	}

	function handleUploadComplete() {
		// invalidateAll is called by ImageUpload, so nothing extra needed here
	}

	async function handleTogglePin() {
		const formData = new FormData();
		formData.append('id', entry.id);

		await fetch('?/togglePin', {
			method: 'POST',
			body: formData
		});

		await invalidateAll();
	}

	async function handleDueDateChange(e: Event) {
		const input = e.target as HTMLInputElement;
		editDueDate = input.value;

		const formData = new FormData();
		formData.append('id', entry.id);
		formData.append('dueDate', input.value);

		await fetch('?/updateDueDate', {
			method: 'POST',
			body: formData
		});

		await invalidateAll();
	}

	async function handleTagsChange(newTags: Tag[]) {
		editTags = newTags;

		// Save immediately (no debounce for tags)
		const formData = new FormData();
		formData.append('id', entry.id);
		formData.append('tags', JSON.stringify(newTags.map((t) => t.name)));

		await fetch('?/updateTags', {
			method: 'POST',
			body: formData
		});

		await invalidateAll();
	}

	async function handleCameraInput(e: Event) {
		const input = e.target as HTMLInputElement;
		const file = input.files?.[0];
		if (!file || !file.type.startsWith('image/')) return;

		const formData = new FormData();
		formData.append('image', file);
		formData.append('entryId', entry.id);

		await fetch('?/uploadImage', {
			method: 'POST',
			body: formData
		});

		await invalidateAll();
		input.value = '';
	}
</script>

<div class="relative overflow-hidden">
	<!-- Delete background revealed during swipe -->
	<div
		class="absolute inset-y-0 right-0 w-24 bg-red-500 flex items-center justify-center"
		aria-hidden="true"
	>
		<svg class="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
			<path
				stroke-linecap="round"
				stroke-linejoin="round"
				stroke-width="2"
				d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
			/>
		</svg>
	</div>

	<!-- Swipeable entry card -->
	<article
		ontouchstart={handleTouchStart}
		ontouchmove={handleTouchMove}
		ontouchend={handleTouchEnd}
		style="transform: translateX({swipeOffset}px); transition: {isSwiping
			? 'none'
			: 'transform 0.2s'}"
		class="p-4 border-b border-gray-100 md:border md:rounded-lg md:shadow-sm md:mb-3 bg-white relative"
	>
		<!-- Collapsed view - clickable header -->
		<div class="flex items-start gap-3">
			{#if entry.type === 'task'}
				<form method="POST" action="?/toggleComplete" use:enhance>
					<input type="hidden" name="id" value={entry.id} />
					<button
						type="submit"
						class="w-6 h-6 rounded border-2 border-gray-300 flex items-center justify-center touch-target
                   {entry.status === 'done' ? 'bg-green-500 border-green-500' : 'hover:border-gray-400'}"
						aria-label={entry.status === 'done' ? 'Mark as incomplete' : 'Mark as complete'}
					>
						{#if entry.status === 'done'}
							<svg
								class="w-4 h-4 text-white"
								fill="none"
								stroke="currentColor"
								viewBox="0 0 24 24"
							>
								<path
									stroke-linecap="round"
									stroke-linejoin="round"
									stroke-width="2"
									d="M5 13l4 4L19 7"
								/>
							</svg>
						{/if}
					</button>
				</form>
			{:else}
				<span
					class="w-6 h-6 rounded-full bg-purple-100 flex items-center justify-center flex-shrink-0"
				>
					<span class="text-purple-600 text-xs font-medium">T</span>
				</span>
			{/if}

			<!-- svelte-ignore a11y_no_static_element_interactions -->
			<div
				class="flex-1 min-w-0 cursor-pointer"
				role="button"
				tabindex="0"
				onclick={toggleExpand}
				onkeydown={handleKeydown}
			>
				<h3
					class="font-medium text-gray-900 text-base md:text-lg {entry.status === 'done'
						? 'line-through text-gray-400'
						: ''}"
				>
					{#if !expanded && searchQuery}
						{@html highlightText(entry.title || 'Untitled', searchQuery)}
					{:else}
						{entry.title || 'Untitled'}
					{/if}
				</h3>
				{#if !expanded}
					<p
						class="text-gray-600 text-sm md:text-base line-clamp-2 {entry.status === 'done'
							? 'text-gray-400'
							: ''}"
					>
						{#if searchQuery}
							{@html highlightText(entry.content, searchQuery)}
						{:else}
							{entry.content}
						{/if}
					</p>
					{#if entry.tags?.length > 0}
						<div class="flex flex-wrap gap-1 mt-1">
							{#each entry.tags.slice(0, 3) as tag}
								<span class="text-xs px-2 py-0.5 bg-gray-100 text-gray-600 rounded-full"
									>{tag.name}</span
								>
							{/each}
							{#if entry.tags.length > 3}
								<span class="text-xs text-gray-400">+{entry.tags.length - 3}</span>
							{/if}
						</div>
					{/if}
				{/if}
			</div>

			<div class="flex items-center gap-2">
				{#if isSaving}
					<span class="text-xs text-gray-400">Saving...</span>
				{/if}
				{#if entry.pinned}
					<svg class="w-4 h-4 text-yellow-500" fill="currentColor" viewBox="0 0 20 20" aria-label="Pinned">
						<path d="M5 4a2 2 0 012-2h6a2 2 0 012 2v3.586l1.707 1.707A1 1 0 0117 10v1a1 1 0 01-1 1h-4v5a1 1 0 11-2 0v-5H6a1 1 0 01-1-1v-1a1 1 0 01.293-.707L7 7.586V4z" />
					</svg>
				{/if}
				{#if entry.dueDate && !expanded}
					<span class="text-xs text-gray-500">{entry.dueDate}</span>
				{/if}
				{#if entry.images?.length > 0 && !expanded}
					<span
						class="flex items-center gap-1 text-xs text-gray-500"
						aria-label="{entry.images.length} image{entry.images.length > 1 ? 's' : ''}"
					>
						<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
							<path
								stroke-linecap="round"
								stroke-linejoin="round"
								stroke-width="2"
								d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"
							/>
						</svg>
						{entry.images.length}
					</span>
				{/if}
				<span
					class="text-xs px-2 py-1 rounded-full {entry.type === 'task'
						? 'bg-blue-100 text-blue-700'
						: 'bg-purple-100 text-purple-700'}"
				>
					{entry.type}
				</span>
				<button
					type="button"
					onclick={toggleExpand}
					class="p-1 hover:bg-gray-100 rounded"
					aria-label={expanded ? 'Collapse entry' : 'Expand entry'}
				>
					<svg
						class="w-5 h-5 text-gray-400 transform transition-transform {expanded
							? 'rotate-180'
							: ''}"
						fill="none"
						stroke="currentColor"
						viewBox="0 0 24 24"
					>
						<path
							stroke-linecap="round"
							stroke-linejoin="round"
							stroke-width="2"
							d="M19 9l-7 7-7-7"
						/>
					</svg>
				</button>
			</div>
		</div>

		<!-- Expanded view - edit fields -->
		{#if expanded}
			<div transition:slide={{ duration: 200 }} class="mt-4 pl-9 space-y-3">
				<div>
					<label for="edit-title-{entry.id}" class="block text-sm font-medium text-gray-700 mb-1"
						>Title</label
					>
					<input
						id="edit-title-{entry.id}"
						bind:value={editTitle}
						oninput={handleInput}
						placeholder="Add a title..."
						class="w-full px-3 py-2 border border-gray-200 rounded-lg text-base focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
					/>
				</div>

				<div>
					<label for="edit-content-{entry.id}" class="block text-sm font-medium text-gray-700 mb-1"
						>Content</label
					>
					<textarea
						id="edit-content-{entry.id}"
						bind:value={editContent}
						oninput={handleInput}
						rows="4"
						class="w-full px-3 py-2 border border-gray-200 rounded-lg text-base resize-y focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
					></textarea>
				</div>

				<!-- Images section -->
				{#if entry.images?.length > 0}
					<div>
						<div class="flex items-center justify-between mb-2">
							<label class="text-sm font-medium text-gray-700">Images</label>
							<button
								type="button"
								onclick={() => (editImagesMode = !editImagesMode)}
								class="text-sm text-blue-600 hover:text-blue-700"
							>
								{editImagesMode ? 'Done' : 'Edit'}
							</button>
						</div>
						<ImageGallery
							images={entry.images}
							entryId={entry.id}
							editMode={editImagesMode}
							onDelete={handleDeleteImage}
						/>
					</div>
				{/if}

				<!-- Add image section -->
				<div>
					<label class="text-sm font-medium text-gray-700 mb-2 block">Add Image</label>
					<div class="flex gap-2 items-start">
						<div class="flex-1">
							<ImageUpload entryId={entry.id} onUploadComplete={handleUploadComplete} />
						</div>
						<button
							type="button"
							onclick={() => cameraInput?.click()}
							class="px-4 py-2 border border-gray-300 rounded-lg flex items-center gap-2 hover:bg-gray-50 transition-colors"
						>
							<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
								<path
									stroke-linecap="round"
									stroke-linejoin="round"
									stroke-width="2"
									d="M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z"
								/>
								<path
									stroke-linecap="round"
									stroke-linejoin="round"
									stroke-width="2"
									d="M15 13a3 3 0 11-6 0 3 3 0 016 0z"
								/>
							</svg>
							Camera
						</button>
						<input
							bind:this={cameraInput}
							type="file"
							accept="image/*"
							capture="environment"
							onchange={handleCameraInput}
							class="hidden"
						/>
					</div>
				</div>

				<!-- Pin and Due Date row -->
				<div class="flex items-center gap-4">
					<button
						type="button"
						onclick={handleTogglePin}
						class="p-2 rounded-lg hover:bg-gray-100 {entry.pinned ? 'text-yellow-500' : 'text-gray-400'}"
						aria-label={entry.pinned ? 'Unpin entry' : 'Pin entry'}
					>
						<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
							<path d="M5 4a2 2 0 012-2h6a2 2 0 012 2v3.586l1.707 1.707A1 1 0 0117 10v1a1 1 0 01-1 1h-4v5a1 1 0 11-2 0v-5H6a1 1 0 01-1-1v-1a1 1 0 01.293-.707L7 7.586V4z" />
						</svg>
					</button>

					<div>
						<label for="due-date-{entry.id}" class="block text-sm font-medium text-gray-700 mb-1">Due Date</label>
						<input
							id="due-date-{entry.id}"
							type="date"
							value={editDueDate}
							onchange={handleDueDateChange}
							class="px-3 py-2 border border-gray-200 rounded-lg text-base focus:outline-none focus:ring-2 focus:ring-blue-500"
						/>
					</div>
				</div>

				<!-- Tags section -->
				<div>
					<label class="block text-sm font-medium text-gray-700 mb-1">Tags</label>
					<TagInput {availableTags} selectedTags={editTags} onchange={handleTagsChange} />
				</div>

				<div class="flex items-center justify-between">
					<div>
						<label for="edit-type-{entry.id}" class="block text-sm font-medium text-gray-700 mb-1"
							>Type</label
						>
						<select
							id="edit-type-{entry.id}"
							bind:value={editType}
							onchange={handleInput}
							class="px-3 py-2 border border-gray-200 rounded-lg text-base focus:outline-none focus:ring-2 focus:ring-blue-500"
						>
							<option value="thought">Thought</option>
							<option value="task">Task</option>
						</select>
					</div>

					<form method="POST" action="?/delete" use:enhance>
						<input type="hidden" name="id" value={entry.id} />
						<button
							type="submit"
							class="px-4 py-2 text-red-600 hover:bg-red-50 rounded-lg touch-target"
							onclick={(e) => {
								if (!confirm('Delete this entry?')) {
									e.preventDefault();
								}
							}}
						>
							Delete
						</button>
					</form>
				</div>
			</div>
		{/if}
	</article>

	<!-- Delete confirmation overlay -->
	{#if isConfirmingDelete}
		<div
			class="absolute inset-0 bg-white/95 flex items-center justify-center gap-4 z-10"
			transition:slide={{ duration: 150 }}
		>
			<button
				onclick={cancelDelete}
				class="px-4 py-2 text-gray-600 border border-gray-300 rounded-lg touch-target min-w-[44px] min-h-[44px]"
			>
				Cancel
			</button>
			<button
				onclick={confirmDelete}
				class="px-4 py-2 bg-red-600 text-white rounded-lg touch-target min-w-[44px] min-h-[44px]"
			>
				Delete
			</button>
		</div>
	{/if}
</div>

