import axios from 'axios';
import html2canvas from 'html2canvas';
import JSPDF from 'jspdf';
import { formatDate } from '@/utils/formatTime';
import { ElMessage, ElMessageBox } from 'element-plus';
import { VxeUI } from 'vxe-pc-ui';
import { exportJbOrder } from '@/api/business/order';
/**
 * @description 防抖
 * @param func    功能函数(即要防抖的函数)
 * @param delay   延时时间
 * @param thisArg 功能函数内this的对象
 */
export function debounce(func: Function, delay: number, thisArg?: any) {
	let timer: number;
	return function (...args: any[]) {
		if (timer) {
			window.clearTimeout(timer);
		}
		timer = window.setTimeout(function () {
			func.apply(thisArg, args);
		}, delay);
	};
}
/**
 * @description 节流（原理同上）
 * @param func    功能函数(即要节流的函数)
 * @param delay   延时时间
 * @param thisArg 功能函数内this的对象
 */
export function throttle(func: Function, delay: number, thisArg?: any) {
	let timeStamp: number;
	return function (...args: any[]) {
		const nowTimeStamp = Date.now();
		if (!timeStamp || nowTimeStamp - timeStamp >= delay) {
			func.apply(thisArg, args);
			timeStamp = nowTimeStamp;
		}
	};
}
/**
 *  @description vite引入图片
 * @param {string} name   ../assets/images 后面的文件路径+文件名后缀
 * @returns {string} 返回处理后的文件地址
 */
export function getImageUrl(name: string) {
	return new URL(`../assets/images/${name}`, import.meta.url).href;
}
/**
 * 手机号脱敏处理
 * @param  { string} phoneNumber  手机号码
 * @returns {string} 返回处理后的手机号码
 */
export function desensitizationPhone(phoneNumber: string) {
	if (!phoneNumber) return '';
	return phoneNumber.replace(/^(.{3})(\d+)(.{4})$/, '$1****$2');
}
/**
 * 姓名脱敏处理
 * @param {string} name  姓名
 * @returns {string} 返回处理后的姓名
 */
export function desensitizationName(name: string) {
	if (!name) return '';
	const len = name.length;
	return len <= 3
		? '*' + name.substring(1, len)
		: len > 3 && len <= 6
		? '**' + name.substring(2, len)
		: len > 6
		? name.substring(0, 2) + '****' + name.substring(6, len)
		: '';
}
/**
 * @description 生成guid
 * @returns {string} 返回guid
 */
export function guid(): string {
	const S4 = (): string => {
		return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
	};
	return S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4();
}
/**
 * 根据id排除自己（树形结构选择 修改时用）
 * @param {any} arr 需要排除的数组
 * @param {string} id 当前id
 * @returns {arr} 返回排除后的数组
 */
export function excludeSelfById(arr: Array<any>, id: string) {
	if (!arr) return [];
	return arr.filter((v: any) => {
		if (v.id === id) return false;
		if (v.children && v.children.length) {
			v.children = excludeSelfById(v.children, id);
		}
		return true;
	});
}
/**
 * @description 下载文件流zip
 * @param res 文件流
 */
export function downloadZip(res: any) {
	const blob = new Blob([res.data], { type: 'application/zip' }); //设置下载的内容以及格式
	// 兼容webkit浏览器，处理webkit浏览器中href自动添加blob前缀，默认在浏览器打开而不是下载
	const URL = window.URL || window.webkitURL;
	// 这里就是创建一个a标签，等下用来模拟点击事件
	const a = document.createElement('a');
	const filename = res.headers['content-disposition'].split(';')[1].split('filename=')[1];
	// 下载链接
	a.href = URL.createObjectURL(blob);
	//解码，返回的是文件流所以我从res.header里面拿的文件名，但是是编码后的%E4巴拉巴拉的，所以拿来用的话要在前端解码
	a.download = decodeURIComponent(filename); //设置文件名
	document.body.appendChild(a);
	a.click();
	// 收尾工作，在内存中移除URL 对象
	document.body.removeChild(a);
}
/**
 * @description 下载文件流
 * @param res 文件流
 * @param filename 文件名
 */
