<script setup>
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from "vue";
import { useNamespace } from "@yh-ui/hooks";
import { useComponentTheme } from "@yh-ui/theme";
import { marqueeProps, marqueeEmits } from "./marquee";
defineOptions({
  name: "YhMarquee"
});
const props = defineProps(marqueeProps);
const emit = defineEmits(marqueeEmits);
const ns = useNamespace("marquee");
const { themeStyle } = useComponentTheme(
  "marquee",
  computed(() => props.themeOverrides)
);
const containerRef = ref(null);
const contentRef = ref(null);
const cloneCount = ref(1);
const isReady = ref(false);
const isHidden = ref(false);
const isLoopPaused = ref(false);
let delayTimer = null;
const computedDuration = computed(() => {
  if (props.speed > 0 && contentRef.value) {
    const size = props.direction === "horizontal" ? contentRef.value.scrollWidth : contentRef.value.scrollHeight;
    return size / props.speed;
  }
  return props.duration;
});
const marqueeStyle = computed(() => {
  const gapValue = typeof props.gap === "number" ? `${props.gap}px` : props.gap;
  const durationValue = `${computedDuration.value}s`;
  const iterationCount = props.loop > 0 ? props.loop : "infinite";
  return {
    "--yh-marquee-gap": gapValue,
    "--yh-marquee-duration": durationValue,
    "--yh-marquee-iteration-count": iterationCount,
    "--yh-marquee-direction": props.reverse ? "reverse" : "normal",
    "--yh-marquee-play-state": props.play && !isHidden.value && !isLoopPaused.value ? "running" : "paused",
    "--yh-marquee-clone-count": cloneCount.value,
    "animation-delay": `${props.delay}s`
  };
});
const overlayStyle = computed(() => {
  const color = props.gradientColor;
  const width = typeof props.gradientWidth === "number" ? `${props.gradientWidth}px` : props.gradientWidth;
  return {
    "--yh-marquee-gradient-color": color,
    "--yh-marquee-gradient-width": width
  };
});
const calculateClones = async () => {
  await nextTick();
  const container = containerRef.value;
  const content = contentRef.value;
  if (!container || !content) return;
  const containerSize = props.direction === "horizontal" ? container.offsetWidth : container.offsetHeight;
  const contentSize = props.direction === "horizontal" ? content.scrollWidth : content.scrollHeight;
  if (contentSize === 0) return;
  if (props.autoFill) {
    const needed = Math.ceil(containerSize / contentSize);
    cloneCount.value = Math.max(1, needed);
  } else {
    cloneCount.value = 1;
  }
};
const handleAnimationIteration = () => {
  emit("cycleComplete");
  if (props.loopDelay > 0) {
    isLoopPaused.value = true;
    if (delayTimer) clearTimeout(delayTimer);
    delayTimer = setTimeout(() => {
      isLoopPaused.value = false;
      delayTimer = null;
    }, props.loopDelay * 1e3);
  }
};
watch([() => props.autoFill, () => props.direction, () => props.gap], calculateClones);
onMounted(() => {
  calculateClones();
  isReady.value = true;
  if (props.pauseOnHidden && typeof IntersectionObserver !== "undefined" && containerRef.value) {
    const observer = new IntersectionObserver(
      (entries) => {
        isHidden.value = !entries[0].isIntersecting;
      },
      { threshold: 0 }
    );
    observer.observe(containerRef.value);
    onUnmounted(() => observer.disconnect());
  }
});
onUnmounted(() => {
  if (delayTimer) {
    clearTimeout(delayTimer);
    delayTimer = null;
  }
});
defineExpose({
  /** 手动重新计算克隆数量（通常在动态改变内容高度/宽度时调用） */
  calculateClones,
  /** 容器 DOM 引用 */
  containerRef,
  /** 内容 DOM 引用 */
  contentRef
});
</script>

