<script lang="ts">
	import { state } from './state.svelte';
	import Item from './Item.svelte';

	let container: HTMLDivElement;
	let isPanning = false;
	let hasPanned = false;
	let lastX = 0;
	let lastY = 0;

	function handleMouseDown(e: MouseEvent) {
		if (e.button === 1 || (e.button === 0 && (e.shiftKey || e.target === container))) {
			isPanning = true;
			hasPanned = false;
			lastX = e.clientX;
			lastY = e.clientY;
			e.preventDefault();
		}
	}

	function handleMouseMove(e: MouseEvent) {
		if (!isPanning) return;
		const dx = e.clientX - lastX;
		const dy = e.clientY - lastY;
		if (dx !== 0 || dy !== 0) hasPanned = true;
		lastX = e.clientX;
		lastY = e.clientY;
		state.pan(dx, dy);
	}

	function handleMouseUp(e: MouseEvent) {
		if (isPanning && !hasPanned && e.target === container) {
			state.select(null);
			state.focus(null);
		}
		isPanning = false;
	}

	function handleWheel(e: WheelEvent) {
		e.preventDefault();
		const factor = e.deltaY > 0 ? 0.9 : 1.1;
		const rect = container.getBoundingClientRect();
		const cx = e.clientX - rect.left;
		const cy = e.clientY - rect.top;
		state.zoomAt(factor, cx, cy);
	}

	function handleDrop(e: DragEvent) {
		e.preventDefault();
		const files = e.dataTransfer?.files;
		if (!files || files.length === 0) return;

		const rect = container.getBoundingClientRect();
		const dropX = (e.clientX - rect.left - state.viewport.x) / state.viewport.zoom;
		const dropY = (e.clientY - rect.top - state.viewport.y) / state.viewport.zoom;

		for (const file of files) {
			handleFile(file, dropX, dropY);
		}
	}

	function handleFile(file: File, x: number, y: number) {
		const id = crypto.randomUUID();
		const assetId = crypto.randomUUID();
		const url = URL.createObjectURL(file);

		if (file.type.startsWith('image/')) {
			const img = new Image();
			img.onload = () => {
				state.addAsset(assetId, { blob: file, url, filename: file.name });
				state.addItem({
					id,
					assetId,
					html: `<img src="${url}" alt="" />`,
					css: `img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}`,
					x,
					y,
					width: img.naturalWidth,
					height: img.naturalHeight,
					rotation: 0,
					zIndex: state.maxZIndex + 1
				});
			};
			img.src = url;
		} else if (file.type.startsWith('audio/')) {
			state.addAsset(assetId, { blob: file, url, filename: file.name });
			state.addItem({
				id,
				assetId,
				html: `<audio src="${url}" controls></audio>`,
				css: `audio {
  width: 100%;
}`,
				x,
				y,
				width: 300,
				height: 54,
				rotation: 0,
				zIndex: state.maxZIndex + 1
			});
		} else if (file.type.startsWith('video/')) {
			const video = document.createElement('video');
			video.onloadedmetadata = () => {
				state.addAsset(assetId, { blob: file, url, filename: file.name });
				state.addItem({
					id,
					assetId,
					html: `<video src="${url}" controls></video>`,
					css: `video {
  width: 100%;
  height: 100%;
}`,
					x,
					y,
					width: video.videoWidth || 640,
					height: video.videoHeight || 360,
					rotation: 0,
					zIndex: state.maxZIndex + 1
				});
			};
			video.src = url;
		}
	}

	function handleDragOver(e: DragEvent) {
		e.preventDefault();
	}

	function handleKeyDown(e: KeyboardEvent) {
		if (state.editingId || state.editingGlobal) return;
		if (state.focusedId) return;
		const tag = (e.target as HTMLElement)?.tagName;
		if (tag === 'INPUT' || tag === 'TEXTAREA') return;
		if ((e.target as HTMLElement)?.isContentEditable) return;

		const mod = e.metaKey || e.ctrlKey;
		const rect = container.getBoundingClientRect();
		const centerX = (rect.width / 2 - state.viewport.x) / state.viewport.zoom;
		const centerY = (rect.height / 2 - state.viewport.y) / state.viewport.zoom;

		if (mod && e.key === 'c' && state.selectedId) {
			e.preventDefault();
			state.copyItem(state.selectedId);
		} else if (mod && e.key === 'v') {
			e.preventDefault();
			const newId = state.pasteItem(centerX, centerY);
			if (newId) state.select(newId);
		} else if (mod && e.key === 'd' && state.selectedId) {
			e.preventDefault();
			const newId = state.duplicateItem(state.selectedId, centerX, centerY);
			if (newId) state.select(newId);
		} else if (e.key === 'Escape') {
			state.select(null);
			state.focus(null);
		} else if (e.key === '[' && state.selectedId) {
			e.preventDefault();
			state.sendBackward(state.selectedId);
		} else if (e.key === ']' && state.selectedId) {
			e.preventDefault();
			state.bringForward(state.selectedId);
		} else if (e.key.startsWith('Arrow') && state.selectedId) {
			e.preventDefault();
			const step = e.shiftKey ? 10 : 1;
			const item = state.getItem(state.selectedId);
			if (!item) return;
			const dx = e.key === 'ArrowLeft' ? -step : e.key === 'ArrowRight' ? step : 0;
			const dy = e.key === 'ArrowUp' ? -step : e.key === 'ArrowDown' ? step : 0;
			state.updateItem(state.selectedId, { x: item.x + dx, y: item.y + dy });
		} else if (e.key === 'e' && state.selectedId && !mod) {
			e.preventDefault();
			state.focus(state.selectedId);
			state.edit(state.selectedId);
		}
	}
</script>

<svelte:window onmouseup={handleMouseUp} onmousemove={handleMouseMove} onkeydown={handleKeyDown} />

<!-- svelte-ignore a11y_no_static_element_interactions -->
<div
	bind:this={container}
	class="canvas"
	onmousedown={handleMouseDown}
	onwheel={handleWheel}
	ondrop={handleDrop}
	ondragover={handleDragOver}
>
	<div
		class="viewport"
		style="transform: translate({state.viewport.x}px, {state.viewport.y}px) scale({state.viewport
			.zoom})"
	>
		{#each state.manifest.items as item (item.id)}
			<Item {item} />
		{/each}
	</div>
</div>

<style>
	.canvas {
		width: 100%;
		height: 100%;
		overflow: hidden;
		position: relative;
		background: var(--bg, #1a1a1a);
		background-image: radial-gradient(circle, var(--border, #333) 1px, transparent 1px);
		background-size: 20px 20px;
		cursor: grab;
	}

	.canvas:active {
		cursor: grabbing;
	}

	.viewport {
		transform-origin: 0 0;
		position: absolute;
		top: 0;
		left: 0;
	}
</style>
