package com.product.file.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import com.product.common.lang.StringUtils;
import com.product.core.cache.util.RedisUtil;
import com.product.core.config.Global;
import com.product.core.entity.DataTableEntity;
import com.product.core.entity.FieldSetEntity;
import com.product.core.exception.BaseException;
import com.product.core.service.support.AbstractBaseService;
import com.product.core.spring.context.SpringMVCContextHolder;
import com.product.file.config.CmnConst;
import com.product.file.config.FileCode;
import com.product.file.util.FileUtils;
import com.product.module.sys.entity.SystemUser;
import com.product.module.sys.service.idel.IOnlineDocumentEditingService;
import com.product.util.BaseUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author cheng
 * @Date 2022/4/11 10:08
 * @Desc 鏂囨。鍦ㄧ嚎缂栬緫涓氬姟绫�
 */
@Service
@Primary
public class OnlineDocumentEditService extends AbstractBaseService implements IOnlineDocumentEditingService {
	/**
	 * 鏂囨。缂栬緫鏍囪瘑key
	 */
	private final String DOCUMENT_EDIT_KEY = "document-edit:";

	@Autowired
	FileManagerService fileManagerService;

	@Autowired
	FileUtils fileUtils;

	/**
	 * 鏂囨。濂楃孩
	 *
	 * @param ff
	 * @param file
	 */
	public void nestRedDocument(FieldSetEntity ff, File file) {
		try {
			String document_template = ff.getString("document_template");
			String document_template_tail = ff.getString("document_template_tail");
			String fileUuid = ff.getString("file_uuid");
			FieldSetEntity fieldSetEntity = getBaseDao().getFieldSetEntity(CmnConst.PRODUCT_SYS_ATTACHMENTS, fileUuid, false);
			//鑾峰彇鏂囦欢绫诲瀷
			String fileName = fieldSetEntity.getString(CmnConst.FILE_NAME);
			//鍒ゆ柇鏄惁涓篸oc鏂囦欢
			String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
			if ("doc".equals(fileType)) {
				//灏哾oc鏂囦欢杞崲涓篸ocx鏂囦欢
				File f = file;
				file = com.product.file.util.FileUtil.toDocx(file);
				if (f != null) {
					f.delete();
				}
			}
			List<File> fileList = new ArrayList<>(3);
			if (!StringUtils.isEmpty(document_template)) {
				File file1 = fileManagerService.getFile(document_template);
				//鍒ゆ柇file1鐨勬枃浠剁被鍨�
				if (file1.getName().substring(file1.getName().lastIndexOf(".") + 1).equals("doc")) {
					//杞崲涓篸ocx
					File docx = com.product.file.util.FileUtil.toDocx(file1);
					FileUtil.del(file1);
					file1 = docx;
				}
				fileList.add(file1);
				fileList.add(file);
			} else {
				fileList.add(file);
			}
			if (!StringUtils.isEmpty(document_template_tail)) {
				fileList.add(fileManagerService.getFile(document_template_tail));
			}
			File mergeFile = MergeDoc.mergeDoc(fileList, Global.getSystemConfig("upload.file.temp.path", "./attachment/temp") + File.separator + "nest_red_document_" + IdUtil.randomUUID() + "_" + ff.getString("file_uuid"));
			if (mergeFile != null && mergeFile.isFile()) {
				if ("doc".equals(fileType)) {
					//灏哾ocx鏂囦欢杞崲涓篸oc鏂囦欢
					File f = mergeFile;
					mergeFile = com.product.file.util.FileUtil.toDoc(f);
					if (f != null) {
						f.delete();
					}
				}
				HashMap<String, File> objectObjectHashMap = new HashMap<>();
				objectObjectHashMap.put("mergeFile", mergeFile);
				uploadFile(ff.getString("file_uuid"), objectObjectHashMap);
			} else {
				throw new BaseException(FileCode.NEST_RED_DOCUMENT_FAIL);
			}
			fileList.forEach(FileUtil::del);
		} catch (BaseException e) {
			throw e;
		} catch (Exception e) {
			e.printStackTrace();
			throw new BaseException(FileCode.NEST_RED_DOCUMENT_FAIL);
		}
	}


