/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the yifu4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */
package com.yifu.cloud.plus.v1.yifu.archives.service.impl;

import cn.hutool.core.util.CharsetUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yifu.cloud.plus.v1.yifu.archives.entity.TElecEmployeeInfo;
import com.yifu.cloud.plus.v1.yifu.archives.entity.TEmployeeInfo;
import com.yifu.cloud.plus.v1.yifu.archives.mapper.TAttaInfoMapper;
import com.yifu.cloud.plus.v1.yifu.archives.mapper.TElecEmployeeInfoMapper;
import com.yifu.cloud.plus.v1.yifu.archives.service.FileUploadService;
import com.yifu.cloud.plus.v1.yifu.archives.service.TElecEmployeeInfoService;
import com.yifu.cloud.plus.v1.yifu.archives.service.TEmployeeInfoService;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CacheConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.util.Common;
import com.yifu.cloud.plus.v1.yifu.common.core.util.R;
import com.yifu.cloud.plus.v1.yifu.common.core.util.RedisUtil;
import com.yifu.cloud.plus.v1.yifu.common.dapr.config.DaprUpmsProperties;
import lombok.RequiredArgsConstructor;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;


/**
 * 电子档案信息表
 *
 * @author fxj
 * @date 2022-06-18 09:39:46
 */
@Service
@RequiredArgsConstructor
@EnableConfigurationProperties(DaprUpmsProperties.class)
public class TElecEmployeeInfoServiceImpl extends ServiceImpl<TElecEmployeeInfoMapper, TElecEmployeeInfo> implements TElecEmployeeInfoService {

	private final TEmployeeInfoService tEmployeeInfoService;

	private final FileUploadService fileUploadService;

	private final DaprUpmsProperties daprUpmsProperties;

	private final TAttaInfoMapper attaInfoMapper;

	@Override
	public boolean save(TElecEmployeeInfo entity) {
		return super.save(entity);
	}

	@Override
	public IPage<TElecEmployeeInfo> getTElecEmployeeInfoPage(Page page, TElecEmployeeInfo tElecEmployeeInfo) {
		return baseMapper.getTElecEmployeeInfoPage(page, tElecEmployeeInfo);
	}

