<template>
  <div class="slider-container">
    <div class="slider-track" :style="animationStyle">
      <div
        v-for="(image, index) in repeatedItems"
        :key="`${image.text?.value}__${index}`"
        :class="sliderItemClass"
      >
        <img
          v-if="slideImageDesign.visible && image.content?.hasContent"
          class="slider-item__image"
          :src="image.content.highResolutionMobileImage"
          loading="lazy"
          :alt="image.text?.value"
        />

        <div class="slider-item__wrapper">
          <div
            v-if="slideTextDesign.visible"
            class="slider-item__text"
          >
            {{ image.text?.value }}
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import {
  ref,
  computed,
  onMounted,
  onBeforeUnmount,
  CSSProperties,
  watch,
} from 'vue';
import {
  useDeckElementContent,
  EditorTypes,
  Card,
  TextAreaContent,
  ImageContent,
  useLayoutElementDesign,
  useImageElementDesign,
  useTextElementDesign,
} from '@lightspeed/crane';
import { Content, Design } from '../type.ts';

type Slide = {
  text?: TextAreaContent;
  content?: ImageContent;
}

const slideImageDesign = useImageElementDesign<Design>('image_content');
const slideTextDesign = useTextElementDesign<Design>('image_text');

const slideOverlayConfig = computed(() => ({
  solidOverlay: (slideImageDesign.overlay?.solid?.color as Color).raw,
  gradientOverlay: 'linear-gradient(180deg, '
      + `${(slideImageDesign.overlay?.gradient?.fromColor as Color).raw}1A 0%, `
      + `${(slideImageDesign.overlay?.gradient?.toColor as Color).raw}70 100%)`,
}));

const slideImageStyles = computed<CSSProperties>(() => {
  const style: CSSProperties = {};

  if (slideImageDesign.overlay?.type === 'gradient') {
    style.background = slideOverlayConfig.value.gradientOverlay;
  }
  if (slideImageDesign.overlay?.type === 'solid') {
    style.background = slideOverlayConfig.value.solidOverlay;
  }

  return style;
});

const slideTextStyles = computed<CSSProperties>(() => ({
  fontSize: `${slideTextDesign.size}px`,
  fontFamily: slideTextDesign.font,
  color: (slideTextDesign.color as Color).hex,
  fontStyle: slideTextDesign.italic ? 'italic' : 'normal',
  fontWeight: slideTextDesign.bold ? 'bold' : 'normal',
}));

const sliderContent = useDeckElementContent<Content>('slider');

const slides = computed<Slide[]>(() => (
  (sliderContent?.cards?.map((card: Card) => ({
    text: sliderContent.getReactiveRef(card, EditorTypes.TEXTAREA, 'image_text') as TextAreaContent | undefined,
    content: sliderContent.getReactiveRef(card, EditorTypes.IMAGE, 'image_content') as ImageContent | undefined,
  })) ?? []).filter((image) => (image.content !== undefined && image.content.hasContent))
));

const layoutDesign = useLayoutElementDesign();
const sliderItemClass = computed(() => [
  'slider-item',
  {
    'slider-item--with-border-radius': layoutDesign.layout === 'Narrow_Title_And_Images_With_Border_Radius',
  },
]);

const windowWidth = ref<number>(typeof window !== 'undefined' ? window.innerWidth : 0);

const repeatedItems = ref<Slide[]>([]);

const isSmallWindow = computed<boolean>(() => windowWidth.value < 800);

const slideWidth = computed<number>(() => (isSmallWindow.value ? 167 : 256));
const formattedSlideWidth = computed<string>(() => `${slideWidth.value}px`);

const slideGap = computed<number>(() => (isSmallWindow.value ? 20 : 32));
const formattedSlideGap = computed<string>(() => `${slideGap.value}px`);

const slideSize = computed<number>(() => slideWidth.value + slideGap.value);

function initializeItems(): void {
  windowWidth.value = window.innerWidth;
  const minItemsToFillViewport = Math.ceil(windowWidth.value / slideSize.value);
  const repeats = Math.ceil(minItemsToFillViewport / (slides.value?.length as number)) + 1;

  repeatedItems.value = Array(repeats).fill(slides.value).flat();
}

const animationStyle = computed<CSSProperties>(() => {
  const totalWidth = repeatedItems.value.length * slideSize.value;

  return {
    width: `${totalWidth}px`,
  };
});

watch(slides, initializeItems);

onMounted(() => {
  initializeItems();
  window.addEventListener('resize', initializeItems);
});

onBeforeUnmount(() => {
  window.removeEventListener('resize', initializeItems);
});
</script>

<style lang="scss" scoped>
.slider-container {
  overflow: hidden;
  width: 100%;
  white-space: nowrap;
  margin-top: 48px;

  --slide-width: v-bind(formattedSlideWidth);
  --slide-gap: v-bind(formattedSlideGap);
}

.slider-track {
  display: flex;
  align-items: center;
  animation: scroll 40s linear infinite 1s;
  -webkit-animation: scroll 40s linear infinite 1s;
}

.slider-item {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: var(--slide-width);
  margin-right: var(--slide-gap);
  height: 218px;

  flex-shrink: 0;
  overflow: hidden;

  &--with-border-radius {
    border-radius: 16px;
  }

  @media screen and (min-width: 800px) {
    height: 334px;

    &--with-border-radius {
      border-radius: 24px;
    }
  }

  &__wrapper {
    --slider-item-background: v-bind(slideImageStyles.background);

    position: absolute;
    display: flex;
    width: 100%;
    height: 100%;
    left: 0;
    bottom: 0;
    padding: 16px;
    background: var(--slider-item-background);
  }

  &__text {
    --slider-item-text-font-size: v-bind(slideTextStyles.fontSize);
    --slider-item-text-font-family: v-bind(slideTextStyles.fontFamily);
    --slider-item-text-color: v-bind(slideTextStyles.color);
    --slider-item-text-font-style: v-bind(slideTextStyles.fontStyle);
    --slider-item-text-font-weight: v-bind(slideTextStyles.fontWeight);

    margin: auto 0 0;
    line-height: normal;
    overflow: hidden;
    text-overflow: ellipsis;
    font-family: var(--slider-item-text-font-family);
    font-size: var(--slider-item-text-font-size);
    font-style: var(--slider-item-text-font-style);
    font-weight: var(--slider-item-text-font-weight);
    color: var(--slider-item-text-color);
  }

  &__image {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
}

@keyframes scroll {
  0% {
    transform: translateX(0);
  }

  100% {
    transform: translateX(-50%);
  }
}
</style>
