<template>
  <VerticalScrollText 
    v-if="type === 'scroller'" 
    :numberString="finalString"
    :animDuration="duration"
    v-bind="props" 
  />
  <Text v-else v-bind="props" :text="finalString" />
</template>

<script setup lang="ts">
import Text, { type TextProps } from '@/components/basic/Text.vue';
import VerticalScrollText from '@/components/typography/VerticalScrollText.vue';
import { FormatUtils } from '@imengyu/imengyu-utils';
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';

export interface CountToProps extends TextProps {
  /**
   * 开始值
   * @default 0
   */
  startValue?: number;
  /**
   * 结束值
   */
  endValue: number;
  /**
   * 持续时间
   * @default 3000
   */
  duration?: number;
  /**
   * 是否将数字转换为千分符
   * @default false
   */
  thousand?: boolean;
  /**
   * 数字如果不足该位数，则在前面补0
   */
  numberCount?: number,
  /**
   * 保留小数位数
   * @default 0
   */
  decimalCount?: number,
  /**
   * 效果类型。默认：text
   * * text 普通文字切换效果
   * * scroller 文字上下滚动效果
   */
  type?: 'text'|'scroller';
}

export interface CountToInstance {
  restart: () => void;
}

const props = withDefaults(defineProps<CountToProps>(), {
  startValue: 0,
  endValue: 0,
  duration: 3000,
  thousand: false,
  numberCount: 0,
  decimalCount: 0,
  type: 'text',
});

const value = ref(0);
const interval = ref(0);
const speed = computed(() => 
  Math.max(1, Math.floor(Math.abs(props.startValue - props.endValue) / (props.duration / 50)))
);

function startAnim() {
  if (interval.value > 0)
    clearInterval(interval.value);
  if (props.startValue < props.endValue) {
    //+
    interval.value = setInterval(() => {   
      if (value.value >= props.endValue) {
        clearInterval(interval.value);
        interval.value = 0;
        value.value = props.endValue;
      }
      else
        value.value = value.value + speed.value;
    }, 50) as unknown as number;
  } else {
    //-
    interval.value = setInterval(() => {
        if (value.value <= props.endValue) {
          clearInterval(interval.value);
          interval.value = 0;
          value.value = props.endValue;
        }
        else
          value.value = value.value - speed.value;
    }, 50) as unknown as number;
  }
}

const finalString = computed(() => {
  let valueString = props.decimalCount > 0 ? value.value.toFixed(props.decimalCount) : value.value.toString();
  if (valueString.length < props.numberCount)
    valueString = FormatUtils.formatNumberWithZero(
      Math.floor(value.value), 
      props.numberCount
    ) + (valueString.split('.')[1] ?? '');
  
    //转为文字
  return (props.thousand ? FormatUtils.formatNumberWithComma(valueString) : valueString);
})

function loadAnim() {
  if (props.type === 'text') {
    value.value = props.startValue;
    startAnim();
  } else {
    value.value = props.endValue;
  }
}

watch(() => [ props.startValue, props.endValue, props.type ], () => {
  loadAnim();
});

onMounted(() => {
  loadAnim();
})
onBeforeUnmount(() => {
  if (interval.value > 0) {
    clearInterval(interval.value);
    interval.value = 0;
  }
});

defineExpose<CountToInstance>({
   restart() {
    if (props.type === 'text') {
      value.value = props.startValue;
      startAnim();
    } else {
      value.value = props.startValue;
      setTimeout(() => value.value = props.endValue, 200);
    }
  },
});

</script>