<script lang="ts">
  let slot: HTMLDivElement;
  let images: (HTMLPictureElement | HTMLImageElement)[];

  export let title: string;

  let altText: string;
  let height: number;
  let loaded = false;

  function hide(index: number) {
    const img = images[index];
    img.classList.remove("active");
  }

  const heightCache = [];
  function show(index: number) {
    const img = images[index];
    img.classList.add("active");
    const _img = img.querySelector("img") || img;
    if (!_img) return;
    _img.addEventListener("load", () => {
      img.classList.remove("thumb-loading");
      _img.style.opacity = "1";
    });
    altText = _img["alt"] ?? _img.getAttribute("alt") ?? "";
    if (heightCache[index]) {
      height = heightCache[index];
    }
    setTimeout(() => {
      height = heightCache[index] ?? _img.getBoundingClientRect().height;
      heightCache[index] = height;
    }, 100);
  }

  let index = 0;
  function setIndex(i: number) {
    if (i < 0) i = images.length - 1;
    if (i >= images.length) i = 0;
    hide(index);
    index = i;
    show(index);
  }

  $: if (slot && !images?.length) {
    images = Array.from(slot.querySelectorAll("picture"));
    if (images?.length) {
      images.forEach((_, i) => hide(i));
      show(index);
      images[index].onload = () => {
        loaded = true;
        height = images[index].getBoundingClientRect().height;
      };
    }
    setTimeout(() => {
      loaded = true;
    }, 100);
  }
</script>

<div
  class="wrapper grid overflow-hidden rounded-xl border border-neutral"
  class:title={true}
  class:not-loaded={!loaded}
  class:loaded
  style={`--height:${height}px`}>
  <div class="flex items-center p-x-4 p-y-6 bg justify-between">
    <h3>{title}</h3>

    <div
      class="overflow-hidden rounded-md bg-light gap-2 flex p-2 border border-light">
      <button
        class="flex-1 i-tabler-arrow-left"
        aria-label="previous image"
        on:click={() => setIndex(index - 1)}></button>
      <button
        class="flex-1 i-tabler-arrow-right"
        aria-label="next image"
        on:click={() => setIndex(index + 1)}></button>
    </div>
  </div>

  <div class="images border-block border-neutral" bind:this={slot}>
    <slot />
  </div>
  <div class="px-4 flex items-center place-content-between bg">
    <p>
      {#if images?.length}
        {index + 1}/{images?.length}
      {/if}
    </p>
    {#if altText}
      <p class="flex-1 text-center">{altText}</p>
    {/if}
  </div>
</div>

<style>
  .wrapper {
    grid-template-rows: 1fr 50px;
    transition: height 0.3s;
  }

  .wrapper :global(.image-wrapper) {
    margin: 0 !important;
  }

  .wrapper.title {
    grid-template-rows: 50px 1fr 50px;
  }

  .loaded {
    height: calc(var(--height) + 50px);
  }

  .not-loaded .images :global(picture):first-child {
    display: block !important;
  }

  .wrapper.title.loaded {
    height: calc(var(--height) + 100px);
  }

  .images :global(picture) {
    border-radius: 0px;
    display: none;
  }

  .images :global(.thumb-loading)::before {
    opacity: 0;
  }

  .images :global(.active) {
    position: relative;
    display: block !important;
    opacity: 1;
    transition:
      opacity 0.3s ease,
      display 0.3s 0.3s;
  }
</style>