	/**
	 * @param zipFile zip文件包
	 * @description: 解析zip文件包中的多个附件，并生成结算记录
	 * @return: com.yifu.cloud.v1.common.core.util.R<java.lang.Boolean>
	 * @author: huyc
	 * @date: 2022/6/27
	 */
	@Override
	@Transactional
	public R importZip(MultipartFile zipFile){
		try {
			String pathName = System.getProperty("java.io.tmpdir");
			String dec = System.getProperty("java.io.tmpdir");
			File file1 = new File(pathName);
			//如果文件夹不存在  创建文件夹
			if (!file1.exists()) {
				file1.mkdir();
			}

			//获取文件名（包括后缀）
			String pname = zipFile.getOriginalFilename();
			pathName = pathName + pname;

			File file = new File(pathName);
			zipFile.transferTo(file);
			// 获取解压出来的文件名 不带后缀
			return unZip(file, dec);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return R.ok();
	}

	@Override
	public R getEmpInfoByCard(String idCard) {
		TEmployeeInfo tEmployeeInfo = tEmployeeInfoService.getOne((Wrappers.<TEmployeeInfo>query().lambda()
				.eq(TEmployeeInfo::getEmpIdcard, idCard)).eq(TEmployeeInfo::getDeleteFlag, CommonConstants.ZERO_STRING));
		if (Common.isNotNull(tEmployeeInfo)) {
			if (CommonConstants.ONE_INT == tEmployeeInfo.getFileStatus()) {
				return R.failed("身份证号对应的档案为已减档");
			}
			return R.ok(tEmployeeInfo);
		}
		return R.failed("未找到身份证号对应的档案信息");
	}

	@Override
	public R saveElecInfo(TElecEmployeeInfo tElecEmployeeInfo) {
		baseMapper.insert(tElecEmployeeInfo);
		//更新附件信息
		List<String> ids;
		if (Common.isNotNull(tElecEmployeeInfo.getAttaIds())) {
			ids = Common.initStrToList(tElecEmployeeInfo.getAttaIds(), CommonConstants.COMMA_STRING);
			attaInfoMapper.updateDomainId(tElecEmployeeInfo.getId(), ids);
		}
		return R.ok();
	}

	/**
	 * zip解压
	 *
	 * @param srcFile zip源文件
	 * @throws RuntimeException 解压失败会抛出运行时异常
	 */
	private R unZip(File srcFile, String destDirPath) throws RuntimeException {

		Map<String, String> elecTypeMap = new HashMap<>();
		// 渲染字典值
		Map<String,String> dicObj = (Map<String, String>) RedisUtil.redis.opsForValue()
				.get(CacheConstants.DICT_DETAILS
						+ CommonConstants.COLON_STRING
						+ "literature_types");
		if (Common.isNotNull(dicObj)) {
			for (Map.Entry<String, String> entry : dicObj.entrySet()) {
				elecTypeMap.put(entry.getValue(),entry.getKey());
			}
		}
		if (elecTypeMap.isEmpty()) {
			return R.failed("获取字典失败！");
		}
		// 判断源文件是否存在
		if (!srcFile.exists()) {
			throw new RuntimeException(srcFile.getPath() + "所指文件不存在");
		}
		// 开始解压
		ZipFile zipFile = null;
		try {
			zipFile = new ZipFile(srcFile, CharsetUtil.CHARSET_GBK);
			Enumeration<?> entries = zipFile.entries();
			Enumeration<?> entriesCheck = zipFile.entries();

			Set<String> infoList =new HashSet<>();
			Set<String> idCardList =new HashSet<>();
			Set<String> cardType =new HashSet<>();

			TEmployeeInfo tEmployeeInfo;
			ZipEntry entry;
			String idCard;
			String empInfo;
			while (entriesCheck.hasMoreElements()) {
				entry = (ZipEntry) entriesCheck.nextElement();
				//添加进filesName
				empInfo = entry.getName();
				infoList.add(empInfo);
				String dataType = "";
				if (empInfo.lastIndexOf("/") != empInfo.indexOf("/")) {
					if (!empInfo.contains("-")) {
						return R.failed("请使用正确的文件夹命名格式：身份证-员工姓名");
					}
					idCard = empInfo.substring(0, empInfo.indexOf("-"));
					tEmployeeInfo = tEmployeeInfoService.getOne((Wrappers.<TEmployeeInfo>query().lambda()
							.eq(TEmployeeInfo::getEmpIdcard, idCard)).eq(TEmployeeInfo::getFileStatus, CommonConstants.ZERO_INT)
							.eq(TEmployeeInfo::getDeleteFlag, CommonConstants.ZERO_STRING)
							.eq(TEmployeeInfo::getFileStatus, CommonConstants.ZERO_INT));
					if (Common.isEmpty(tEmployeeInfo)) {
						return R.failed("未找到身份证对应的档案信息,身份证号：" + idCard);
					}
					idCardList.add(idCard);
					if (empInfo.length() > 20) {
						dataType = empInfo.substring(empInfo.indexOf("/") + 1, empInfo.lastIndexOf("/"));
						if (!Common.isNotNull(elecTypeMap.get(dataType))) {
							return R.failed("资料类型错误：" + dataType);
						}
						cardType.add(idCard + "_" + dataType);
					}
				}
			}
			for (String idCarInfo : idCardList) {
				if (infoList.stream().noneMatch(e-> containsCheckTwo(e,idCarInfo))) {
					return R.failed(idCarInfo + ":"+"证件数据不可为空");
				}
			}
			if (cardType.size() > CommonConstants.ZERO_INT) {
				for (String typeInfo :cardType) {
					if (infoList.stream().noneMatch(e -> containsCheckOne(e, typeInfo))) {
						return R.failed(typeInfo + ":" + "证件数据不可为空");
					}
				}
			}

			Map<String, String> insMap = new HashMap<>();
			TEmployeeInfo employeeInfo;
			while (entries.hasMoreElements()) {
				entry = (ZipEntry) entries.nextElement();
				//添加进filesName
				empInfo = entry.getName();
				// 如果是文件夹，就创建个文件夹
				if (entry.isDirectory()) {
					String dirPath = destDirPath + "/" + entry.getName();
					File dir = new File(dirPath);
					dir.mkdirs();
				} else {
					// 如果是文件，就先创建一个文件，然后用io流把内容copy过去
					File targetFile = new File(destDirPath + "/" + entry.getName());

					// 保证这个文件的父文件夹必须要存在
					if (!targetFile.getParentFile().exists()) {
						targetFile.getParentFile().mkdirs();
					}
					targetFile.createNewFile();
					// 将压缩文件内容写入到这个文件中
					InputStream is = zipFile.getInputStream(entry);
					FileOutputStream fos = new FileOutputStream(targetFile);
					int len;
					byte[] buf = new byte[1024];
					while ((len = is.read(buf)) != -1) {
						fos.write(buf, 0, len);
					}

					TElecEmployeeInfo tElecEmployeeInfo = new TElecEmployeeInfo();
					if (empInfo.length() > empInfo.lastIndexOf("/") + 1) {
						idCard = empInfo.substring(0, empInfo.indexOf("-"));
						String dataType = empInfo.substring(empInfo.indexOf("/") + 1, empInfo.lastIndexOf("/"));
						String empName = "";
						employeeInfo = tEmployeeInfoService.getOne((Wrappers.<TEmployeeInfo>query().lambda()
								.eq(TEmployeeInfo::getEmpIdcard, idCard)).eq(TEmployeeInfo::getFileStatus, CommonConstants.ZERO_INT)
								.eq(TEmployeeInfo::getDeleteFlag, CommonConstants.ZERO_STRING));
						if (Common.isNotNull(employeeInfo)) {
							empName = employeeInfo.getEmpName();
						}
						tElecEmployeeInfo.setEmpIdcard(idCard);
						tElecEmployeeInfo.setEmpName(empName);
						if (Common.isNotNull(elecTypeMap.get(dataType))) {
							tElecEmployeeInfo.setDataType(elecTypeMap.get(dataType));
						}
						String id = insMap.get(idCard + CommonConstants.DOWN_LINE_STRING + dataType);
						if (Common.isEmpty(id)) {
							this.save(tElecEmployeeInfo);
							insMap.put(idCard + CommonConstants.DOWN_LINE_STRING + dataType, tElecEmployeeInfo.getId());
						}
						fileUploadService.uploadImg(fileCovertMultipartFile(targetFile), "", CommonConstants.EIGHT_STRING, insMap.get(idCard + CommonConstants.DOWN_LINE_STRING + dataType));
					}

					// 关流顺序，先打开的后关闭
					fos.close();
					is.close();
				}
			}
			//解析完成删除本次解析中生成的文件  删除此目录下的所有文件
			deleteFolder(destDirPath);
		} catch (Exception e) {
			throw new RuntimeException("unzip error from ZipUtils", e);
		} finally {
			if (zipFile != null) {
				try {
					zipFile.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return R.ok();
	}

	/**
	 * File转MultipartFile
	 *
	 * @param file 需要转换的文件
	 * @description: File转MultipartFile
	 * @return: org.springframework.web.multipart.MultipartFile
	 * @author: huyc
	 * @date: 2022/6/27
	 */
	private MultipartFile fileCovertMultipartFile(File file) {
		FileItemFactory factory = new DiskFileItemFactory(16, null);
		FileItem item = factory.createItem(file.getName(), "text/plain", true, file.getName());
		int bytesRead = 0;
		byte[] buffer = new byte[8192];
		try {
			FileInputStream fis = new FileInputStream(file);
			OutputStream os = item.getOutputStream();
			while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
				os.write(buffer, 0, bytesRead);
			}
			os.close();
			fis.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		MultipartFile multipartFile = new CommonsMultipartFile(item);
		return multipartFile;
	}


	/**
	 * 根据路径删除指定的目录或文件，无论存在与否
	 *
	 * @param path 要删除的目录或文件路径
	 * @return 删除成功返回 true，否则返回 false
	 */
	public static boolean deleteFolder(String path) {
		File file = new File(path);
		// 判断目录或文件是否存在
		if (!file.exists()) {
			return false;
		} else {
			// 判断是否为文件
			if (file.isFile()) {  // 为文件时调用删除文件方法
				return deleteFile(path);
			} else {  // 为目录时调用删除目录方法
				return deleteDirectory(path);
			}
		}
	}

	/**
	 * 删除单个文件
	 */
	private static boolean deleteFile(String path) {
		File file = new File(path);
		// 路径为文件且不为空则进行删除
		if (file.isFile() && file.exists()) {
			file.delete();
			return true;
		}
		return false;
	}

	/**
	 * 删除目录（文件夹）以及目录下的文件
	 */
	private static boolean deleteDirectory(String path) {
		//如果path不以文件分隔符结尾，自动添加文件分隔符
		if (!path.endsWith(File.separator)) {
			path = path + File.separator;
		}
		File dirFile = new File(path);
		//如果dir对应的文件不存在，或者不是一个目录，则退出
		if (!dirFile.exists() || !dirFile.isDirectory()) {
			return false;
		}
		boolean flag = true;
		//删除文件夹下的所有文件(包括子目录)
		File[] files = dirFile.listFiles();
		for (File file : files) {
			//删除子文件
			if (file.isFile()) {
				flag = deleteFile(file.getAbsolutePath());
			} //删除子目录
			else {
				flag = deleteDirectory(file.getAbsolutePath());
			}
			if (!flag) {
				break;
			}
		}
		if (!flag) {
			return false;
		}
		//删除当前目录
		return dirFile.delete();
	}

	public boolean containsCheckTwo(String e,String idCard) {
		return e.contains(idCard) && e.length() > 20;
	}

	public boolean containsCheckOne(String e,String cardType) {
		String empIdcard = cardType.substring(0,cardType.indexOf("_"));
		String fileName = cardType.substring(cardType.indexOf("_") +1);
		return e.contains(empIdcard) && e.contains(fileName) && e.contains(CommonConstants.SPOT);
	}
}