export function downloadFileByStream(res: any, filename?: string) {
	// 创建blob对象，解析流数据
	const blob = new Blob([res.data], {
		// 设置返回的文件类型
		// type: 'application/pdf;charset=UTF-8' 表示下载文档为pdf，如果是word则设置为word，excel为excel
		type: res.data.type,
	});
	// 这里就是创建一个a标签，等下用来模拟点击事件
	const a = document.createElement('a');
	// 兼容webkit浏览器，处理webkit浏览器中href自动添加blob前缀，默认在浏览器打开而不是下载  20240401000013
	const URL = window.URL || window.webkitURL;
	// 根据解析后的blob对象创建URL 对象
	// 下载链接
	a.href = URL.createObjectURL(blob);
	if (!filename) {
		const fileNameStr = res.headers['content-disposition']?.split(';')[2]?.split('filename*=')[1];
		if (fileNameStr) {
			const index = fileNameStr.lastIndexOf("'");
			const result = fileNameStr.substring(index + 1, fileNameStr.length);
			filename = decodeURIComponent(result);
		} else {
			filename = formatDate(new Date(), 'YYYYMMDDHHmmss'); // 如果没有文件名，则默认取当前时间
		}
	}
	// 下载文件名,如果后端没有返回，可以自己写a.download = '文件.pdf'
	a.download = filename;
	document.body.appendChild(a);
	// 点击a标签，进行下载
	a.click();
	// 收尾工作，在内存中移除URL 对象
	document.body.removeChild(a);
}
/**
 * @description 根据地址下载文件
 * @param src 文件地址
 * @param filename 文件名
 */
export function downloadFileBySrc(src: string, filename: string) {
	if (!src) {
		return;
	}
	let fileName: string = filename || ''; // 文件名
	axios({
		method: 'get',
		url: src,
		responseType: 'blob',
		headers: { 'content-type': 'audio/mpeg' },
	})
		.then((res: any) => {
			let blob: Blob = new Blob([res.data], { type: res.data.type }); // 创建blob 设置blob文件类型 data 设置为后端返回的文件(例如mp3,jpeg) type:这里设置后端返回的类型 为 mp3
			let down: HTMLAnchorElement = document.createElement('a'); // 创建A标签
			let href: string = window.URL.createObjectURL(blob); // 创建下载的链接
			down.href = href; // 下载地址
			down.download = fileName; // 下载文件名
			document.body.appendChild(down);
			down.click(); // 模拟点击A标签
			document.body.removeChild(down); // 下载完成移除元素
			window.URL.revokeObjectURL(href); // 释放blob对象
		})
		.catch(function (error) {
			console.log(error);
			ElMessage.error('下载失败');
		});
}
/**
 * @description 把后端返回的文件转换为前端需要的文件数据格式
 * @param data 后端返回的文件数据
 * @return 转换后的文件数据
 */
export function transformFile(data: Array<any>[]) {
	if (!data || data.length === 0) return [];
	return data.map((v: any) => {
		// 如果转换过的数据中没有response，说明是旧数据，需要转换
		if (!v.response) {
			return {
				...v,
				name: v.fileName,
				publicity: v.publicity,
				path: v.path,
				url: import.meta.env.VITE_API_UPLOAD_URL + v.path,
				allPath: import.meta.env.VITE_API_UPLOAD_URL + v.path,
				fileName: v.fileName,
				response: {
					result: {
						fileName: v.fileName,
						path: v.path,
						type: v.type,
						id: v.additions,
					},
				},
			};
		} else {
			return v;
		}
	});
}
/**
 * @description 递归查找 callValue 对应的 enum 值
 * */
export function findItemNested(enumData: any, callValue: any, value: string, children: string) {
	return enumData.reduce((accumulator: any, current: any) => {
		if (accumulator) return accumulator;
		if (current[value] === callValue) return current;
		if (current[children]) return findItemNested(current[children], callValue, value, children);
	}, null);
}
/**
 * @description 根据枚举列表查询当需要的数据（如果指定了 label 和 value 的 key值，会自动识别格式化）
 * @param {String} callValue 当前单元格值
 * @param {Array} enumData 字典列表
 * @param {Array} fieldNames label && value && children 的 key 值
 * @param {String} type 过滤类型（目前只有 tag）
 * @returns {String}
 * */
