<script lang="ts">
	import { toast } from 'svelte-sonner';
	import { getContext, tick, onDestroy } from 'svelte';
	import { formatFileSize } from '$lib/utils';
	import type { FileEntry } from '$lib/apis/terminal';

	import Dropdown from '$lib/components/common/Dropdown.svelte';
	import Folder from '../../icons/Folder.svelte';
	import EllipsisHorizontal from '../../icons/EllipsisHorizontal.svelte';
	import GarbageBin from '../../icons/GarbageBin.svelte';
	import Pencil from '../../icons/Pencil.svelte';
	import Clipboard from '../../icons/Clipboard.svelte';

	const i18n = getContext('i18n');

	export let entry: FileEntry;
	export let currentPath: string;
	export let terminalUrl: string = '';
	export let terminalKey: string = '';

	export let onOpen: (entry: FileEntry) => void = () => {};
	export let onDownload: (path: string) => void = () => {};
	export let onDelete: (path: string, name: string) => void = () => {};
	export let onMove: (source: string, destFolder: string) => void = () => {};
	export let onRename: (oldPath: string, newName: string) => void = () => {};

	// ── Selection ─────────────────────────────────────────────────────────
	export let selected: boolean = false;
	export let selectionMode: boolean = false;
	export let selectedPaths: Set<string> = new Set();
	export let onSelect: (entry: FileEntry, event: MouseEvent) => void = () => {};
	export let onLongPress: () => void = () => {};
	export let showDate: boolean = false;

	const formatRelativeTime = (epoch: number): string => {
		const diff = Math.floor(Date.now() / 1000) - epoch;
		if (diff < 60) return 'just now';
		if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;
		if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`;
		if (diff < 2592000) return `${Math.floor(diff / 86400)}d ago`;
		if (diff < 31536000) return `${Math.floor(diff / 2592000)}mo ago`;
		return `${Math.floor(diff / 31536000)}y ago`;
	};

	let dragOverFolder = false;

	// ── Rename state ─────────────────────────────────────────────────────
	let renaming = false;
	let renameValue = '';
	let renameInput: HTMLInputElement;

	const startRename = async () => {
		renameValue = entry.name;
		renaming = true;
		await tick();
		renameInput?.focus();
		if (entry.type === 'file') {
			const dotIdx = entry.name.lastIndexOf('.');
			renameInput?.setSelectionRange(0, dotIdx > 0 ? dotIdx : entry.name.length);
		} else {
			renameInput?.select();
		}
	};

	const submitRename = () => {
		const newName = renameValue.trim();
		renaming = false;
		if (!newName || newName === entry.name) return;
		onRename(`${currentPath}${entry.name}`, newName);
	};

	const cancelRename = () => {
		renaming = false;
		renameValue = '';
	};

	// ── Long-press for touch selection ───────────────────────────────────
	let longPressTimer: ReturnType<typeof setTimeout> | null = null;
	let didLongPress = false;

	const onPointerDown = (e: PointerEvent) => {
		if (e.pointerType !== 'touch') return;
		didLongPress = false;
		longPressTimer = setTimeout(() => {
			didLongPress = true;
			onLongPress();
			onSelect(entry, e as any);
		}, 500);
	};

	const onPointerUp = () => {
		if (longPressTimer) {
			clearTimeout(longPressTimer);
			longPressTimer = null;
		}
	};

	const onPointerCancel = () => {
		if (longPressTimer) {
			clearTimeout(longPressTimer);
			longPressTimer = null;
		}
	};

	onDestroy(() => {
		if (longPressTimer) clearTimeout(longPressTimer);
	});

	// ── Click handler ────────────────────────────────────────────────────
	const handleClick = (e: MouseEvent) => {
		if (renaming) return;
		if (didLongPress) {
			didLongPress = false;
			return;
		}

		// Modifier click → toggle/range select
		if (e.metaKey || e.ctrlKey || e.shiftKey) {
			e.preventDefault();
			onSelect(entry, e);
			return;
		}

		// In selection mode (touch) → toggle select
		if (selectionMode) {
			onSelect(entry, e);
			return;
		}

		// Normal click → open
		onOpen(entry);
	};
</script>

<li class="group">
	<div
		class="w-full flex items-center transition
			{selected ? 'bg-blue-50 dark:bg-blue-900/20' : 'hover:bg-gray-50 dark:hover:bg-gray-800'}
			{dragOverFolder
			? 'bg-blue-50 dark:bg-blue-900/30 ring-1 ring-blue-400 dark:ring-blue-500 ring-inset'
			: ''}"
		role={entry.type === 'directory' ? 'button' : undefined}
		on:dragover={(e) => {
			if (entry.type !== 'directory') return;
			if (!e.dataTransfer?.types.includes('application/x-terminal-file-move')) return;
			e.preventDefault();
			e.stopPropagation();
			dragOverFolder = true;
		}}
		on:dragleave={(e) => {
			if (entry.type !== 'directory') return;
			e.stopPropagation();
			dragOverFolder = false;
		}}
		on:drop={(e) => {
			if (entry.type !== 'directory') return;
			const raw = e.dataTransfer?.getData('application/x-terminal-file-move');
			if (!raw) return;
			e.preventDefault();
			e.stopPropagation();
			dragOverFolder = false;
			try {
				const data = JSON.parse(raw);
				const paths = data.paths || (data.path ? [data.path] : []);
				const destFolder = `${currentPath}${entry.name}/`;
				for (const p of paths) {
					if (p + '/' === destFolder || p === destFolder) continue;
					onMove(p, destFolder);
				}
			} catch {}
		}}
	>
		<button
			class="flex-1 flex items-center gap-2 px-3 py-1.5 text-left min-w-0"
			draggable={true}
			on:dragstart={(e) => {
				const filePath = `${currentPath}${entry.name}`;
				// If dragging a selected item, drag all selected
				if (selected && selectedPaths.size > 1) {
					e.dataTransfer?.setData(
						'application/x-terminal-file-move',
						JSON.stringify({ paths: [...selectedPaths] })
					);
					// Custom drag ghost showing count
					const ghost = document.createElement('div');
					ghost.style.cssText =
						'position:fixed;top:-1000px;left:-1000px;display:flex;align-items:center;gap:6px;padding:4px 10px;border-radius:8px;background:#374151;color:#fff;font-size:12px;white-space:nowrap;pointer-events:none;';
					ghost.textContent = `${selectedPaths.size} items`;
					document.body.appendChild(ghost);
					e.dataTransfer?.setDragImage(ghost, 0, 0);
					requestAnimationFrame(() => ghost.remove());
				} else {
					e.dataTransfer?.setData(
						'application/x-terminal-file-move',
						JSON.stringify({ path: filePath, name: entry.name })
					);
				}
				if (entry.type === 'file') {
					e.dataTransfer?.setData(
						'application/x-terminal-file',
						JSON.stringify({
							path: filePath,
							name: entry.name,
							url: terminalUrl,
							key: terminalKey
						})
					);
				}
			}}
			on:pointerdown={onPointerDown}
			on:pointerup={onPointerUp}
			on:pointercancel={onPointerCancel}
			on:click={handleClick}
			on:dblclick|preventDefault|stopPropagation={() => {
				startRename();
			}}
		>
			{#if selectionMode || selected}
				<!-- Checkbox indicator -->
				<div
					class="size-3.5 shrink-0 rounded border transition-colors flex items-center justify-center
						{selected
						? 'bg-blue-500 dark:bg-blue-600 border-blue-500 dark:border-blue-600 text-white'
						: 'border-gray-300 dark:border-gray-600'}"
				>
					{#if selected}
						<svg
							xmlns="http://www.w3.org/2000/svg"
							viewBox="0 0 20 20"
							fill="currentColor"
							class="size-2.5"
						>
							<path
								fill-rule="evenodd"
								d="M16.704 4.153a.75.75 0 0 1 .143 1.052l-8 10.5a.75.75 0 0 1-1.127.075l-4.5-4.5a.75.75 0 0 1 1.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 0 1 1.05-.143Z"
								clip-rule="evenodd"
							/>
						</svg>
					{/if}
				</div>
			{/if}
			{#if entry.type === 'directory'}
				<Folder className="size-4 shrink-0 text-blue-400 dark:text-blue-300" />
			{:else}
				<svg
					xmlns="http://www.w3.org/2000/svg"
					viewBox="0 0 24 24"
					fill="none"
					stroke="currentColor"
					stroke-width="1.5"
					class="size-4 shrink-0 text-gray-400"
				>
					<path
						stroke-linecap="round"
						stroke-linejoin="round"
						d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"
					/>
				</svg>
			{/if}
			{#if renaming}
				<!-- svelte-ignore a11y-click-events-have-key-events -->
				<input
					bind:this={renameInput}
					bind:value={renameValue}
					class="flex-1 text-xs bg-transparent border border-gray-200 dark:border-gray-700 rounded px-1.5 py-0.5 outline-none focus:border-blue-400 dark:focus:border-blue-500 text-gray-800 dark:text-gray-200 min-w-0"
					on:keydown={(e) => {
						if (e.key === 'Enter') {
							e.preventDefault();
							submitRename();
						}
						if (e.key === 'Escape') {
							e.preventDefault();
							cancelRename();
						}
					}}
					on:blur={submitRename}
					on:click|stopPropagation
				/>
			{:else}
				<span class="flex-1 text-xs text-gray-800 dark:text-gray-200 truncate">
					{entry.name}
				</span>
			{/if}
			{#if entry.type === 'file' && entry.size !== undefined && !renaming}
				{#if showDate && entry.modified}
					<span class="text-[10px] text-gray-400 shrink-0"
						>{formatRelativeTime(entry.modified)}</span
					>
				{/if}
				<span class="text-xs text-gray-400 shrink-0">{formatFileSize(entry.size)}</span>
			{:else if entry.type === 'directory' && showDate && entry.modified && !renaming}
				<span class="text-[10px] text-gray-400 shrink-0">{formatRelativeTime(entry.modified)}</span>
			{/if}
		</button>

		<Dropdown align="end" sideOffset={4}>
			<button
				class="shrink-0 p-0.5 mr-1 rounded-lg transition
					text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-400
					hover:bg-gray-100 dark:hover:bg-gray-800"
				aria-label={$i18n.t('More')}
			>
				<EllipsisHorizontal className="size-3.5" />
			</button>

			<div slot="content">
				<div
					class="min-w-[150px] rounded-2xl p-1 z-[9999999] bg-white dark:bg-gray-850 dark:text-white shadow-lg border border-gray-100 dark:border-gray-800"
				>
					<button
						type="button"
						class="select-none flex rounded-xl py-1.5 px-3 w-full hover:bg-gray-50 dark:hover:bg-gray-800 transition items-center gap-2 text-sm"
						on:click={(e) => {
							e.stopPropagation();
							const path =
								entry.type === 'directory'
									? `${currentPath}${entry.name}/`
									: `${currentPath}${entry.name}`;
							onDownload(path);
						}}
					>
						<svg
							xmlns="http://www.w3.org/2000/svg"
							viewBox="0 0 20 20"
							fill="currentColor"
							class="size-4"
						>
							<path
								d="M10.75 2.75a.75.75 0 0 0-1.5 0v8.614L6.295 8.235a.75.75 0 1 0-1.09 1.03l4.25 4.5a.75.75 0 0 0 1.09 0l4.25-4.5a.75.75 0 0 0-1.09-1.03l-2.955 3.129V2.75Z"
							/>
							<path
								d="M3.5 12.75a.75.75 0 0 0-1.5 0v2.5A2.75 2.75 0 0 0 4.75 18h10.5A2.75 2.75 0 0 0 18 15.25v-2.5a.75.75 0 0 0-1.5 0v2.5c0 .69-.56 1.25-1.25 1.25H4.75c-.69 0-1.25-.56-1.25-1.25v-2.5Z"
							/>
						</svg>
						<div class="flex items-center">{$i18n.t('Download')}</div>
					</button>

					<button
						type="button"
						class="select-none flex rounded-xl py-1.5 px-3 w-full hover:bg-gray-50 dark:hover:bg-gray-800 transition items-center gap-2 text-sm"
						on:click={(e) => {
							e.stopPropagation();
							const path =
								entry.type === 'directory'
									? `${currentPath}${entry.name}/`
									: `${currentPath}${entry.name}`;
							navigator.clipboard.writeText(path).then(() => {
								toast.success($i18n.t('Path copied'));
							});
						}}
					>
						<Clipboard className="size-4" strokeWidth="1.5" />
						<div class="flex items-center">{$i18n.t('Copy Path')}</div>
					</button>

					<button
						type="button"
						class="select-none flex rounded-xl py-1.5 px-3 w-full hover:bg-gray-50 dark:hover:bg-gray-800 transition items-center gap-2 text-sm"
						on:click={(e) => {
							e.stopPropagation();
							startRename();
						}}
					>
						<Pencil className="size-4" strokeWidth="1.5" />
						<div class="flex items-center">{$i18n.t('Rename')}</div>
					</button>

					<button
						type="button"
						class="select-none flex rounded-xl py-1.5 px-3 w-full hover:bg-gray-50 dark:hover:bg-gray-800 transition items-center gap-2 text-sm"
						on:click={(e) => {
							e.stopPropagation();
							onDelete(`${currentPath}${entry.name}`, entry.name);
						}}
					>
						<GarbageBin className="size-4" />
						<div class="flex items-center">{$i18n.t('Delete')}</div>
					</button>
				</div>
			</div>
		</Dropdown>
	</div>
</li>
