<script lang="ts">
	import { onDestroy } from 'svelte';
	import Cropper from 'cropperjs';
	import type { default as CropperType } from 'cropperjs';
	import 'cropperjs/dist/cropper.css';
	import { Dialog, DialogHeader, DialogTitle, DialogFooter } from '$lib/components/ui/dialog';
	import { Button } from '$lib/components/ui/button';

	interface Props {
		file: File;
		onconfirm: (blob: Blob, mimeType: string) => void;
		oncancel: () => void;
	}

	let { file, onconfirm, oncancel }: Props = $props();

	let imgEl: HTMLImageElement | undefined = $state();
	let cropper: CropperType | null = null;
	let objectUrl = '';
	let open = $state(true);

	// Initialize cropper once the img element is bound and the file is known.
	// Use a $effect so it runs after the DOM is ready (replaces onMount).
	$effect(() => {
		if (!imgEl || !file) return;

		// Create the object URL and set src directly on the element (not via reactive
		// state) so cropperjs sees the correct src before the image load event fires.
		objectUrl = URL.createObjectURL(file);
		imgEl.src = objectUrl;

		// Cropperjs must be initialised inside the image's load event so it can
		// measure the natural dimensions — if we call new Cropper() before the image
		// has loaded, the crop canvas is blank/invisible.
		const handleLoad = () => {
			cropper = new Cropper(imgEl!, {
				aspectRatio: 1,
				viewMode: 1,
				dragMode: 'move',
				autoCropArea: 0.8,
				restore: false,
				guides: false,
				center: true,
				highlight: false,
				cropBoxMovable: true,
				cropBoxResizable: true,
				toggleDragModeOnDblclick: false,
				background: false
			});
		};

		imgEl.addEventListener('load', handleLoad, { once: true });

		return () => {
			imgEl?.removeEventListener('load', handleLoad);
			cropper?.destroy();
			cropper = null;
			URL.revokeObjectURL(objectUrl);
			objectUrl = '';
		};
	});

	onDestroy(() => {
		cropper?.destroy();
		if (objectUrl) URL.revokeObjectURL(objectUrl);
	});

	function confirm() {
		if (!cropper) return;
		const canvas = cropper.getCroppedCanvas({ width: 400, height: 400 });
		const mimeType = file.type === 'image/webp' ? 'image/webp' : 'image/jpeg';
		canvas.toBlob(
			(blob: Blob | null) => {
				if (blob) onconfirm(blob, mimeType);
			},
			mimeType,
			0.9
		);
	}

	function handleClose() {
		open = false;
		oncancel();
	}
</script>

<Dialog bind:open onclose={handleClose} class="max-w-sm">
	<DialogHeader>
		<DialogTitle>Crop profile picture</DialogTitle>
	</DialogHeader>

	<!-- Cropper image container — overflow must be visible so cropperjs can
	     render the crop canvas outside the natural image bounds. The fixed
	     height gives cropperjs a stable container to size itself against. -->
	<div class="px-5">
		<div class="rounded-xl bg-(--color-surface-2)" style="height: 300px; position: relative;">
			<img
				bind:this={imgEl}
				alt="Crop preview"
				style="display:block; max-width:100%; max-height:100%;"
			/>
		</div>
		<p class="text-xs text-(--color-muted) text-center mt-3">
			Drag to reposition · pinch or scroll to zoom · drag corners to resize
		</p>
	</div>

	<DialogFooter>
		<Button variant="outline" onclick={handleClose}>Cancel</Button>
		<Button variant="default" onclick={confirm}>Use photo</Button>
	</DialogFooter>
</Dialog>