	/**
	 * 鍦ㄧ嚎棰勮鎴栫紪杈戣幏鍙栨枃浠�
	 *
	 * @param response
	 * @param uuid
	 * @throws IOException
	 */
	public void getFile(HttpServletResponse response, String uuid) throws IOException {
		String currentUserId = SpringMVCContextHolder.getCurrentUserId();
		if (StringUtils.isEmpty(currentUserId)) {
			return;
		}
		String redisKey = this.DOCUMENT_EDIT_KEY + uuid + "-" + currentUserId;
		//鍦╮edis涓幏鍙栫紦瀛� 鏍规嵁缂撳瓨鏄惁瀛樺湪鍒ゆ柇璇ユ枃浠舵槸鍚︽爣璇嗕负姝e湪缂栬緫鐨勭姸鎬�
		Map<String, Object> map = (Map<String, Object>) RedisUtil.get(redisKey);  //鏌ヨ鏂囦欢璁板綍
		FieldSetEntity fse = getBaseDao().getFieldSetEntity(CmnConst.PRODUCT_SYS_ATTACHMENTS, uuid, false);
		if (FieldSetEntity.isEmpty(fse)) {
			throw new BaseException(FileCode.GET_FILE_RECORD_FAIL);
		}
		if (map != null) {
			//姝e湪缂栬緫 鍑嗗杈撳嚭宸茬紪杈戣繃浣嗘湭鎻愪氦鐨勬枃浠�
			String dir = fse.getString(CmnConst.ATTACHMENT_URL);
			String fileName = fse.getString(CmnConst.ATTACHMENT_TITLE);
			//宸茬紪杈戞湭鎻愪氦鐨勬枃浠惰矾寰�
			try {
				File sourceFile = fileUtils.getFile(fse.getBoolean(CmnConst.UPLOAD_SIGN), dir, fileName + "_" + currentUserId + "_" + map.get("uniqueKey"), fse.getBoolean(CmnConst.ENCRPT_SIGN));
				if (sourceFile != null && sourceFile.isFile()) {
					//杈撳嚭
					IoUtil.write(response.getOutputStream(), true, FileUtil.readBytes(sourceFile));
					sourceFile.delete();
					return;
				}
			} catch (BaseException e) {
				//鎹曡幏寮傚父
			}
		}
		IoUtil.write(response.getOutputStream(), true, fileManagerService.getFileContent(fse));
	}

	/**
	 * 娓呯┖姝e湪缂栬緫鏂囨。鐘舵€� 鏍规嵁鐢ㄦ埛
	 *
	 * @param userId 鐢ㄦ埛id
	 */
	public void clearBeingEditDocumentStatus(String userId) {
		if (StringUtils.isEmpty(userId)) {
			return;
		}
		//姝e垯鍖归厤redis涓殑key
		Set<byte[]> keys = RedisUtil.keys(this.DOCUMENT_EDIT_KEY + "*-" + userId);
		if (keys != null && keys.size() > 0) {
			String[] strKeys = new String[keys.size()];
			int i = 0;
			for (byte[] key : keys) {
				strKeys[i++] = new String(key);
			}
			//娓呯┖redis
			RedisUtil.del(strKeys);
		}
	}

