<template>
	<view class="u-count-down">
		<slot>
			<text class="u-count-down__text" :style="customStyle">{{ formattedTime }}</text>
		</slot>
	</view>
</template>

<script>
import { isSameSecond, parseFormat, parseTimeData } from "./utils";
/**
 * u-count-down 倒计时
 * @description 该组件一般使用于某个活动的截止时间上，通过数字的变化，给用户明确的时间感受，提示用户进行某一个行为操作。
 * @tutorial https://uviewui.com/components/countDown.html
 * @property {String | Number}	timestamp		倒计时时长，单位ms （默认 0 ）
 * @property {String}			format		时间格式，DD-日，HH-时，mm-分，ss-秒，SSS-毫秒  （默认 'HH:mm:ss' ）
 * @property {Boolean}			autoStart	是否自动开始倒计时 （默认 true ）
 * @event {Function} end 倒计时结束时触发
 * @event {Function} change 倒计时变化时触发
 * @event {Function} start	开始倒计时
 * @event {Function} pause	暂停倒计时
 * @event {Function} reset	重设倒计时，若 auto-start 为 true，重设后会自动开始倒计时
 * @example <u-count-down :timestamp="timestamp"></u-count-down>
 */
export default {
	name: "u-count-down",  
	emits: ["change", "end", "finish"],
	props: {
		// 倒计时时长，单位ms
		timestamp: {
			type: [String, Number],
			default: 0
		},
		// 时间格式，DD-日，HH-时，mm-分，ss-秒，SSS-毫秒
		format: {
			type: String,
			default: "DD:HH:mm:ss"
		},
		// 是否自动开始倒计时
		autoStart: {
			type: Boolean,
			default: true
		},
		customStyle: {
			type: [String, Object],
			default: ""
		}
	},
	data() {
		return {
			timer: null,
			// 各单位(天，时，分等)剩余时间
			timeData: parseTimeData(0),
			// 格式化后的时间，如"03:23:21"
			formattedTime: "0",
			// 倒计时是否正在进行中
			runing: false,
			endTime: 0, // 结束的毫秒时间戳
			remainTime: 0 // 剩余的毫秒时间
		};
	},
	watch: {
		timestamp(n) {
			this.reset();
		},
		format(newVal, oldVal) {
			this.pause();
			this.start();
		}
	},
	mounted() {
		this.init();
	},
	methods: {
		init() {
			this.reset();
		},
		// 开始倒计时
		start() {
			if (this.runing) return;
			// 标识为进行中
			this.runing = true;
			// 结束时间戳 = 此刻时间戳 + 剩余的时间
			this.endTime = Date.now() + this.remainTime;
			this.toTick();
		},
		// 根据是否展示毫秒，执行不同操作函数
		toTick() {
			if (this.format.indexOf("SSS") > -1) {
				this.microTick();
			} else {
				this.macroTick();
			}
		},
		macroTick() {
			this.clearTimeout();
			// 每隔一定时间，更新一遍定时器的值
			// 同时此定时器的作用也能带来毫秒级的更新
			this.timer = setTimeout(() => {
				// 获取剩余时间
				const remain = this.getRemainTime();
				// 重设剩余时间
				if (!isSameSecond(remain, this.remainTime) || remain === 0) {
					this.setRemainTime(remain);
				}
				// 如果剩余时间不为0，则继续检查更新倒计时
				if (this.remainTime !== 0) {
					this.macroTick();
				}
			}, 30);
		},
		microTick() {
			this.clearTimeout();
			this.timer = setTimeout(() => {
				this.setRemainTime(this.getRemainTime());
				if (this.remainTime !== 0) {
					this.microTick();
				}
			}, 30);
		},
		// 获取剩余的时间
		getRemainTime() {
			// 取最大值，防止出现小于0的剩余时间值
			return Math.max(this.endTime - Date.now(), 0);
		},
		// 设置剩余的时间
		setRemainTime(remain) {
			this.remainTime = remain;
			// 根据剩余的毫秒时间，得出该有天，小时，分钟等的值，返回一个对象
			const timeData = parseTimeData(remain);
			this.$emit("change", timeData);
			// 得出格式化后的时间
			this.formattedTime = parseFormat(this.format, timeData);
			// 如果时间已到，停止倒计时
			if (remain <= 0) {
				this.pause(); 
				this.$emit("end");
				this.$emit("finish");
			}
		},
		// 重置倒计时
		reset() {
			this.pause();
			this.remainTime = this.timestamp;
			this.setRemainTime(this.remainTime);
			if (this.autoStart) {
				this.start();
			}
		},
		// 暂停倒计时
		pause() {
			this.runing = false;
			this.clearTimeout();
		},
		// 清空定时器
		clearTimeout() {
			clearTimeout(this.timer);
			this.timer = null;
		}
	},
	// #ifndef VUE3
	beforeDestroy() {
		this.clearTimeout();
	},
	// #endif
	
	// #ifdef VUE3
	beforeUnmount() {
		this.clearTimeout();
	},
	// #endif
};
</script>

<style lang="scss"></style>
