import _ from 'lodash'
import moment from 'moment'
let zTool = {
	/**
	 * @description 表单验证
	 * @param formRef 组件
	 * @param callBack 回调方法
	 */
	validate(formRef, callBack) {
		formRef.validate(valid => {
			if (!!valid && callBack) {
				callBack()
			}
		});
	},
	/**
	 * @description 表单验证
	 * @param formRefs 组件
	 * @param callBack 回调方法
	 */
	validateForms(formRefs, callBack) {
		let promises = [];
		for (let i = 0; i < formRefs.length; i++) {
			promises.push(new Promise((resolve) => { formRefs[i].validate(valid => { if (valid) { resolve(); } }) }));
		}
		Promise.all(promises).then(() => { if (callBack) { callBack() } }).catch(()=>{})
	},
	/**
	 * @description 表单字段验证
	 * @param formRef 组件
	 * @param callBack 回调方法
	 * @param fields 字段
	 */
	validateFields(formRef, callBack, ...fields) {
		for (let i = 0; i < fields.length; i++) {
			formRef.validateField(fields[i],valid => {
				if (!!valid && callBack && ( i +1 ) === fields.length) {
					callBack()
				}
			})
		}
	},
	/**
	 * @description 启用禁用
	 * @param ref 组件
	 * @param apiObj API对象
	 * @param row 行数据
	 * @param index 行号
	 * @param props 属性数组
	 */
	switch(ref, apiObj, row, index, props = ['id']) {
		if (index === -1) {
			return;
		}
		let params = { isActived: row.isActived };
		for (let prop of props) {
			params[`${prop}`] = row[`${prop}`]
		}
		this.loading(ref);
		apiObj.put(params).then(() => {
			ref.$message.success(row.isActived === 0 ? '禁用成功' : '启用成功');
			ref.searchFun();
		}).catch(()=>{}).finally(() => {
			this.loadingHidden(ref);
		});
	},
	/**
	 * @description 保存
	 * @param ref 组件
	 * @param apiObj API对象
	 * @param params 保存参数
	 * @param msg 提示信息
	 * @param callBack 回调方法
	 * @param isMessage 是否提示
	 * @param isCloseDialog 是否关闭弹窗
	 * @param isSearchFun 是否刷新页面
	 */
	save(ref, apiObj, params, msg = '操作成功', callBack, isMessage = true, isCloseDialog = true, isSearchFun = true) {
		this.loading(ref);
		apiObj.post(params).then(() => {
			if (isMessage) {
				ref.$message.success(msg);
			}
			if (isCloseDialog) {
				ref.closeDialog();
			}
			if (isSearchFun) {
				ref.searchFun();
			}
			if (callBack) {
				callBack();
			}
		}).catch(()=>{}).finally(() => {
			this.loadingHidden(ref);
		})
	},
	/**
	 * @description 响应赋值
	 * @param ref 组件f
	 * @param apiObj API对象
	 * @param name 赋值的属性
	 * @param params 参数
	 * @param callBack 回调方法
	 */
	resSetValue(ref, apiObj, name, params = {}, callBack, isLoad = false) {
		let obj = getObjByStrName(ref, name)
		let attr = getAttrByStrName(ref, name)
		if (obj[`${attr}`] === undefined) {
			return
		}
		if (isLoad) {
			this.loading(ref);
		}
		apiObj.get(params).then((res) => {
			obj[`${attr}`] = res;
			if (callBack) {
				callBack(res)
			}
		}).catch(()=>{}).finally(() => {
			if (isLoad) {
				this.loadingHidden(ref);
			}
		})
	},

	/**
	 * @description Number格式化
	 * @param number Number
	 * @param afterPointDigit 小数点后位数
	 * @param useThousandSign 是否使用千位符
	 * @param noExistDisplay 数字不存在时的展示值
	 * @param zeroDisplayNegative 数字0展示为负数
	 * @return number 格式化后的时数字/字符串
	 */
	numberFormat(number, afterPointDigit, useThousandSign = true, noExistDisplay, zeroDisplayNegative) {
		if (number !== 0 && !number) {
			if (noExistDisplay) {
				return noExistDisplay
			} else {
				return number
			}
		}
		number = Number(number)
		if (afterPointDigit === 0 || afterPointDigit) {
			number = number.toFixed(afterPointDigit)
		}
		if (useThousandSign) {
			number = number.toString()
			if (number.indexOf('.') >= 0) {
				number = number.replace(/(\d{1,3})(?=(\d{3})+(?:\.))/g, '$1,')
			} else {
				number = number.replace(/(\d{1,3})(?=(\d{3})+(?:$))/g, '$1,')
			}
		}
		if (zeroDisplayNegative && Number(number) == 0) {
			number = '-' + number
		}
		return number
	},
	/**
	 * @description 改变输入值
	 * @param ref 组件
	 * @param name 属性名称
	 * @param type change类型 具体类型如下
	 * STR_1允许输入任意字符; STR_2允许输入数字字母下划线和汉字; STR_3允许输入数字字母下划线;
	 * NUM_1允许输入数字; NUM_2允许输入数字(去除数字前方的0); NUM_3允许输入数字和小数点(去除数字前方多余的0); NUM_4允许输入数字(去除数字前方多余的0);NUM_5允许输入负数,数字和小数点(去除数字前方多余的0);
	 * NULL_XX 不允许非法字符
	 * @param max1 最大输入长度 NUM类型时为小数点前数字位数
	 * @param max2 小数点后数字位数
	 */
	changeInput(ref, name, type, max1, max2) {
		let obj = getObjByStrName(ref, name)
		let attr = getAttrByStrName(ref, name)
		if (obj[`${attr}`] === undefined) {
			return
		}
		if (obj[`${attr}`] === null) {
			return
		}
		obj[`${attr}`] = obj[`${attr}`].toString().trim();
		if (type === 'STR_1') {
			obj[`${attr}`] = obj[`${attr}`].substring(0, max1)
		} else if (type === 'STR_2') {
			obj[`${attr}`] = obj[`${attr}`].replace(/[^\w_/.*\u4e00-\u9fa5]/g, '').substring(0, max1)
		} else if (type === 'STR_3') {
			obj[`${attr}`] = obj[`${attr}`].replace(/[^\w_]/g, '').substring(0, max1)
		} else if (type === 'NUM_1') {
			obj[`${attr}`] = obj[`${attr}`].replace(/[^\d]/g, '').substring(0, max1)
		} else if (type === 'NUM_2') {
			obj[`${attr}`] = obj[`${attr}`]
				.replace(/[^\d]/g, '')
				.replace(/\b(0+)/g, '')
				.substring(0, max1)
		} else if (type === 'NUM_3') {
			let num = obj[`${attr}`]
			num = num
				.replace(/[^\d.]/g, '')
				.replace('.', '$#$')
				.replace(/\./g, '')
				.replace('$#$', '.')
				.replace(/^\./g, '')
			if (num.indexOf('.') === -1) {
				num = num == 0 ? num.replace(/\b(0+)/g, '0') : num.replace(/\b(0+)/g, '').substring(0, max1)
			} else {
				num = num.substring(0, num.indexOf('.')).substring(0, max1) + '.' + num.substring(num.indexOf('.') + 1).substring(0, max2)
			}
			obj[`${attr}`] = num
		} else if (type === 'NUM_4') {
			let num = obj[`${attr}`]
			obj[`${attr}`] = num == 0 ? num.replace(/[^\d]/g, '').replace(/\b(0+)/g, '0') : num.replace(/[^\d]/g, '').replace(/\b(0+)/g, '').substring(0, max1)
		} else if (type === 'NUM_5') {
			let num = obj[`${attr}`]
			num = num
				.replace(/[^\d.-]/g, '')
				.replace('.', '$#$')
				.replace(/\./g, '')
				.replace('$#$', '.')
				.replace(/^\./g, '')
				.replace(/-{2,}/g, '-')
				.replace(/(?<=-)(.*?)(-)/, '')
			if (num.indexOf('.') === -1) {
				num = num == 0 ? num.replace(/\b(0+)/g, '0') : num.replace(/\b(0+)/g, '').substring(0, max1)
			} else {
				num = num.substring(0, num.indexOf('.')).substring(0, max1) + '.' + num.substring(num.indexOf('.') + 1).substring(0, max2)
			}
			obj[`${attr}`] = num
		}  else if (type === 'NULL_XX') {
			obj[`${attr}`] = obj[`${attr}`]
				.replace(/[`~!@#$%^&*()_\-+=<>?:"{}|,./;'\\[\]·~！@#￥%……&*（）——\-+={}|《》？：“”【】、；‘’，。、]/g, '')
				.replace(/\s/g, '')
				.substring(0, max1)
		}
	},
	/**
	 * 合计
	 * @param param 合计参数
	 * @param array 自定义数组 eg: [ { prop: amount, scopeType: 1 } ]
	 * @returns
	 */
	getSummaries(param, array) {
		const { columns, data } = param
		const sums = []
		columns.forEach((column, index) => {
			if (index === 0) {
				sums[index] = '合计'
				return
			}
			array.forEach(item => {
				if (item.prop === column.property) {
					const values = data.map(item => Number(item[column.property]))
					sums[index] = values.reduce((prev, curr) => {
						const value = Number(curr)
						if (!isNaN(value)) {
							return prev + curr
						} else {
							return prev
						}
					}, 0)

					if (item.scopeType) {
						switch (item.scopeType) {
							case 3:
								return (sums[index] = this.numberFormat(sums[index], 2, true));
							case 4:
								return (sums[index] = this.numberFormat(sums[index], 2, false));
							case 5:
								return (sums[index] = this.numberFormat(sums[index], 0, false));
							case 6:
								return (sums[index] = this.numberFormat(sums[index], 4, false));
							case 7:
								return (sums[index] = this.numberFormat(sums[index], 6, false));
							case 8:
								return (sums[index] = this.numberFormat(sums[index], 3, false));
							case 9:
								return (sums[index] = this.numberFormat(sums[index], 2, true, undefined, true));
						}
					}
				}
			})
		})
		return sums
	},
	/**
	 * 加载
	 */
	loading(ref) {
		ref.loadingInstance = ref.$loading({
			fullscreen: true,
			text: '请稍后'
		})
	},
	/**
	 * 取消加载
	 */
	loadingHidden(ref) {
		if (ref.loadingInstance != null) {
			setTimeout(() => {
				ref.loadingInstance.close()
			}, 500);

		}
	},
	/**
	 * 日期转字符串
	 */
	dateToStr(date = new Date(), format = 'YYYY-MM-DD') {
		return moment(date).format(format);
	},
	/**
	 * @description 导出EXCEL
	 * @param ref 组件
	 * @param methodsName 查询方法
	 * @param params 查询参数
	 * @param name EXCEL名称
	 */
	zDownloadExcel(ref, methodsName, params, name) {
		let req = this.zDeleteObjectInvalidKey(params, true)
		methodsName.get(req)
		.then(res => {
			let url = window.URL.createObjectURL(new Blob([res], { type: 'application/vnd.ms-excel;charset=UTF-8' }))
			let link = document.createElement('a')
			link.href = url
			link.download = name
			document.body.appendChild(link)
			link.click()
			document.body.removeChild(link)
			window.URL.revokeObjectURL(url)
		})
		.catch()
		.finally(() => {
			// ref.endLoading()
		})
	},
	/**
	 * @description 删除Object对象无效key
	 * @param object1 对象
	 * @param delEmptyStr 是否删除值为''的key
	 * @return 删除后的对象
	 */
	zDeleteObjectInvalidKey(object1 = {}, delEmptyStr = false) {
		let object = _.cloneDeep(object1)
		for (let key in object) {
		if (object[key] === undefined || object[key] === null) {
			delete object[key]
		}
		if (delEmptyStr && object[key] === '') {
			delete object[key]
		}
		}
		return object
	},
	/**
	 * @description 导出模板
	 * @param name 模板名称
	 */
	zDownloadTemplate(name) {
		let a = document.createElement('a')
		a.href = '/static/'.concat(name)
		console.log(a.href);
		a.download = name
		a.click()
	},
	/**
	 * @description 导入EXCEL
	 * @param ref 组件
	 * @param methodsName 导入方法
	 * @param data 数据
	 */
	zImportExcel(ref, methodsName, data) {
		this.loading(ref);
		methodsName.post(data)
		.then(res => {
			if (res.message === 'success') {
			if (!res.errorMsg) {
				ref.$message.success('批量导入成功')
				ref.searchFun()
			} else {
				ref.$message.error(res.errorMsg, true)
			}
			}
		}).catch(()=>{}).finally(() => {
			this.loadingHidden(ref);
		})
	},

	/**
	 * @description 处理cascader
	 * @param params 参数对象
	 * @param cascaderNames cascader属性名称
	 * @return object 处理后的参数对象
	 */
	handleCascader(params = {}, ...cascaderNames) {
		let object = _.cloneDeep(params)
		for (let i = 0; i < cascaderNames.length; i++) {
			let cascaderName = cascaderNames[i]
			if (object[`${cascaderName}`] && typeof object[`${cascaderName}`] !== 'string') {
				object[`${cascaderName}`] =
					object[`${cascaderName}`].length > 0 ? object[`${cascaderName}`][object[`${cascaderName}`].length - 1] : null
			}
		}
		return object
	},
	 addWatermark(file,name) {
		return new Promise((resolve, reject) => {
		  const canvas = document.createElement('canvas');
		  const ctx = canvas.getContext('2d');
		  const image = new Image();
		  image.onload = function () {
			// 设置canvas大小为图片大小
			canvas.width = image.width;
			canvas.height = image.height;
			// 在canvas上绘制原始图片
			ctx.drawImage(image, 0, 0);
			// 添加水印文本
			ctx.font = '15px Arial';
			ctx.fillStyle = 'rgb(228,233,229)';
			const watermarkText = name; // 水印文本
			const angle = 15 * Math.PI / 180; // 将15度转换为弧度
			// 计算每个部分的高度
			const partHeight = canvas.height / 3;
			// 计算每行的宽度
			const rowWidth = canvas.width / Math.ceil(canvas.width / canvas.height);
			// 遍历每行
			for (let i = 0; i < 3; i++) {
			  // 计算水印的y坐标
			  const y = (i + 0.2) * partHeight; // 在每行的中间位置添加水印
			  // 遍历每个部分
			  for (let j = 0; j < Math.ceil(canvas.width / rowWidth); j++) {
				// 计算水印的x坐标
				const x = (j + 0.2) * rowWidth; // 在每个部分的中间位置添加水印
				// 保存当前绘图环境状态
				ctx.save();
				// 将坐标系移动到水印的位置
				ctx.translate(x, y);
				// 应用倾斜角度
				ctx.rotate(angle); // 将角度转换为弧度
				// 绘制水印文本
				ctx.fillText(watermarkText, 0, 0);
				// 恢复绘图环境到之前的状态
				ctx.restore();
			  }
			}
	
			// const watermarkCount = 3; // 水印数量
			// const horizontalSpacing = canvas.width / (watermarkCount+2 ); // 水平间距
			// const verticalSpacing = canvas.height / (watermarkCount +2); // 垂直间距
	
			// for (let i = 1; i <= watermarkCount; i++) {
			//   for (let j = 1; j <= watermarkCount; j++) {
	
			//     const x = i * horizontalSpacing;
			//     const y = j * verticalSpacing;
			//     ctx.save(); // 保存当前的绘图状态
			//     ctx.translate(x, y); // 将原点移动到水印位置
			//     ctx.rotate(angle); // 固定倾斜15度
			//     ctx.fillText(watermarkText, 0, 0); // 绘制倾斜的水印文本
			//     ctx.restore(); // 恢复之前保存的绘图状态，避免影响后续绘图
			//   }
			// }
	
			// const watermarkText = '社保信息'; // 水印文本
			// const watermarkCountX = Math.ceil(canvas.width / 150); // 根据图片宽度计算水印横向数量
			// const watermarkCountY = Math.ceil(canvas.height / 150); // 根据图片高度计算水印纵向数量
			// const angle = 10 * Math.PI / 180; // 将5度转换为弧度
	
			// for (let i = 1; i <= watermarkCountX; i++) {
			//   for (let j = 1; j <= watermarkCountY; j++) {
			//     const x = i * (canvas.width / (watermarkCountX + 1));
			//     const y = j * (canvas.height / (watermarkCountY + 1));
			//     ctx.save(); // 保存当前的绘图状态
			//     ctx.translate(x, y); // 将原点移动到水印位置
			//     ctx.rotate(angle); // 固定倾斜5度
			//     ctx.fillText(watermarkText, 0, 0); // 绘制倾斜的水印文本
			//     ctx.restore(); // 恢复之前保存的绘图状态，避免影响后续绘图
			//   }
			// }
	
			// 将canvas转换为Blob对象
			canvas.toBlob(blob => {
			  resolve(new File([blob], file.name, { type: 'image/jpg' }));
			}, 'image/jpg');
		  };
	
		  image.onerror = function () {
			reject(new Error('Failed to load image'));
		  };
	
		  // 使用异步方法加载图片
		  image.src = URL.createObjectURL(file);
		});
	  },
	/**
	 * @description 处理多选cascader
	 * @param params 参数对象
	 * @param cascaderNames cascader属性名称
	 * @return object 处理后的参数对象
	 */
	handleMultipleCascader(params = {}, ...cascaderNames) {
		let object = _.cloneDeep(params)
		for (let i = 0; i < cascaderNames.length; i++) {
			let cascaderName = cascaderNames[i]
			if (object[`${cascaderName}`]) {
				for (let i = 0; i < object[`${cascaderName}`].length; i++) {
					if (typeof object[`${cascaderName}`][i] !== 'string') {
						object[`${cascaderName}`][i] =
							object[`${cascaderName}`][i].length > 0 ? object[`${cascaderName}`][i][object[`${cascaderName}`][i].length - 1] : null
					}
				}
			}
		}
		return object
	}
};

/**
 * @description 双子函数 解析名称字符串 与getAttrByStrName共同使用 对象[`${属性}`] 达到给组件属性赋值作用
 * @param ref 组件
 * @param name 组件属性名
 */
function getObjByStrName(ref, name) {
	let obj = ref
	let array = name.split(/\.|\[/)
	for (let i = 0; i < array.length - 1; i++) {
		obj = array[i].endsWith(']') ? obj[parseInt(array[i].substring(0, array[i].length - 1))] : obj[`${array[i]}`]
	}
	return obj
}

/**
 * @description 双子函数 解析名称字符串 与getObjByStrName共同使用 对象[`${属性}`] 达到给组件属性赋值作用
 * @param ref 组件
 * @param name 组件属性名
 */
function getAttrByStrName(ref, name) {
	let array = name.split(/\.|\[/)
	return array[array.length - 1]
}

export default zTool

