<script lang="ts">
  import IconButton from '../iconbutton/IconButton.svelte';
  import { ChevronLeft20, ChevronRight20 } from '@mozaic-ds/icons-svelte';
  /**
   * A Carousel allows users to browse through multiple items within a horizontal container, using swipe gestures on mobile or navigation controls on desktop. It is primarily used to showcase products, promotions, or visual content, offering an engaging way to explore information in a condensed and interactive format. Carousels help optimize space while keeping content visually appealing and easily accessible.
   *
   * @slot default - Use this slot to insert a list of components to be displayed in the carousel.
   * @slot header  - Use this slot to insert the title, subtitle or link of the carousel.
   */
  interface Props {
    [key: string]: any;
    /**
     * Aria label for the previous button.
     */
    previousButtonAriaLabel?: string;
    /**
     * Aria label for the next button.
     */
    nextButtonAriaLabel?: string;
  }

  let {
    previousButtonAriaLabel = 'previous',
    nextButtonAriaLabel = 'next',
    class: className,
    ...attrs
  }: Props = $props();

  // State
  let activeIndex = $state(0);
  let contentContainer: HTMLElement | null = null;

  let observer: IntersectionObserver | null = null;

  const scrollOptions: ScrollIntoViewOptions = {
    behavior: 'smooth',
    block: 'nearest',
    inline: 'center',
  };

  function getCarouselChildren(): HTMLElement[] {
    if (!contentContainer) return [];

    const slot = contentContainer.querySelector('slot') as HTMLSlotElement;
    return slot ? (slot.assignedElements({ flatten: true }) as HTMLElement[]) : [];
  }

  function scrollToChild(index: number) {
    const children = getCarouselChildren();
    children[index]?.scrollIntoView(scrollOptions);
  }

  function goPrevious() {
    if (activeIndex > 0) scrollToChild(activeIndex - 1);
  }

  function goNext() {
    const children = getCarouselChildren();
    if (activeIndex < children.length - 1) scrollToChild(activeIndex + 1);
  }

  $effect(() => {
    if (!contentContainer) return;

    observer = new IntersectionObserver(
      (entries) => {
        const entry = entries.find((e) => e.isIntersecting);
        if (entry) {
          const children = getCarouselChildren();
          activeIndex = children.findIndex((el) => el === entry.target);
        }
      },
      {
        root: contentContainer,
        threshold: 0.9,
      },
    );

    getCarouselChildren().forEach((el) => observer!.observe(el));

    return () => observer?.disconnect();
  });

  const isFirstChildActive = $derived(activeIndex === 0);
  const isLastChildActive = $derived(activeIndex === getCarouselChildren().length - 1);
</script>

<div
  class={['mc-carousel', className]}
  role="group"
  aria-roledescription="carousel"
  aria-labelledby="mc-carousel__title"
  {...attrs}
>
  <div class="mc-carousel__header">
    <div class="mc-carousel__headings">
      <slot name="header" />
    </div>

    <div class="mc-carousel__controls">
      <IconButton
        size="s"
        outlined
        onclick={goPrevious}
        disabled={isFirstChildActive}
        aria-label={previousButtonAriaLabel}
      >
        <ChevronLeft20 slot="icon" />
      </IconButton>

      <IconButton
        size="s"
        outlined
        onclick={goNext}
        disabled={isLastChildActive}
        aria-label={nextButtonAriaLabel}
      >
        <ChevronRight20 slot="icon" />
      </IconButton>
    </div>
  </div>

  <div class="mc-carousel__content" bind:this={contentContainer}>
    <slot />
  </div>
</div>

<style>/**
 * Do not edit directly, this file was auto-generated.
 */
.mt-title {
  font-weight: var(--font-accent, 600);
}
.mt-title--l {
  font-size: var(--font-title-l, 1.75rem);
  line-height: calc(var(--font-title-l, 1.75rem) * var(--line-height-s, 1.3));
}
.mt-title--m {
  font-size: var(--font-title-m, 1.5rem);
  line-height: calc(var(--font-title-m, 1.5rem) * var(--line-height-s, 1.3));
}
.mt-title--s {
  font-size: var(--font-title-s, 1.125rem);
  line-height: calc(var(--font-title-s, 1.125rem) * var(--line-height-s, 1.3));
}

.mc-carousel {
  display: flex;
  flex-direction: column;
  row-gap: 1rem;
}
.mc-carousel__header {
  display: flex;
  align-items: flex-start;
}
.mc-carousel__headings {
  display: flex;
  flex-direction: column;
  row-gap: 0.25rem;
  flex: 1;
  align-items: flex-start;
  color: var(--color-text-primary, #000000);
}
.mc-carousel__controls {
  display: flex;
  column-gap: 0.5rem;
  margin: 0.25rem 0.25rem 0 0;
}
.mc-carousel__content {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
}
.mc-carousel__content > * {
  scroll-snap-align: start;
}

:global(::slotted(*)) {
  scroll-snap-align: start;
}

:global(::slotted(.mc-carousel__title)) {
  margin: 0;
}

:global(::slotted(.mc-carousel__sub-title)) {
  margin: 0;
}</style>
