import { defineComponent, ref, watch, onMounted, computed } from "vue";

const props = {
  startVal: {
    type: Number,
    default: 0
  },
  endVal: {
    type: Number,
    default: 2021
  },
  duration: {
    type: Number,
    default: 3000
  },
  autoplay: {
    type: Boolean,
    default: true
  },
  decimals: {
    type: Number,
    default: 0
  },
  separator: {
    type: String,
    default: ","
  },
  prefix: {
    type: String,
    default: ""
  },
  suffix: {
    type: String,
    default: ""
  },
  fontSize: {
    type: String,
    default: "16px"
  },
  color: {
    type: String,
    default: ""
  }
};

export const ReNormalCountTo = defineComponent({
  name: "ReNormalCountTo",
  props,
  emits: ["mounted", "callback"],
  setup(props, { emit }) {
    const state = ref(props.startVal);
    const startTime = ref(0);
    const rafId = ref(0);

    const formatNumber = computed(() => {
      const val = state.value.toFixed(props.decimals);
      const parts = val.split(".");
      parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, props.separator);
      return props.prefix + parts.join(".") + props.suffix;
    });

    function count(timestamp: number) {
      if (!startTime.value) startTime.value = timestamp;
      const progress = timestamp - startTime.value;
      const remaining = props.duration - progress;

      if (remaining < 0) {
        state.value = props.endVal;
        emit("callback");
        return;
      }

      const rate = progress / props.duration;
      state.value = props.startVal + (props.endVal - props.startVal) * rate;
      rafId.value = requestAnimationFrame(count);
    }

    function start() {
      startTime.value = 0;
      rafId.value = requestAnimationFrame(count);
    }

    onMounted(() => {
      if (props.autoplay) {
        start();
      }
      emit("mounted");
    });

    watch(
      () => props.endVal,
      () => {
        if (props.autoplay) {
          start();
        }
      }
    );

    return () => (
      <span
        style={{
          fontSize: props.fontSize,
          color: props.color
        }}
      >
        {formatNumber.value}
      </span>
    );
  }
});

export default ReNormalCountTo;
