<script lang="ts">
  import { marked } from "marked";
  import { fade } from "svelte/transition";
  import { getBlockLayoutClasses } from "../../lib/block-layout";
  import type { ImageGalleryBlockData, ImageGalleryImage } from "../../lib/block-types";
  import "../../lib/iconify-offline";
  import Icon from "@iconify/svelte";
  import { useTranslate } from "../../lib/translations";
  import { T } from "../../lib/translations";

  const t = useTranslate();
  let { block }: { block: ImageGalleryBlockData } = $props();

  marked.setOptions({ gfm: true });

  const layoutClasses = $derived(getBlockLayoutClasses(block.layout));
  const descriptionHtml = $derived(
    block.description && typeof block.description === "string"
      ? (marked.parse(block.description) as string)
      : "",
  );
  const images = $derived(
    (block.images ?? []).filter((i): i is ImageGalleryImage => i != null && typeof i === "object"),
  );
  const withUrl = $derived(
    images
      .map((img) => ({ img, url: img.resolvedSrc ?? imageUrl(img) }))
      .filter((x): x is { img: ImageGalleryImage; url: string } => x.url != null),
  );

  let currentIndex = $state(0);

  function imageUrl(img: ImageGalleryImage): string | null {
    if (typeof img.src === "string") return img.src.startsWith("//") ? `https:${img.src}` : img.src;
    if (img.file?.url) return img.file.url.startsWith("//") ? `https:${img.file.url}` : img.file.url;
    return null;
  }

  function prev() {
    currentIndex = (currentIndex - 1 + withUrl.length) % withUrl.length;
  }

  function next() {
    currentIndex = (currentIndex + 1) % withUrl.length;
  }

  const SWIPE_THRESHOLD = 50;
  let startX = $state(0);
  let isDragging = $state(false);
  let dragDelta = $state(0);

  function onPointerDown(e: PointerEvent) {
    if (withUrl.length <= 1) return;
    startX = e.clientX;
    isDragging = true;
    dragDelta = 0;
    (e.currentTarget as HTMLElement).setPointerCapture?.(e.pointerId);
  }

  function onPointerMove(e: PointerEvent) {
    if (!isDragging) return;
    dragDelta = e.clientX - startX;
    if (e.pointerType === "touch" && Math.abs(dragDelta) > 10) e.preventDefault();
  }

  function onPointerUp() {
    if (!isDragging) return;
    if (Math.abs(dragDelta) > SWIPE_THRESHOLD) {
      if (dragDelta < 0) next();
      else prev();
    }
    isDragging = false;
    dragDelta = 0;
    startX = 0;
  }

  function onTouchStart(e: TouchEvent) {
    if (withUrl.length <= 1) return;
    startX = e.touches[0].clientX;
    isDragging = true;
    dragDelta = 0;
  }

  function onTouchMove(e: TouchEvent) {
    if (!isDragging || !e.touches[0]) return;
    const delta = e.touches[0].clientX - startX;
    dragDelta = delta;
    if (Math.abs(delta) > 10) e.preventDefault();
  }

  function onTouchEnd() {
    if (!isDragging) return;
    if (Math.abs(dragDelta) > SWIPE_THRESHOLD) {
      if (dragDelta < 0) next();
      else prev();
    }
    isDragging = false;
    dragDelta = 0;
    startX = 0;
  }
</script>

<div class={layoutClasses} data-block-type="image_gallery" data-block-slug={block._slug}>
  {#if descriptionHtml}
    <div class="markdown max-w-none prose prose-zinc mb-4">
      {@html descriptionHtml}
    </div>
  {/if}

  {#if withUrl.length === 0}
    <p class="text-sm text-stein-500">{t(T.image_gallery_empty)}</p>
  {:else if withUrl.length === 1}
    <figure class="m-0">
      <img
        src={withUrl[0].url}
        alt={withUrl[0].img.description ?? ""}
        class="w-full rounded-sm object-cover aspect-video"
        loading="eager"
      />
      {#if withUrl[0].img.description}
        <figcaption class="mt-1 text-sm text-stein-600">{withUrl[0].img.description}</figcaption>
      {/if}
    </figure>
  {:else}
    <div class="group relative">
      <div
        class="relative overflow-hidden rounded-sm bg-stein-100 aspect-video touch-pan-y cursor-grab active:cursor-grabbing"
        role="region"
        aria-label={t(T.image_gallery_swipe_aria)}
        onpointerdown={onPointerDown}
        onpointermove={onPointerMove}
        onpointerup={onPointerUp}
        onpointercancel={onPointerUp}
        ontouchstart={onTouchStart}
        ontouchmove={onTouchMove}
        ontouchend={onTouchEnd}
        ontouchcancel={onTouchEnd}
      >
        {#key currentIndex}
          {@const current = withUrl[currentIndex]}
          <figure
            class="m-0 absolute inset-0"
            transition:fade={{ duration: 200 }}
          >
            <img
              src={current.url}
              alt={current.img.description ?? ""}
              class="w-full h-full object-cover"
              loading={currentIndex === 0 ? "eager" : "lazy"}
            />
            {#if current.img.description}
              <figcaption
                class="absolute bottom-0 left-0 right-0 py-2 px-3 text-xs text-white bg-black/50 rounded-b-sm transition-opacity lg:opacity-0 lg:group-hover:opacity-100"
              >
                {current.img.description}
              </figcaption>
            {/if}
          </figure>
        {/key}
      </div>

      <button
        type="button"
        class="absolute left-2 top-1/2 -translate-y-1/2 w-6 h-6 flex items-center justify-center rounded-full bg-black/50 text-white hover:bg-black/70 transition-opacity focus:outline-none focus:ring-2 focus:ring-wald-500 lg:opacity-0 lg:group-hover:opacity-100"
        aria-label={t(T.image_gallery_prev_aria)}
        onclick={prev}
      >
        <Icon icon="mdi:chevron-left" class="text-2xl" aria-hidden="true" />
      </button>
      <button
        type="button"
        class="absolute right-2 top-1/2 -translate-y-1/2 w-6 h-6 flex items-center justify-center rounded-full bg-black/50 text-white hover:bg-black/70 transition-opacity focus:outline-none focus:ring-2 focus:ring-wald-500 lg:opacity-0 lg:group-hover:opacity-100"
        aria-label={t(T.image_gallery_next_aria)}
        onclick={next}
      >
        <Icon icon="mdi:chevron-right" class="text-2xl" aria-hidden="true" />
      </button>

      <div class="flex justify-center gap-1.5 mt-2" role="tablist" aria-label={t(T.image_gallery_position_aria)}>
        {#each withUrl as _, i}
          <button
            type="button"
            role="tab"
            aria-label={t(T.image_gallery_slide_aria, { index: i + 1 })}
            aria-selected={i === currentIndex}
            class="w-2 h-2 rounded-full transition-colors {i === currentIndex
              ? "bg-wald-600"
              : "bg-stein-300 hover:bg-stein-400"}"
            onclick={() => (currentIndex = i)}
          ></button>
        {/each}
      </div>
    </div>
  {/if}
</div>
