<script lang="ts">
	import { onMount } from 'svelte';

	interface Props {
		showPreview?: boolean;
		oncapture: (base64: string, mediaType: string) => void;
		onclose: () => void;
	}

	let { showPreview = true, oncapture, onclose }: Props = $props();

	let videoElement: HTMLVideoElement | null = $state(null);
	let stream: MediaStream | null = $state(null);
	let capturedImage: { base64: string; mediaType: string } | null = $state(null);
	let error: string | null = $state(null);
	let closed = false;

	async function findUltraWideCamera(): Promise<string | null> {
		try {
			const devices = await navigator.mediaDevices.enumerateDevices();
			const videoDevices = devices.filter((d) => d.kind === 'videoinput');
			const ultraWide = videoDevices.find(
				(d) => d.label.toLowerCase().includes('ultra') && d.label.toLowerCase().includes('back')
			);
			return ultraWide?.deviceId ?? null;
		} catch {
			return null;
		}
	}

	async function startCamera() {
		if (closed) return;

		if (!navigator.mediaDevices?.getUserMedia) {
			error = 'Camera not supported (requires HTTPS)';
			return;
		}

		try {
			stream = await navigator.mediaDevices.getUserMedia({
				video: { facingMode: { ideal: 'environment' } },
				audio: false
			});

			const ultraWideId = await findUltraWideCamera();

			if (ultraWideId) {
				stream.getTracks().forEach((t) => t.stop());
				stream = await navigator.mediaDevices.getUserMedia({
					video: {
						deviceId: { exact: ultraWideId },
						width: { ideal: 4032 },
						height: { ideal: 3024 }
					},
					audio: false
				});
			} else {
				stream.getTracks().forEach((t) => t.stop());
				stream = await navigator.mediaDevices.getUserMedia({
					video: {
						facingMode: { ideal: 'environment' },
						width: { ideal: 4032 },
						height: { ideal: 3024 }
					},
					audio: false
				});
			}

			if (videoElement && !closed) {
				videoElement.srcObject = stream;
			}
		} catch (e) {
			error = e instanceof Error ? e.message : 'Camera access denied';
		}
	}

	function stopCamera() {
		if (stream) {
			stream.getTracks().forEach((track) => track.stop());
			stream = null;
		}
	}

	function capture() {
		if (!videoElement) return;

		const canvas = document.createElement('canvas');
		canvas.width = videoElement.videoWidth;
		canvas.height = videoElement.videoHeight;

		const ctx = canvas.getContext('2d');
		if (!ctx) return;

		ctx.drawImage(videoElement, 0, 0);

		const maxSize = 1920;
		const scale = Math.min(maxSize / canvas.width, maxSize / canvas.height, 1);
		const outCanvas = document.createElement('canvas');
		outCanvas.width = Math.round(canvas.width * scale);
		outCanvas.height = Math.round(canvas.height * scale);
		const outCtx = outCanvas.getContext('2d');
		if (!outCtx) return;
		outCtx.drawImage(canvas, 0, 0, outCanvas.width, outCanvas.height);

		const base64 = outCanvas.toDataURL('image/jpeg', 0.65).split(',')[1];
		const mediaType = 'image/jpeg';

		stopCamera();

		if (showPreview) {
			capturedImage = { base64, mediaType };
		} else {
			oncapture(base64, mediaType);
		}
	}

	function acceptCapture() {
		if (capturedImage) {
			oncapture(capturedImage.base64, capturedImage.mediaType);
		}
	}

	function retake() {
		capturedImage = null;
		startCamera();
	}

	function close() {
		closed = true;
		stopCamera();
		onclose();
	}

	onMount(() => {
		startCamera();
		return () => {
			closed = true;
			stopCamera();
		};
	});
</script>

<div class="fixed inset-0 z-50 flex flex-col bg-black" data-camera-ui>
	{#if error}
		<div class="flex flex-1 flex-col items-center justify-center p-4">
			<p class="mb-4 text-center text-sm text-red-400">{error}</p>
			<button onclick={close} class="rounded bg-neutral-700 px-4 py-2 text-sm text-white">
				Close
			</button>
		</div>
	{:else if capturedImage}
		<div class="relative min-h-0 flex-1">
			<button class="absolute inset-0" onclick={acceptCapture}>
				<img
					src="data:{capturedImage.mediaType};base64,{capturedImage.base64}"
					alt="Captured"
					class="h-full w-full object-contain"
				/>
			</button>
		</div>
		<div class="flex gap-4 p-4">
			<button onclick={retake} class="flex-1 rounded bg-neutral-700 py-3 text-sm text-white">
				Retake
			</button>
			<button onclick={acceptCapture} class="flex-1 rounded bg-blue-600 py-3 text-sm text-white">
				Use
			</button>
		</div>
	{:else}
		<video bind:this={videoElement} autoplay playsinline muted class="h-full w-full object-cover"
		></video>
		<button
			onclick={close}
			class="absolute top-4 right-4 flex h-8 w-8 items-center justify-center rounded-full bg-black/50 text-white"
		>
			×
		</button>
		<button
			onclick={capture}
			aria-label="Capture photo"
			class="absolute bottom-8 left-1/2 h-16 w-16 -translate-x-1/2 rounded-full border-4 border-white bg-white/20"
		></button>
	{/if}
</div>
