import CryptoJS from 'crypto-js'
import JSEncrypt from 'jsencrypt'
import config from "@/config"

const tools = {
	data: {
		set(cacheKey: string, data: any, expireIn: number = 0) {
			let cacheValue = {
				content: data,
				expireIn: expireIn === 0 ? 0 : new Date().getTime() + expireIn * 1000
			}
			return localStorage.setItem(cacheKey, tools.base64.encrypt(JSON.stringify(cacheValue)))
		},
		get(cacheKey: string) {
			try {
				const data = localStorage.getItem(cacheKey);
				if (!data) return null
				const cacheValue = JSON.parse(tools.base64.decrypt(data))
				if (cacheValue) {
					let nowTime = new Date().getTime()
					if (nowTime > cacheValue.expireIn && cacheValue.expireIn !== 0) {
						localStorage.removeItem(cacheKey)
						return null;
					}
					return cacheValue.content
				}
				return null
			} catch (err) {
				return null
			}
		},
		remove(cacheKey: string) {
			return localStorage.removeItem(cacheKey)
		},
		clear() {
			return localStorage.clear()
		}
	},
	base64: {
		encrypt(data: string) {
			return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(data))
		},
		decrypt(cipher: string) {
			return CryptoJS.enc.Base64.parse(cipher).toString(CryptoJS.enc.Utf8)
		}
	},
	go: async function (fn: Function) {
		try {
			let res = await fn
			return [res, null]
		} catch (err) {
			return [null, err]
		}
	},
	md5: function (data: string) {
		return CryptoJS.MD5(data).toString()
	},
	aes: {
		encrypt(message: string, secretKey: string): string {
			return CryptoJS.AES.encrypt(message, secretKey).toString()
		},
		decrypt(ciphertext: string, secretKey: string) {
			CryptoJS.AES.decrypt(ciphertext, secretKey).toString(CryptoJS.enc.Utf8)
		}
	},
	rsa: {
		encrypt(message: string): string {
			const encryptor = new JSEncrypt()
			encryptor.setPublicKey(config.RSA_PUBLIC_KEY)
			const encrypted = encryptor.encrypt(message)
			if (!encrypted) {
				throw new Error('RSA encrypt failed')
			}
			return encrypted;
		},
		decrypt(cipherText: string, privateKey: string): string {
			const decryptor = new JSEncrypt()
			decryptor.setPrivateKey(privateKey)
			const decrypted = decryptor.decrypt(cipherText)
			if (!decrypted) {
				throw new Error('RSA decrypt failed')
			}
			return decrypted
		}
	},
	screen: function (element) {
		var isFull = !!(document.webkitIsFullScreen || document.mozFullScreen || document.msFullscreenElement || document.fullscreenElement);
		if (isFull) {
			if (document.exitFullscreen) {
				document.exitFullscreen();
			} else if (document.msExitFullscreen) {
				document.msExitFullscreen();
			} else if (document.mozCancelFullScreen) {
				document.mozCancelFullScreen();
			} else if (document.webkitExitFullscreen) {
				document.webkitExitFullscreen();
			}
		} else {
			if (element.requestFullscreen) {
				element.requestFullscreen();
			} else if (element.msRequestFullscreen) {
				element.msRequestFullscreen();
			} else if (element.mozRequestFullScreen) {
				element.mozRequestFullScreen();
			} else if (element.webkitRequestFullscreen) {
				element.webkitRequestFullscreen();
			}
		}
	},
	/* 复制对象 */
	objCopy: function (obj) {
		return JSON.parse(JSON.stringify(obj || []));
	},
	/* 日期格式化 */
	dateFormat: function (date, fmt = 'yyyy-MM-dd hh:mm:ss') {
		date = new Date(date)
		var o = {
			"M+": date.getMonth() + 1,                 //月份
			"d+": date.getDate(),                    //日
			"h+": date.getHours(),                   //小时
			"m+": date.getMinutes(),                 //分
			"s+": date.getSeconds(),                 //秒
			"q+": Math.floor((date.getMonth() + 3) / 3), //季度
			"S": date.getMilliseconds()             //毫秒
		};
		if (/(y+)/.test(fmt)) {
			fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
		}
		for (var k in o) {
			if (new RegExp("(" + k + ")").test(fmt)) {
				fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
			}
		}
		return fmt;
	},
	makeTreeData: function (data, parent_id = 0, key = "id", parent = "parent_id") {
		const arr = [];
		for (let item of data) {
			if (item[parent] == parent_id) {
				// 数据格式处理
				const tmp = item;
				const children = this.makeTreeData(data, item[key], key, parent);
				if (children.length > 0) {
					tmp['children'] = children
				}
				arr.push(tmp)
			}
		}
		return arr
	},
	randomUUIDString: function (len = 16) {
		return crypto.randomUUID().replace(/-/g, '').slice(0, len)
	},
	getBrowser(userAgent: string) {
		// 检测浏览器类型和版本
		if (/Opera|OPR/.test(userAgent)) {
			return 'Opera';
		} else if (/Edg/.test(userAgent)) {
			return 'Edge';
		} else if (/Chrome/.test(userAgent)) {
			return 'Chrome';
		} else if (/Safari/.test(userAgent)) {
			return 'Safari';
		} else if (/Firefox/.test(userAgent)) {
			return 'Firefox';
		} else if (/MSIE|Trident/.test(userAgent)) {
			return 'IE';
		} else {
			return '未知'
		}
	},
	// 数组0 - index
	array: {
		// 交换
		swap(arr: Array<any>, index1: number, index2: number) {
			arr[index1] = arr.splice(index2, 1, arr[index1])[0];
			return arr;
		},
		zIndexUp(arr, index) {
			if (index !== 0) {
				this.swap(arr, index, index - 1);
			}
		},
		zIndexDown(arr, index) {
			if (index + 1 < arr.length) {
				this.swap(arr, index, index + 1);
			}
		},
		zIndexTop(arr, index) {
			if (index > 0) {
				const moveNum = index - 0;
				for (let i = 0; i < moveNum; i++) {
					this.swap(arr, index, index - 1);
					index--;
				}
			}
		},
		zIndexBottom(arr, index) {
			if (index + 1 < arr.length) {
				const moveNum = arr.length - 1 - index;
				for (let i = 0; i < moveNum; i++) {
					this.swap(arr, index, index + 1);
					index++;
				}
			}
		},
		// index1 >>> index2
		zIndexTo(arr, index1, index2) {
			if (index1 === index2) return;
			if (index1 < index2) {
				const moveNum = index2 - 1 - index1;
				for (let i = 0; i < moveNum; i++) {
					this.swap(arr, index1, index1 + 1);
					index1++;
				}
			} else {
				const moveNum = index1 - index2;
				for (let i = 0; i < moveNum; i++) {
					this.swap(arr, index1, index1 - 1);
					index1--;
				}
			}
		}
	},
	// 深度合并数据
	deepMerge: (...objects: any[]) => {
		const result: any = {}
		for (const obj of objects) {
			tools.mergeObject(result, obj)
		}
		return result
	},
	mergeObject: (target: any, source: any) => {
		if (!source || typeof source !== 'object') return
		for (const key in source) {
			const value = source[key]
			if (value && typeof value === 'object' && !Array.isArray(value)) {
				if (!target[key] || typeof target[key] !== 'object') {
					target[key] = {}
				}
				tools.mergeObject(target[key], value)
			} else {
				target[key] = value
			}
		}
	}
}
export default tools
