<script lang="ts">
	import { createQuery } from '@tanstack/svelte-query';
	import { getPhoto } from '$lib/services/photoprism';
	import {
		closePreview,
		preview,
		previewNext,
		previewPrev
	} from '$lib/stores/preview.svelte';
	import { thumbUrl, videoUrl } from '$lib/stores/session.svelte';
	import { setFocused } from '$lib/stores/selection.svelte';
	import RightSidebar from '$lib/components/sidebar/RightSidebar.svelte';
	import { isVideo, primaryFile, videoFile, type PpPhoto } from '$lib/types/photoprism';

	const photoQuery = createQuery<PpPhoto>(() => ({
		queryKey: ['photo', preview.uid ?? ''],
		queryFn: () => getPhoto(preview.uid as string),
		enabled: Boolean(preview.uid)
	}));

	// Mirror the currently-shown photo into selection.focused. The
	// timeline's tile uses `selection.focused === photo.UID` to draw the
	// blue ring, so this keeps the selection in lockstep with whatever
	// the user is paging through in preview. The host page (+page.svelte)
	// owns the matching scroll-into-view on close so the tile actually
	// mounts (it can be windowed out if the user navigated far).
	$effect(() => {
		if (preview.uid !== null) setFocused(preview.uid);
	});

	// Keyboard handling lives at the document level so it works regardless
	// of focus location. Form fields inside the sidebar still keep their
	// own arrow-key behaviour because we ignore events whose target is an
	// input/textarea.
	$effect(() => {
		function onKey(e: KeyboardEvent) {
			if (preview.uid === null) return;
			const tag = (e.target as HTMLElement | null)?.tagName?.toLowerCase();
			const inField = tag === 'input' || tag === 'textarea' || tag === 'select';
			switch (e.key) {
				case 'Escape':
					e.preventDefault();
					closePreview();
					break;
				case 'ArrowLeft':
					if (inField) return;
					e.preventDefault();
					previewPrev();
					break;
				case 'ArrowRight':
					if (inField) return;
					e.preventDefault();
					previewNext();
					break;
			}
		}
		window.addEventListener('keydown', onKey);
		return () => window.removeEventListener('keydown', onKey);
	});

	// Prevent body scroll while the overlay is up.
	$effect(() => {
		if (typeof document === 'undefined') return;
		const prev = document.body.style.overflow;
		if (preview.uid !== null) document.body.style.overflow = 'hidden';
		return () => {
			document.body.style.overflow = prev;
		};
	});

	function onBackdrop(e: MouseEvent) {
		// Clicking the dimmed area (but not the image or sidebar) closes.
		if (e.target === e.currentTarget) closePreview();
	}

	const currentIndex = $derived(
		preview.uid ? preview.order.indexOf(preview.uid) : -1
	);
</script>

{#if preview.uid !== null}
	<div
		class="fixed inset-0 z-50 flex bg-black/80 backdrop-blur-sm"
		role="dialog"
		aria-modal="true"
		aria-label="Photo preview"
		onclick={onBackdrop}
		onkeydown={(e) => {
			if (e.key === 'Escape') closePreview();
		}}
		tabindex="-1"
	>
		<!-- Left: image area -->
		<div
			class="relative flex flex-1 items-center justify-center p-6"
			onclick={onBackdrop}
			role="presentation"
		>
			<button
				class="absolute left-4 top-4 z-10 rounded-md bg-background/80 px-2.5 py-1.5 text-xs hover:bg-background"
				onclick={closePreview}
				aria-label="Close preview"
			>
				✕ Close
			</button>

			{#if currentIndex > 0}
				<button
					class="absolute left-2 z-10 rounded-full bg-background/80 px-3 py-2 text-lg hover:bg-background"
					onclick={previewPrev}
					aria-label="Previous photo"
				>
					‹
				</button>
			{/if}
			{#if currentIndex >= 0 && currentIndex < preview.order.length - 1}
				<button
					class="absolute right-2 z-10 rounded-full bg-background/80 px-3 py-2 text-lg hover:bg-background"
					onclick={previewNext}
					aria-label="Next photo"
				>
					›
				</button>
			{/if}

			{#if photoQuery.isPending}
				<p class="text-sm text-white/80">Loading…</p>
			{:else if photoQuery.isError}
				<p class="text-sm text-red-300">Failed to load photo.</p>
			{:else if photoQuery.data}
				{@const pf = primaryFile(photoQuery.data)}
				{#if isVideo(photoQuery.data)}
					{@const vf = videoFile(photoQuery.data)}
					<!-- svelte-ignore a11y_media_has_caption -->
					<video
						src={videoUrl(vf.Hash)}
						poster={thumbUrl(pf.Hash, 'fit_1920')}
						controls
						autoplay
						muted
						class="max-h-full max-w-full rounded-md object-contain shadow-2xl"
					></video>
				{:else}
					<img
						src={thumbUrl(pf.Hash, 'fit_1920')}
						alt={photoQuery.data.OriginalName ?? pf.Name ?? 'Photo'}
						class="max-h-full max-w-full rounded-md object-contain shadow-2xl"
					/>
				{/if}
			{/if}
		</div>

		<!-- Right: metadata sidebar -->
		<aside
			class="w-[360px] shrink-0 overflow-y-auto border-l border-border bg-background p-4"
		>
			{#if photoQuery.data}
				<RightSidebar photo={photoQuery.data} />
			{:else}
				<p class="text-sm text-muted-foreground">Loading metadata…</p>
			{/if}
		</aside>
	</div>
{/if}
