<script lang="ts">
	// Slide transition: the incoming slide glides in from one edge while the outgoing slide
	// is pushed off the opposite edge on the same axis — the pair travels together, edge to
	// edge, like a filmstrip / conveyor. `phase` tells this instance which half it is:
	//   enter → starts offscreen, settles at centre (the new photo)
	//   exit  → starts at centre, leaves offscreen the same way (the previous photo)
	// The diashow's two-layer stack renders both at once, so the push reads as one motion.
	//
	// The animation lives in scoped classes, not an inline animation declaration: Svelte
	// scopes keyframe names and only rewrites animation references inside the scoped style
	// block, so an inline animation name silently never matches its keyframe. Dynamic values
	// (duration, offsets) ride in as inline CSS custom properties, which pass through
	// untouched. Switching the is-exit class swaps animation-name, which restarts the
	// animation — the mechanism that lets the previous frame begin its exit.

	interface Props {
		src: string;
		isVideo: boolean;
		durationMs: number;
		/** Fired when a video slide finishes so the parent can advance early. */
		onended?: () => void;
		/** Edge the slide enters from. */
		direction?: 'up' | 'down' | 'left' | 'right';
		/** Which half of the push this instance plays. */
		phase?: 'enter' | 'exit';
	}

	let { src, isVideo, durationMs, onended, direction = 'up', phase = 'enter' }: Props = $props();

	// Offscreen offsets. The incoming slide starts at `enterFrom` and ends centred; the
	// outgoing slide ends at `exitTo` — the opposite edge on the same axis — so both travel
	// the same direction and stay adjacent (no overlap, no gap).
	const enterFrom = $derived(
		{
			up: 'translateY(100%)',
			down: 'translateY(-100%)',
			left: 'translateX(100%)',
			right: 'translateX(-100%)'
		}[direction]
	);
	const exitTo = $derived(
		{
			up: 'translateY(-100%)',
			down: 'translateY(100%)',
			left: 'translateX(-100%)',
			right: 'translateX(100%)'
		}[direction]
	);
</script>

<div
	class="slide-layer absolute inset-0 flex items-center justify-center bg-black"
	class:is-exit={phase === 'exit'}
	style="--slide-dur: {durationMs}ms; --enter-from: {enterFrom}; --exit-to: {exitTo};"
>
	{#if isVideo}
		<!-- svelte-ignore a11y_media_has_caption -->
		<video {src} autoplay muted playsinline {onended} class="h-full w-full object-contain"></video>
	{:else}
		<img {src} alt="" class="h-full w-full object-contain" />
	{/if}
</div>

<style>
	.slide-layer {
		/* easeInOutSine — a gentle slow → fast → slow curve so the push eases in and settles
		   softly rather than lurching from a fast start. */
		animation: slide-enter var(--slide-dur, 1000ms) cubic-bezier(0.37, 0, 0.63, 1) forwards;
		will-change: transform;
	}
	.slide-layer.is-exit {
		animation-name: slide-exit;
	}
	@keyframes slide-enter {
		from {
			transform: var(--enter-from, translateY(100%));
		}
		to {
			transform: translate(0, 0);
		}
	}
	@keyframes slide-exit {
		from {
			transform: translate(0, 0);
		}
		to {
			transform: var(--exit-to, translateY(-100%));
		}
	}
	@keyframes slide-fade {
		from {
			opacity: 0;
		}
		to {
			opacity: 1;
		}
	}
	@keyframes slide-fade-out {
		from {
			opacity: 1;
		}
		to {
			opacity: 0;
		}
	}
	/* Respect users who ask for less motion — cross-dissolve instead of travelling. */
	@media (prefers-reduced-motion: reduce) {
		.slide-layer {
			animation: slide-fade var(--slide-dur, 1000ms) ease-out forwards;
		}
		.slide-layer.is-exit {
			animation: slide-fade-out var(--slide-dur, 1000ms) ease-out forwards;
		}
	}
</style>