export function filterEnum(callValue: any, enumData?: any, fieldNames?: any, type?: 'tag') {
	const value = fieldNames?.value ?? 'value';
	const label = fieldNames?.label ?? 'label';
	const children = fieldNames?.children ?? 'children';
	let filterData: { [key: string]: any } = {};
	// 判断 enumData 是否为数组
	if (Array.isArray(enumData)) filterData = findItemNested(enumData, callValue, value, children);
	// 判断是否输出的结果为 tag 类型
	if (type == 'tag') {
		return filterData?.tagType ? filterData.tagType : '';
	} else {
		return filterData ? filterData[label] : '--';
	}
}

/**
 * @description 处理 prop，当 prop 为多级嵌套时 ==> 返回最后一级 prop
 * @param {String} prop 当前 prop
 * @returns {String}
 * */
export function handleProp(prop: string) {
	const propArr = prop.split('.');
	if (propArr.length == 1) return prop;
	return propArr[propArr.length - 1];
}
/**
 * @description:  是否为数组
 */
export function isArray(val: any): val is Array<any> {
	return val && Array.isArray(val);
}
/**
 * @description 处理 ProTable 值为数组 || 无数据
 * @param {*} callValue 需要处理的值
 * @returns {String}
 * */
export function formatValue(callValue: any) {
	// 如果当前值为数组，使用 / 拼接（根据需求自定义）
	if (isArray(callValue)) return callValue.length ? callValue.join(' / ') : '';
	return callValue ?? '';
}

/**
 * @description 处理 prop 为多级嵌套的情况，返回的数据 (列如: prop: user.name)
 * @param {Object} row 当前行数据
 * @param {String} prop 当前 prop
 * @returns {*}
 * */
export function handleRowAccordingToProp(row: { [key: string]: any }, prop: string) {
	if (!prop.includes('.')) return row[prop] ?? '';
	prop.split('.').forEach((item) => (row = row[item] ?? ''));
	return row;
}
/**
 * @description  前端分页分割数组
 * @param {Object} array 当前所有数目
 * @param {String} size 需要分割多少份
 * @returns {*}
 * */
export function getNeedArr(array: any[], size: number) {
	//获取所需指定长度分割的数组;参数1为用于分割的总数组,参数2为分割数组后每个小数组的长度
	const length = array.length;
	//判断不是数组，或者size没有设置，size小于1，就返回空数组
	if (!length || !size || size < 1) {
		return [];
	}
	//核心部分
	let index = 0; //用来表示切割元素的范围start
	let resIndex = 0; //用来递增表示输出数组的下标

	//根据length和size算出输出数组的长度，并且创建它。
	let result = new Array(Math.ceil(length / size));
	//进行循环
	while (index < length) {
		//循环过程中设置result[0]和result[1]的值。该值根据array.slice切割得到。
		result[resIndex++] = array.slice(index, (index += size));
	}
	//输出新数组
	return result;
}
/**
 * @description  判断数组是否在传入的范围内
 * @param {number} num 传入的数字
 * @param {number} min 最小数
 * @param {number} max 最大数
 * @returns {*}
 * */
export function isInRange(num: number, min: number, max: number) {
	return num >= min && num <= max;
}
/**
 * @description 获取页面导出的pdf文件  默认导出A4大小的文件
 * @param fileName 导出文件名
 * @param className 需要导出的dom的className
 */