<template>
  <div
    ref="containerRef"
    :class="[ns.b(), ns.m(direction), {
  [ns.m('pause-on-hover')]: pauseOnHover,
  [ns.m('pause-on-click')]: pauseOnClick,
  [ns.m('gradient')]: gradient
}]"
    :style="[themeStyle, marqueeStyle, overlayStyle]"
  >
    <div :class="ns.e('content')" @animationiteration="handleAnimationIteration">
      <div ref="contentRef" :class="ns.e('item')">
        <slot />
      </div>

      <!-- 克隆内容以实现无缝滚动 -->
      <div v-for="i in cloneCount" :key="i" :class="ns.e('item')" aria-hidden="true">
        <slot />
      </div>
    </div>

    <!-- 渐变蒙层 -->
    <div v-if="gradient" :class="ns.e('overlay')" />
  </div>
</template>

<style>
@charset "UTF-8";
/**
 * YH-UI Sass Variables
 * 原具体的 CSS 变量输出规则 (:root, html.dark 等) 已移至 root.scss，以防止各组件样式编译时产生重复的全局变量 CSS 冗余。
 */
.yh-marquee {
  display: flex;
  position: relative;
  overflow: hidden;
  width: 100%;
  --yh-marquee-gap: 0px;
  --yh-marquee-duration: 20s;
  --yh-marquee-iteration-count: infinite;
  --yh-marquee-direction: normal;
  --yh-marquee-play-state: running;
  --yh-marquee-gradient-color: var(--yh-bg-color);
  --yh-marquee-gradient-width: 40px;
}
.yh-marquee--horizontal {
  flex-direction: row;
}
.yh-marquee--horizontal .yh-marquee__content {
  flex-direction: row;
  min-width: 100%;
  animation: marquee-horizontal var(--yh-marquee-duration) linear var(--yh-marquee-iteration-count);
  animation-direction: var(--yh-marquee-direction);
  animation-play-state: var(--yh-marquee-play-state);
}
.yh-marquee--horizontal .yh-marquee__item {
  flex-direction: row;
  gap: var(--yh-marquee-gap);
  margin-right: var(--yh-marquee-gap);
}

.yh-marquee--vertical {
  flex-direction: column;
  height: 100%;
  min-height: 100px;
}
.yh-marquee--vertical .yh-marquee__content {
  flex-direction: column;
  height: max-content;
  min-height: 100%;
  animation: marquee-vertical var(--yh-marquee-duration) linear var(--yh-marquee-iteration-count);
  animation-direction: var(--yh-marquee-direction);
  animation-play-state: var(--yh-marquee-play-state);
}
.yh-marquee--vertical .yh-marquee__item {
  flex-direction: column;
  gap: var(--yh-marquee-gap);
  margin-bottom: var(--yh-marquee-gap);
}

.yh-marquee__content {
  display: flex;
  flex-shrink: 0;
}

.yh-marquee__item {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-shrink: 0;
}

.yh-marquee--pause-on-hover:hover .yh-marquee__content {
  animation-play-state: paused !important;
}

.yh-marquee--pause-on-click:active .yh-marquee__content {
  animation-play-state: paused !important;
}

.yh-marquee__overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  pointer-events: none;
  z-index: 1;
}
.yh-marquee--horizontal .yh-marquee__overlay {
  background: linear-gradient(to right, var(--yh-marquee-gradient-color) 0%, transparent var(--yh-marquee-gradient-width), transparent calc(100% - var(--yh-marquee-gradient-width)), var(--yh-marquee-gradient-color) 100%);
}
.yh-marquee--vertical .yh-marquee__overlay {
  background: linear-gradient(to bottom, var(--yh-marquee-gradient-color) 0%, transparent var(--yh-marquee-gradient-width), transparent calc(100% - var(--yh-marquee-gradient-width)), var(--yh-marquee-gradient-color) 100%);
}

@keyframes marquee-horizontal {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(calc(-100% / (var(--yh-marquee-clone-count) + 1)));
  }
}
@keyframes marquee-vertical {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(calc(-100% / (var(--yh-marquee-clone-count) + 1)));
  }
}
</style>