	/**
	 * 涓氬姟鏁版嵁淇濆瓨鏃跺簳灞傝皟鐢ㄦ鏂规硶
	 * 璋冪敤姝ゆ柟娉曞悗灏嗘枃浠舵爣璁颁负宸蹭繚瀛� 娓呴櫎姝e湪缂栬緫鐨勭姸鎬佹爣璇�
	 *
	 * @param fileUuid 鏂囦欢uuid
	 * @param userId   鎿嶄綔浜篿d
	 * @return
	 */
	@Override
	public boolean saveDocNotice(String fileUuid, int userId) throws BaseException {

		if (StringUtils.isEmpty(fileUuid)) {
			return false;
		}
		String[] fileUuids = fileUuid.split(",");
		//鏌ヨ鏂囦欢璁板綍
		DataTableEntity dt = getBaseDao().listTable(CmnConst.PRODUCT_SYS_ATTACHMENTS, BaseUtil.buildQuestionMarkFilter("uuid", fileUuids, true));
		if (!DataTableEntity.isEmpty(dt)) {
//                throw new BaseException(FileCode.GET_FILE_RECORD_FAIL);
			for (int i = 0; i < dt.getRows(); i++) {
				FieldSetEntity fse = dt.getFieldSetEntity(i);
				try {
					String redisKey = this.DOCUMENT_EDIT_KEY + fse.getUUID() + "-" + userId;
					if (!RedisUtil.exists(redisKey)) {
						continue;
					}
					Map<String, Object> map = (Map<String, Object>) RedisUtil.get(redisKey);
					if (map != null) {
						String dir = fse.getString(CmnConst.ATTACHMENT_URL);
						String fileName = fse.getString(CmnConst.ATTACHMENT_TITLE);
						if (!fileUtils.fileIsExist(fse.getBoolean(CmnConst.UPLOAD_SIGN), dir, fileName)) {
							continue;
						}
						//绯荤粺闄勪欢瀛樻斁鐨勬牴璺緞
						File sourceFile = fileUtils.getFile(fse.getBoolean(CmnConst.UPLOAD_SIGN), dir, fileName + "_" + userId + "_" + map.get("uniqueKey"), fse.getBoolean(CmnConst.ENCRPT_SIGN));
						if (sourceFile != null && sourceFile.isFile()) {
							File targetFile = fileUtils.getFile(fse.getBoolean(CmnConst.UPLOAD_SIGN), dir, fileName, false);
							if (targetFile != null && targetFile.isFile()) {
								//澶囦唤婧愭枃浠�
								fileUtils.uploadOtherFile(fse.getBoolean(CmnConst.ENCRPT_SIGN), dir, targetFile, fileName + "_back_" + userId + "_" + map.get("uniqueKey"));
								targetFile.delete();
							}

							//灏嗕慨鏀瑰悗鐨勬枃浠惰鐩栧埌婧愭枃浠�
							fileUtils.replaceFile(dir, fileName, fse.getString(CmnConst.FILE_NAME), sourceFile, fse.getBoolean(CmnConst.ENCRPT_SIGN), fse.getBoolean(CmnConst.UPLOAD_SIGN), fse.getBoolean(CmnConst.VIEW_ONLINE_SIGN));
							if (fse.getBoolean(CmnConst.ENCRPT_SIGN)) {
								fileUtils.deleteFilesServerOnFile(dir, fileName + "_" + userId + "_" + map.get("uniqueKey"));
							}
							sourceFile.delete();
							
							//鏍囪鏂囦欢淇敼
							fileManagerService.signUpdateAttachment(fse.getUUID(), userId);
						}
					}
					RedisUtil.del(redisKey);
				} catch (Exception e) {
					e.printStackTrace();
					SpringMVCContextHolder.getSystemLogger().error(e);
//                    return false;
				}
			}
		}

		return true;
	}


	/**
	 * weboffice 淇濆瓨鏂囦欢锛堟墜鍔ㄣ€佽嚜鍔級
	 *
	 * @param uuid    鏂囦欢鐨剈uid
	 * @param fileMap 鏂版彁浜ょ殑鏂囦欢
	 * @throws BaseException
	 */
	public void uploadFile(String uuid, Map<String, File> fileMap) throws BaseException {
		//鏌ヨ鏂囦欢璁板綍
		FieldSetEntity fse = getBaseDao().getFieldSetEntity(CmnConst.PRODUCT_SYS_ATTACHMENTS, uuid, false);
		if (FieldSetEntity.isEmpty(fse)) {
			throw new BaseException(FileCode.GET_FILE_RECORD_FAIL);
		}
		String userId = SpringMVCContextHolder.getCurrentUserId();
		if (StringUtils.isEmpty(userId)) {
			return;
		}
		//鑾峰彇婧愭枃浠惰矾寰�
		String dir = fse.getString(CmnConst.ATTACHMENT_URL);
		String fileName = fse.getString(CmnConst.ATTACHMENT_TITLE);
		if (!fileUtils.fileIsExist(fse.getBoolean(CmnConst.UPLOAD_SIGN), dir, fileName)) {
			throw new BaseException(FileCode.INVALID_FILE_PATH);
		}
		String redisKey = this.DOCUMENT_EDIT_KEY + uuid + "-" + userId;
		Map<String, Object> map = (Map<String, Object>) RedisUtil.get(redisKey);

		//绯荤粺闄勪欢瀛樻斁鐨勬牴璺緞
		File file = fileMap.values().toArray(new File[]{})[0];
		if (fse.getBoolean(CmnConst.ENCRPT_SIGN)) {
			String filePath = Global.getSystemConfig("temp.dir", "") + "/onlineEdit_" + redisKey;
			//鍔犲瘑鏂囦欢
			com.product.file.util.FileUtil.copyFile(file, filePath, 1);
			file.delete();
			file = new File(filePath);
		}
		FileUtils.uploadOtherFile(fse.getBoolean(CmnConst.ENCRPT_SIGN), dir, file, fileName + "_" + userId + "_" + map.get("uniqueKey"));
		file.delete();
	}

