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

	interface Props {
		oncomplete: (base64: string, mediaType: string, thumbnailBase64: string) => void;
		oncancel: () => void;
	}

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

	let count = $state(3);
	let videoElement: HTMLVideoElement | null = $state(null);
	let stream: MediaStream | null = $state(null);
	let error: string | null = $state(null);
	let cancelled = false;
	let countdownInterval: ReturnType<typeof setInterval> | null = null;

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

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

		try {
			const constraints: MediaStreamConstraints = {
				video: {
					facingMode: { ideal: 'environment' },
					width: { ideal: 1920 },
					height: { ideal: 1080 }
				},
				audio: false
			};

			stream = await navigator.mediaDevices.getUserMedia(constraints);

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

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

	function startCountdown() {
		countdownInterval = setInterval(() => {
			if (cancelled) {
				stopCamera();
				return;
			}
			count--;
			if (count === 0) {
				if (countdownInterval) clearInterval(countdownInterval);
				capture();
			}
		}, 1000);
	}

	function capture() {
		if (cancelled || !videoElement) {
			stopCamera();
			return;
		}

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

		const ctx = canvas.getContext('2d');
		if (!ctx) {
			stopCamera();
			oncancel();
			return;
		}

		ctx.drawImage(videoElement, 0, 0);

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

		const thumbMaxSize = 800;
		const scale = Math.min(thumbMaxSize / canvas.width, thumbMaxSize / canvas.height, 1);
		const thumbCanvas = document.createElement('canvas');
		thumbCanvas.width = Math.round(canvas.width * scale);
		thumbCanvas.height = Math.round(canvas.height * scale);
		const thumbCtx = thumbCanvas.getContext('2d');
		if (thumbCtx) {
			thumbCtx.drawImage(canvas, 0, 0, thumbCanvas.width, thumbCanvas.height);
		}
		const thumbnailBase64 = thumbCanvas.toDataURL('image/jpeg', 0.7).split(',')[1];

		stopCamera();
		oncomplete(base64, mediaType, thumbnailBase64);
	}

	function handleCancel() {
		cancelled = true;
		stopCamera();
		oncancel();
	}

	onMount(() => {
		startCamera();
		return () => {
			cancelled = 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={handleCancel} class="rounded bg-neutral-700 px-4 py-2 text-sm text-white">
				Close
			</button>
		</div>
	{:else}
		<div class="relative flex-1">
			<video bind:this={videoElement} autoplay playsinline muted class="h-full w-full object-cover"
			></video>
			<div class="absolute inset-0 flex items-center justify-center">
				<span class="text-8xl font-bold text-white drop-shadow-lg">{count}</span>
			</div>
		</div>
		<div class="p-4 text-center">
			<button onclick={handleCancel} class="text-sm text-neutral-400">Cancel</button>
		</div>
	{/if}
</div>
