<script lang="ts">
  import { backOut, cubicIn } from "svelte/easing";
  import { browser } from "$app/environment";

  const photoUrls = __PHOTO_FILES__.map(
    (name) => `/photos/${encodeURIComponent(name)}`,
  );

  function shuffle<T>(items: T[]): T[] {
    const result = [...items];
    for (let i = result.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [result[i], result[j]] = [result[j], result[i]];
    }
    return result;
  }

  // Randomized client-side only: shuffling during SSR/prerender would bake one
  // order into the static HTML while the client picks another, causing a
  // hydration mismatch on the <img src>.
  let photos = $state<string[]>([]);
  const intervalMs = 6000;

  let index = $state(0);
  let reducedMotion = $state(false);

  // Each photo flies in/out from a random angle with its own spin and pop, so
  // no two transitions look alike.
  function funky(
    node: HTMLElement,
    { duration, variant }: { duration: number; variant: "in" | "out" },
  ) {
    if (reducedMotion) {
      return { duration: 400, css: (t: number) => `opacity: ${t}` };
    }
    const angle = Math.random() * Math.PI * 2;
    const dist = 55 + Math.random() * 55;
    const rot = Math.random() * 80 - 40;
    const scaleFrom = 0.5 + Math.random() * 0.3;
    const x = Math.cos(angle) * dist;
    const y = Math.sin(angle) * dist;
    return {
      duration: duration + Math.random() * 300,
      easing: variant === "in" ? backOut : cubicIn,
      css: (t: number, u: number) => `
				transform: translate(${u * x}%, ${u * y}%) rotate(${u * rot}deg) scale(${1 - u * (1 - scaleFrom)});
				opacity: ${t};
			`,
    };
  }

  $effect(() => {
    if (!browser) return;
    photos = shuffle(photoUrls);
  });

  $effect(() => {
    if (!browser) return;
    const query = window.matchMedia("(prefers-reduced-motion: reduce)");
    reducedMotion = query.matches;
    const onChange = (event: MediaQueryListEvent) =>
      (reducedMotion = event.matches);
    query.addEventListener("change", onChange);
    return () => query.removeEventListener("change", onChange);
  });

  $effect(() => {
    if (photos.length < 2) return;
    const id = setInterval(() => {
      index = (index + 1) % photos.length;
    }, intervalMs);
    return () => clearInterval(id);
  });
</script>

{#if photos.length > 0}
  <div
    class="pointer-events-none absolute inset-0 overflow-hidden"
    aria-hidden="true"
  >
    {#key index}
      <img
        src={photos[index]}
        alt=""
        class="absolute inset-0 h-full w-full object-cover md:object-contain"
        in:funky={{ duration: 900, variant: "in" }}
        out:funky={{ duration: 700, variant: "out" }}
      />
    {/key}
    <div
      class="absolute inset-0 bg-surface-950/65 dark:bg-surface-950/75"
    ></div>
  </div>
{/if}