	public void deleteFile(String dir, String fileName) {
		SystemUser currentUser = SpringMVCContextHolder.getCurrentUser();
		if (currentUser != null && !StringUtils.isEmpty(currentUser.getToken_info())) {
//            TokenValidateInterceptor
		}
	}

	/**
	 * 鑾峰彇杩囨湡鏃堕棿
	 *
	 * @return 杩囨湡鏃堕棿 鍗曚綅 绉�
	 */
	private int getExpirationTime() {
		int refreshTokenExpiration = Global.getPropertyToInteger("refresh.token.expiration", "8") * 60 * 60;
		int tokenExpiration = Global.getPropertyToInteger("token.expiration", (8 * 60) + "") * 60;

		return refreshTokenExpiration > tokenExpiration ? refreshTokenExpiration : tokenExpiration;
	}

	/**
	 * 鏍囪瘑鏂囨。姝e湪缂栬緫
	 *
	 * @param fileUuid
	 * @return
	 */
	public void signDocumentEdit(String fileUuid) throws BaseException {
		String userId = SpringMVCContextHolder.getCurrentUserId();
		if (StringUtils.isEmpty(userId)) {
			throw new BaseException(FileCode.GET_FILE_RECORD_FAIL);
		}
		String key = this.DOCUMENT_EDIT_KEY + fileUuid + "-" + userId;
		//妯$硦鍖归厤key
		Set<byte[]> keyBytes = RedisUtil.keys((this.DOCUMENT_EDIT_KEY + fileUuid + "-*").getBytes(StandardCharsets.UTF_8));
		if (!CollectionUtil.isEmpty(keyBytes)) {
			Set<String> keys = keyBytes.stream().map(item -> new String(item, StandardCharsets.UTF_8)).collect(Collectors.toSet());
			boolean remove = keys.remove(this.DOCUMENT_EDIT_KEY + fileUuid + "-" + userId);
			if (keys != null && keys.size() > 0) {
				//姝e湪琚紪杈�
				String existsKey = keys.toArray(new String[]{})[0];
				//杩欓噷浼氭姏鍑烘鍦ㄧ紪杈戠殑寮傚父
				throwBeingEditDocument(existsKey.substring(existsKey.lastIndexOf("-") + 1));
			} else if (remove) {
				RedisUtil.setOutTime(key, getExpirationTime());
				return;
			}
		}

		Map<String, Object> params = new HashMap<>();
		params.put("userId", userId);
		params.put("fileUuid", fileUuid);
		params.put("uniqueKey", IdUtil.randomUUID());
		RedisUtil.set(key, params);
		RedisUtil.setOutTime(key, getExpirationTime());
	}

	/**
	 * 姝e湪缂栬緫鏂囨。閿欒鎶涘嚭
	 *
	 * @param userId
	 * @throws BaseException
	 */
	private void throwBeingEditDocument(Object userId) throws BaseException {
		FieldSetEntity userInfo = BaseUtil.getSingleInfoByCache("鐢ㄦ埛缂撳瓨", new String[]{String.valueOf(userId)});
		String user_name;
		if (userInfo != null && !StringUtils.isEmpty(userInfo.getString("user_name"))) {
			user_name = userInfo.getString("user_name");
		} else {
			user_name = "鏈煡鐢ㄦ埛";
		}
		throw new BaseException(FileCode.DOCUMENT_BEING_EDITED.getValue(), FileCode.DOCUMENT_BEING_EDITED.getText().replace("{{userName}}", user_name));
	}

}