<script lang="ts">
	import { onMount } from 'svelte';
	import { Maximize2, X, AlertCircle } from 'lucide-svelte';
	import type { CameraWidgetConfig } from '$lib/types/widget.js';

	interface Props {
		config: CameraWidgetConfig;
	}

	let { config }: Props = $props();

	let imgSrc = $state('');
	let loading = $state(true);
	let error = $state(false);
	let fullscreen = $state(false);
	let videoEl: HTMLVideoElement | null = $state(null);
	let fullscreenVideoEl: HTMLVideoElement | null = $state(null);

	const streamType = $derived(config.type ?? 'image');
	const refreshMs = $derived((config.refreshInterval ?? 10) * 1000);
	const aspectRatio = $derived(config.aspectRatio ?? '16/9');

	// For snapshot mode, fetch through our proxy
	function buildProxyUrl(): string {
		const params = new URLSearchParams({ streamUrl: config.streamUrl });
		return `/api/widgets/camera?${params}&t=${Date.now()}`;
	}

	async function fetchSnapshot() {
		error = false;
		try {
			const url = buildProxyUrl();
			// Pre-validate the response
			const res = await fetch(url);
			if (res.ok) {
				const blob = await res.blob();
				if (imgSrc) URL.revokeObjectURL(imgSrc);
				imgSrc = URL.createObjectURL(blob);
			} else {
				error = true;
			}
		} catch {
			error = true;
		} finally {
			loading = false;
		}
	}

	onMount(() => {
		if (streamType === 'image') {
			fetchSnapshot();
		} else if (streamType === 'mjpeg') {
			// MJPEG streams directly via img src
			imgSrc = config.streamUrl;
			loading = false;
		} else if (streamType === 'hls') {
			loading = false;
			// HLS setup via $effect below
		}

		return () => {
			if (imgSrc && streamType === 'image') {
				URL.revokeObjectURL(imgSrc);
			}
		};
	});

	// Auto-refresh for snapshot mode
	$effect(() => {
		if (streamType !== 'image') return;
		const interval = setInterval(fetchSnapshot, refreshMs);
		return () => clearInterval(interval);
	});

	// HLS.js lazy loading
	$effect(() => {
		if (streamType !== 'hls' || !videoEl) return;
		// eslint-disable-next-line @typescript-eslint/no-explicit-any
		let hls: any = null;

		(async () => {
			try {
				const { default: Hls } = await import('hls.js');
				if (Hls.isSupported()) {
					hls = new Hls();
					hls.loadSource(config.streamUrl);
					hls.attachMedia(videoEl!);
				} else if (videoEl!.canPlayType('application/vnd.apple.mpegurl')) {
					videoEl!.src = config.streamUrl;
				} else {
					error = true;
				}
			} catch {
				// HLS.js not available — try native
				if (videoEl!.canPlayType('application/vnd.apple.mpegurl')) {
					videoEl!.src = config.streamUrl;
				} else {
					error = true;
				}
			}
		})();

		return () => {
			if (hls) {
				hls.destroy();
			}
		};
	});

	// HLS.js for fullscreen video element
	$effect(() => {
		if (streamType !== 'hls' || !fullscreenVideoEl) return;
		// eslint-disable-next-line @typescript-eslint/no-explicit-any
		let hls: any = null;

		(async () => {
			try {
				const { default: Hls } = await import('hls.js');
				if (Hls.isSupported()) {
					hls = new Hls();
					hls.loadSource(config.streamUrl);
					hls.attachMedia(fullscreenVideoEl!);
				} else if (fullscreenVideoEl!.canPlayType('application/vnd.apple.mpegurl')) {
					fullscreenVideoEl!.src = config.streamUrl;
				}
			} catch {
				if (fullscreenVideoEl!.canPlayType('application/vnd.apple.mpegurl')) {
					fullscreenVideoEl!.src = config.streamUrl;
				}
			}
		})();

		return () => {
			if (hls) hls.destroy();
		};
	});

	function handleImgError() {
		error = true;
		loading = false;
	}

	function handleImgLoad() {
		loading = false;
		error = false;
	}

	function openFullscreen() {
		fullscreen = true;
	}

	function closeFullscreen() {
		fullscreen = false;
	}
</script>

<div class="flex h-full flex-col rounded-[1.4rem] border border-border bg-card shadow-[var(--shadow-soft)] overflow-hidden">
	<!-- Stream view -->
	<div
		class="relative w-full bg-black"
		style="aspect-ratio: {aspectRatio}"
	>
		{#if loading}
			<div class="absolute inset-0 flex items-center justify-center">
				<div class="flex items-center gap-2 text-sm text-muted-foreground">
					<svg
						class="h-4 w-4 animate-spin"
						xmlns="http://www.w3.org/2000/svg"
						fill="none"
						viewBox="0 0 24 24"
					>
						<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" />
						<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
					</svg>
					Loading...
				</div>
			</div>
		{/if}

		{#if error}
			<div class="absolute inset-0 flex flex-col items-center justify-center gap-2 bg-muted/80">
				<AlertCircle class="h-8 w-8 text-muted-foreground" />
				<span class="text-xs text-muted-foreground">Stream unavailable</span>
			</div>
		{/if}

		{#if streamType === 'hls'}
			<video
				bind:this={videoEl}
				autoplay
				muted
				playsinline
				class="h-full w-full object-contain"
			></video>
		{:else}
			<img
				src={imgSrc}
				alt="Camera stream"
				class="h-full w-full object-contain {loading ? 'opacity-0' : 'opacity-100'} transition-opacity"
				onload={handleImgLoad}
				onerror={handleImgError}
			/>
		{/if}

		<!-- Fullscreen button overlay -->
		{#if !error}
			<button
				type="button"
				onclick={openFullscreen}
				class="absolute bottom-2 right-2 rounded-md bg-black/50 p-1.5 text-white/80 transition-colors hover:bg-black/70 hover:text-white"
				title="Fullscreen"
			>
				<Maximize2 class="h-4 w-4" />
			</button>
		{/if}
	</div>
</div>

<!-- Fullscreen modal -->
{#if fullscreen}
	<!-- svelte-ignore a11y_no_static_element_interactions -->
	<div
		class="fixed inset-0 z-50 flex items-center justify-center bg-black/90"
		onclick={closeFullscreen}
		onkeydown={(e) => e.key === 'Escape' && closeFullscreen()}
	>
		<button
			type="button"
			onclick={closeFullscreen}
			class="absolute right-4 top-4 rounded-md p-2 text-white/80 transition-colors hover:text-white"
		>
			<X class="h-6 w-6" />
		</button>

		<!-- svelte-ignore a11y_click_events_have_key_events -->
		<div class="max-h-[90vh] max-w-[90vw]" onclick={(e) => e.stopPropagation()}>
			{#if streamType === 'hls'}
				<!-- eslint-disable-next-line svelte/no-unused-svelte-ignore -->
				<!-- svelte-ignore a11y_media_has_caption -->
				<video
					autoplay
					muted
					playsinline
					controls
					class="max-h-[90vh] max-w-[90vw] object-contain"
					bind:this={fullscreenVideoEl}
				></video>
			{:else}
				<img
					src={imgSrc}
					alt="Camera stream fullscreen"
					class="max-h-[90vh] max-w-[90vw] object-contain"
				/>
			{/if}
		</div>
	</div>
{/if}
