/**
 * @description 防抖
 * @param {Function} func 需要包装的函数
 * @param {string} wait 等待执行时间
 * @param {boolean} immediate 是否是立即执行 默认不立即执行
 * @returns {Function} 返回包装后的函数
 */
export function debounce(func, wait, immediate = true) {
	let timeout, result

	return function() {
		const context = this
		const args = arguments
		if (timeout) clearTimeout(timeout)
		if (immediate) {
			const callNow = !timeout
			timeout = setTimeout(function() {
				timeout = null
			}, wait)
			if (callNow) result = func.apply(context, args)
		} else {
			timeout = setTimeout(function() {
				func.apply(context, args)
			}, wait)
		}
		return result
	}
}


/**
 * @description 节流
 * @param {Function} func 需要包装的函数
 * @param {string} wait 间隔时间
 * @returns {Function} 返回包装后的函数
 */
export function throttle(func, wait) {
	let timeout
	return function() {
		const context = this
		const args = arguments
		if (!timeout) {
			timeout = setTimeout(function() {
				timeout = null
				func.apply(context, args)
			}, wait)
		}
	}
}


/**
 * @description 深度克隆
 * @param {object} obj 克隆目标
 * @returns {object} 返回目标对象深度克隆后的结果
 */
export function deepClone(obj, cache = new WeakMap()) {
	if (typeof obj !== 'object') return obj // 普通类型，直接返回
	if (obj === null) return obj
	if (cache.get(obj)) return cache.get(obj) // 防止循环引用，程序进入死循环
	if (obj instanceof Date) return new Date(obj)
	if (obj instanceof RegExp) return new RegExp(obj)

	// 找到所属原型上的constructor，所属原型上的constructor指向当前对象的构造函数
	let cloneObj = new obj.constructor()
	cache.set(obj, cloneObj) // 缓存拷贝的对象，用于处理循环引用的情况
	for (let key in obj) {
		if (obj.hasOwnProperty(key)) {
			cloneObj[key] = deepClone(obj[key], cache) // 递归拷贝
		}
	}
	return cloneObj
}


/** 
 * @description 时间日期格式化
 * @param {dateTime} date 标准时间格式 -> new Date()
 * @param {string} format 时间格式化的格式 'yyyy-MM-dd hh:mm:ss'
 * @returns {string} 格式化后的时间  '2017-01-01 01:00:00'
 */
export function dateFormat(date = new Date(), format = 'yyyy-MM-dd hh:mm:ss') {
	var o = {
		'M+': date.getMonth() + 1, // month
		'd+': date.getDate(), // day
		'h+': date.getHours(), // hour
		'm+': date.getMinutes(), // minute
		's+': date.getSeconds(), // second
		'q+': Math.floor((date.getMonth() + 3) / 3), // quarter
		S: date.getMilliseconds(), // millisecond
	}
	if (/(y+)/.test(format)) {
		format = format.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
	}
	for (var k in o) {
		if (new RegExp('(' + k + ')').test(format)) {
			format = format.replace(RegExp.$1, RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k])
				.length))
		}
	}
	return format
}


/**
 * @description 倒计时
 * @param diff 倒计时时间(s)
 * @param loadTime 运行时的当前时间(s)
 * @param item 倒计时对象 默认：{ speed: 1000 }
 * @param callback 回调
 */
export function countDown(diff, loadTime, item, callback) {
	function round($diff) {
		let dd = parseInt($diff / 1000 / 60 / 60 / 24, 10) // 计算剩余的天数
		let hh = parseInt(($diff / 1000 / 60 / 60) % 24, 10) // 计算剩余的小时数
		let mm = parseInt(($diff / 1000 / 60) % 60, 10) // 计算剩余的分钟数
		let ss = parseInt(($diff / 1000) % 60, 10) // 计算剩余的秒数

		function checkTime(_a) {
			let a = _a
			if (a < 10) {
				a = '0' + a
			}
			return a.toString()
		}

		item.conttainer = {
			ddhh: checkTime(dd * 24 + hh),
			dd: checkTime(dd),
			hh: checkTime(hh),
			mm: checkTime(mm),
			ss: checkTime(ss)
		}

		if (
			item.conttainer.dd > 0 ||
			item.conttainer.hh > 0 ||
			item.conttainer.mm > 0 ||
			item.conttainer.ss > 0
		) {
			item.t = setTimeout(function() {
				round($diff - (item.speed || 1000))
			}, item.speed || 1000)
		}
		// 回调
		callback && callback(item)
	}
	round(diff - loadTime)
}


/* 对象循环赋值 */
export function objAssign(target = {}, source = {}) {
	for (let key in target) {
		if (source.hasOwnProperty(key)) {
			target[key] = source[key]
		}
	}
}

/* 数组去重 */
export function arrayUnique(arr) {
	if (!Array.isArray(arr)) {
		console.log('type error!')
		return
	}
	return Array.from(new Set(arr))
}