export function htmlExportPdf(fileName: string, className: string) {
	return new Promise((resolve) => {
		const title = fileName || `导出文件${formatDate(new Date(), 'YYYYmmddHHMMSS')}`; // 导出文件名，默认为“标题”
		const children: any = document.getElementsByClassName(className || 'pdf-cell');
		let canvas = <EmptyArrayType>[];
		let i = 0;
		const toCanvas = () => {
			if (children.length) {
				html2canvas(<HTMLElement>children[i], {
					scale: 2,
				}).then((res: any) => {
					// 计算每个dom的高度，方便后面计算分页
					res.imgWidth = 190;
					res.imgHeight = (190 / res.width) * res.height;
					canvas.push(res);
					i++;
					if (canvas.length === children.length) {
						paging();
						toPdf();
					} else {
						toCanvas();
					}
				});
			}
		};
		/**
		 * [根据dom的高度初步进行分页，会将canvas组装为一个二维数组]
		 */
		const paging = () => {
			const imgArr = <EmptyArrayType>[[]];
			let pageH = 0; // 页面的高度
			let allH = 0; // 当前组所有dom的高度和
			let j = 0;
			for (let k = 0; k < canvas.length; k++) {
				// 涉及到k--的操作，使用for循环方便
				pageH += canvas[k].imgHeight;
				if (pageH > 257 && canvas[k].imgHeight < 257) {
					// 当某个页面装不下下一个dom时，则分页
					imgArr[j][0].allH = allH - canvas[k].imgHeight;
					allH = pageH = 0;
					k--;
					j++;
					imgArr.push([]);
				} else {
					if (canvas[k].imgHeight > 257) {
						// 特殊情况：某个dom高度大于了页面高度，特殊处理
						canvas[k].topH = 257 - (pageH - canvas[k].imgHeight); // 该dom顶部距离页面上方的距离
						pageH = (2 * canvas[k].imgHeight - pageH) % 257;
						canvas[k].pageH = pageH; // 该dom底部距离页面上方的距离
					}
					imgArr[j].push(canvas[k]);
					allH += canvas[k].imgHeight;
				}
				if (k === canvas.length - 1) imgArr[j][0].allH = allH;
			}
			canvas = imgArr;
		};
		/**
		 * [生成PDF文件]
		 */
		const toPdf = () => {
			const PDF = new JSPDF('p', 'mm', 'a4');
			canvas.forEach((page, index) => {
				let allH = page[0].allH;
				let position = 0; // pdf页面偏移
				if (index !== 0 && allH <= 257) PDF.addPage();
				page.forEach((img: any) => {
					if (img.imgHeight < 257) {
						// 当某个dom高度小于页面宽度，直接添加图片
						PDF.addImage(img.toDataURL('image/jpeg', 1.0), 'JPEG', 10, position + 10, img.imgWidth, img.imgHeight);
						position += img.imgHeight;
						allH -= img.imgHeight;
					} else {
						// 当某个dom高度大于页面宽度，则需另行处理
						while (allH > 0) {
							PDF.addImage(img.toDataURL('image/jpeg', 1.0), 'JPEG', 10, position + 10, img.imgWidth, img.imgHeight);
							allH -= img.topH || 257;
							position -= img.topH || 257;
							img.topH = 0;
							if (allH > 0) PDF.addPage();
						}
						position = img.pageH;
					}
				});
			});
			PDF.save(title + '.pdf');
			resolve([]);
		};
		toCanvas();
	});
}
/**
 * @description  判断是否是json
 * @returns {*}
 * @param str
 * */
export function isJSON(str: string) {
	try {
		const jsonStr = JSON.parse(str);
		const jsonObj = JSON.parse(jsonStr);
		return !!(typeof jsonObj == 'object' && jsonObj);
	} catch (e) {
		return false;
	}
}
/**
 * @description  去除空格
 * @returns {*}
 * @param input
 * */
export function trimCompat(input: string | number | null) {
	if (typeof input === 'string') {
		return input.trim();
	} else if (typeof input === 'number') {
		// 如果输入是数字，先转为字符串再 trim（虽然通常数字不需要 trim）
		return String(input).trim();
	} else if (input === null) {
		// 如果输入是 null，可以返回空字符串或者根据需求处理
		return '';
	} else {
		// 其他情况，根据需求可以返回原值或者处理
		return input;
	}
}
/**
 * @description  导出交办单 --- 公共方法
 * @returns {*}
 * @param ids
 * */
export function exportAssignment(ids: string[]) {
	return new Promise((resolve, reject) => {
		ElMessageBox.confirm(`您确定导出选中的工单交办单，是否继续?`, '提示', {
			confirmButtonText: '确认',
			cancelButtonText: '取消',
			type: 'warning',
			draggable: true,
			cancelButtonClass: 'default-button',
			autofocus: false,
		})
			.then(() => {
				VxeUI.modal.message({
					content: `导出中，请稍等`,
					status: 'loading',
					id: 'exportJBD',
					duration: -1,
				});
				exportJbOrder(ids)
					.then((res: any) => {
						downloadZip(res);
						VxeUI.modal.close('exportJBD');
						VxeUI.modal.message({
							content: `导出成功`,
							status: 'success',
						});
						resolve(true);
					})
					.catch((err: any) => {
						VxeUI.modal.close('exportJBD');
						VxeUI.modal.message({
							content: `导出失败`,
							status: 'error',
						});
						reject(err);
					});
			})
			.catch(() => {});
	});
}
