package com.jiayue.ipfcst.fileupload.IEC102;

import com.jiayue.ipfcst.common.data.constant.enums.FileStatusEnum;
import com.jiayue.ipfcst.common.data.constant.enums.FileTypeEnum;
import com.jiayue.ipfcst.common.data.entity.*;
import com.jiayue.ipfcst.common.data.repository.UploadFileLogDetailRepository;
import com.jiayue.ipfcst.common.data.repository.UploadFileLogRepository;
import com.jiayue.ipfcst.console.service.ElectricFieldService;
import com.jiayue.ipfcst.console.service.SysParameterService;
import com.jiayue.ipfcst.fileupload.service.UploadFileCodeService;
import com.jiayue.ipfcst.fileupload.util.ByteUtil;
import com.jiayue.ipfcst.fileupload.util.FileConstant;
import com.jiayue.ipfcst.fileupload.util.FileMutableInteger;
import com.jiayue.ipfcst.fileupload.util.FileUtil;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.*;
import java.util.*;


/**
 * 102业务处理基础类
 *
 * @author xsl
 * @version 3.0
 */
@Service
public class Base102Service {
  @Autowired
  UploadFileLogRepository uploadFileLogRepository;
  @Autowired
  UploadFileLogDetailRepository uploadFileLogDetailRepository;
  @Autowired
  SysParameterService sysParameterService;
  @Autowired
  UploadFileCodeService uploadFileCodeService;
  @Autowired
  ElectricFieldService electricFieldService;


  /**
   * 统计文件上报成功或者失败并移动文件
   *
   * @param uploadFileChannel 通道信息
   * @param faileReason       失败原因
   */

  public void totalFileUploadNums(UploadObject uploadObject, UploadFileChannel uploadFileChannel, String faileReason, Logger log) {
    // 上报文件次数缓存加1
//    Map<String, FileMutableInteger> filterMap = FileConstant.uploadCountMap.entrySet().stream().filter(r -> uploadObject.getObjectNo().equals(r.getKey().substring(0, r.getKey().indexOf("@"))))
//      .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
//        (oldValue, newValue) -> oldValue, LinkedHashMap::new));

    // 上报文件名
    String fileNameKey = "";
    Iterator<Map.Entry<String, FileMutableInteger>> filterMap = FileConstant.uploadCountMap.entrySet().iterator();
    while (filterMap.hasNext()) {
      Map.Entry<String, FileMutableInteger> entry = filterMap.next();
      String key = entry.getKey();
      if (key.substring(0, key.indexOf("@")).equals(uploadObject.getObjectNo())) {
        fileNameKey = key;
        break;
      }
    }

    if (!"".equals(fileNameKey)) {
      String[] keys = new String[3];
      String tempFileName = fileNameKey;
      log.info("UploadNums操作文件：" + tempFileName);
      keys[0] = tempFileName.substring(0, tempFileName.indexOf("@", 0));
      tempFileName = tempFileName.substring(tempFileName.indexOf("@", 0) + 1);
      keys[1] = tempFileName.substring(0, tempFileName.indexOf("@", 0));
      keys[2] = tempFileName.substring(tempFileName.indexOf("@", 0) + 1);

      // 找到文件日志记录
      //今日凌晨
//    Long st = DateTimeUtil.getMillisecondsSubDay();
      //明日凌晨
//    Long et = DateTimeUtil.getMillisecondsSubDay() + 1000 * 60 * 60 * 24-1;

//    Date fileCreateTime = FileConstant.fileShouldMomentMap.get(fileNameKey);
      Integer id = FileConstant.fileShouldMomentMap.get(fileNameKey);
      UploadFileLog uploadFileLog = null;
      Optional<UploadFileLog> fileLogOptional = uploadFileLogRepository.findById(id);
      if (fileLogOptional.isPresent()) {
        uploadFileLog = fileLogOptional.get();
      }

      // 先判断是否查出日志，如果没有则认为文件是本地拷贝进去的
      if (uploadFileLog == null) {
        UploadFileLog newUploadFileLog = new UploadFileLog();
        newUploadFileLog.setUploadObjectId(uploadObject.getId());
        newUploadFileLog.setFileStatusEnum(FileStatusEnum.E1);
        newUploadFileLog.setUploadProtocolEnum(uploadObject.getUploadProtocolEnum());
        newUploadFileLog.setFileName(keys[2]);
        newUploadFileLog.setFileTypeEnum(FileTypeEnum.valueOf(keys[1]));
        newUploadFileLog.setUploadObjectName(uploadObject.getUploadObjectName());
        newUploadFileLog.setUploadObjectNo(uploadObject.getObjectNo());
        newUploadFileLog.setUploadCounter(0);
        newUploadFileLog.setFileRemarks("当日没找到日志记录,系统插入一条");
        uploadFileLog = uploadFileLogRepository.save(newUploadFileLog);
      }

      if ("".equals(faileReason)) {
        UploadFileLogDetail uploadFileLogDetail = new UploadFileLogDetail();
        uploadFileLogDetail.setUploadObjectName(uploadObject.getUploadObjectName());
        uploadFileLogDetail.setUploadFileLogId(uploadFileLog.getId());
        uploadFileLogDetail.setUploadTime(System.currentTimeMillis());
        uploadFileLogDetail.setFileName(keys[2]);
        uploadFileLogDetail.setUploadChanneId(uploadFileChannel.getId());
        uploadFileLogDetail.setUploadChannelName(uploadFileChannel.getChannelName());
        uploadFileLogDetail.setFileStatusEnum(FileStatusEnum.E2);
//      fileMutableInteger.getUploadFileLogDetail().add(uploadFileLogDetail);
        // 上报成功保存数据库，更新上报表，上报明细
//      uploadFileLogRepository.updateFileUploadCount(FileStatusEnum.E2, fileMutableInteger.getValue(), uploadObject.getId(), keys[2]);
//        uploadFileLog.setFileStatusEnum(FileStatusEnum.E2);
//        uploadFileLog.setUploadCounter(uploadFileLog.getUploadCounter()+1);
//        uploadFileLogRepository.save(uploadFileLog);
        uploadFileLogRepository.uploadFileUpdate(FileStatusEnum.E2, uploadFileLog.getUploadCounter() + 1, uploadFileLog.getId());
        uploadFileLogDetailRepository.save(uploadFileLogDetail);
        // 将文件移动到成功目录
        String srcPath = FileUtil.getFileUploadPath() + File.separator + "process" + File.separator + keys[0] + File.separator + keys[1] + File.separator + keys[2];
        String targetPath = FileUtil.getFileUploadPath() + File.separator + "backups" + File.separator + DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMdd") + File.separator + keys[0] + File.separator + keys[1];

        try {
          FileUtil.move(srcPath, targetPath);
        } catch (Exception e) {
          log.error("上报成功移动文件失败", e);
        }
        // 清理缓存
        FileConstant.uploadCountMap.remove(fileNameKey);
        FileConstant.readyUploadFileMap.remove(fileNameKey);
        FileConstant.fileShouldMomentMap.remove(fileNameKey);
        FileConstant.fileContentMap.remove(fileNameKey);
        FileConstant.againUploadFileMap.remove(fileNameKey);
        FileConstant.filePackageNumMap.remove(fileNameKey);
        log.info("上报对象编号:" + keys[0] + " 文件名:" + keys[2] + " 本次上报结果：成功");

      } else {
        // 保存上报失败明细表
        UploadFileLogDetail uploadFileLogDetail = new UploadFileLogDetail();
        uploadFileLogDetail.setUploadObjectName(uploadObject.getUploadObjectName());
        uploadFileLogDetail.setUploadFileLogId(uploadFileLog.getId());
        uploadFileLogDetail.setUploadTime(System.currentTimeMillis());
        uploadFileLogDetail.setFileName(keys[2]);
        uploadFileLogDetail.setUploadChanneId(uploadFileChannel.getId());
        uploadFileLogDetail.setUploadChannelName(uploadFileChannel.getChannelName());
        uploadFileLogDetail.setFileStatusEnum(FileStatusEnum.E3);
        uploadFileLogDetail.setUploadFailureReason(faileReason);
        uploadFileLog.setFileStatusEnum(FileStatusEnum.E3);
        uploadFileLog.setUploadCounter(uploadFileLog.getUploadCounter() + 1);
        uploadFileLogRepository.save(uploadFileLog);
        uploadFileLogDetailRepository.save(uploadFileLogDetail);

        if (FileConstant.againUploadFileMap.get(fileNameKey) == null) {
          // 遇到失败，再给这个文件一次上报的机会
          FileConstant.againUploadFileMap.put(fileNameKey, "");
          log.info(fileNameKey + "上报结果失败,再报一次变量中存入");
        } else {
          // 将文件移动到失败目录
          String srcPath = FileUtil.getFileUploadPath() + File.separator + "process" + File.separator + keys[0] + File.separator + keys[1] + File.separator + keys[2];
          String targetPath = FileUtil.getFileUploadPath() + File.separator + "error" + File.separator + DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMdd") + File.separator + keys[0] + File.separator + keys[1];
          try {
            FileUtil.move(srcPath, targetPath);
          } catch (Exception e) {
            log.error("将文件移动到失败目录", e);
          }
          FileConstant.readyUploadFileMap.remove(fileNameKey);
          FileConstant.fileShouldMomentMap.remove(fileNameKey);
          FileConstant.againUploadFileMap.remove(fileNameKey);
        }
        // 清理缓存
        FileConstant.uploadCountMap.remove(fileNameKey);
        FileConstant.fileContentMap.remove(fileNameKey);
        FileConstant.filePackageNumMap.remove(fileNameKey);
        log.info("上报对象编号:" + keys[0] + " 文件名:" + keys[2] + " 本次上报结果失败：" + faileReason);
      }
    }
  }

  /**
   * 读取文件内容转16进制报文
   *
   * @param filePath
   * @param charsetName
   * @return
   */
  public String createFileMessageHex(String filePath, String charsetName, Logger log) {
    InputStreamReader isr = null;
    String fileMessageHex = "";
    try {
      isr = new InputStreamReader(new FileInputStream(filePath), "UTF-8");
      StringBuffer sb = new StringBuffer("");
      int len1 = 0;
      while ((len1 = isr.read()) != -1) {
        sb.append((char) len1);
      }
      isr.close();

      String str = sb.toString();
      fileMessageHex = ByteUtil.Byte2String(str.getBytes(charsetName));
      fileMessageHex = fileMessageHex.replaceAll(" ", "");
      ////////////////////以下注释生成本地文件/////////////////////
//      int len = fileMessageHex.length();
//      byte[] data = new byte[len / 2];
//      for (
//        int i = 0;
//        i < len; i += 2) {
//        data[i / 2] = (byte) ((Character.digit(fileMessageHex.charAt(i), 16) << 4)
//          + Character.digit(fileMessageHex.charAt(i + 1), 16));
//      }
//      OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d:\\sdf.PVD"), charsetName);
//      String res = new String(data);
//      osw.write(res);
//      osw.close();
    } catch (Exception e) {
      log.error("读取本地文件失败", e);
    } finally {
      if (isr != null) {
        try {
          isr.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    return fileMessageHex;
  }

  /**
   * 根据通道过滤缓存Map的key是否存在
   *
   * @param uploadObjectNo
   * @param map
   * @return
   */
  public Map<String, UploadFileLog> filterFileByObjectNo(String uploadObjectNo, Map<String, UploadFileLog> map, Logger log) {
    Map<String, UploadFileLog> copyMap = new HashMap<>();
    copyMap.putAll(map);
    // 先过滤出上报对象下的所有文件
    Map<String, UploadFileLog> filterMap = new HashMap<>();
    Iterator<Map.Entry<String, UploadFileLog>> it = copyMap.entrySet().iterator();
    while (it.hasNext()) {
      Map.Entry<String, UploadFileLog> entry = it.next();
      if (uploadObjectNo.equals(entry.getKey().substring(0, entry.getKey().indexOf("@")))) {
        filterMap.put(entry.getKey(), entry.getValue());
      }
    }
    // 再将失效时间的文件移除
    Map<String, UploadFileLog> fileterFileMap = new HashMap<>();
    Date d = new Date();
    for (Map.Entry<String, UploadFileLog> entry : filterMap.entrySet()) {
      UploadFileLog u = entry.getValue();
      if (u.getUploadFileEndTime() == null) {
        // 有效的文件
        fileterFileMap.put(entry.getKey(), u);
      } else {
        if (d.getTime() <= u.getUploadFileEndTime()) {
          // 有效的文件
          fileterFileMap.put(entry.getKey(), u);
        } else {
          // 过期文件
          String[] keys = new String[3];
//          keys[0] = entry.getKey().substring(0,entry.getKey().indexOf("@",0));
//          keys[1] = entry.getKey().substring(entry.getKey().indexOf("@",1)+1,entry.getKey().indexOf("@",2));
//          keys[2] = entry.getKey().substring(entry.getKey().indexOf("@",2)+1);
          keys[0] = entry.getKey().substring(0, entry.getKey().indexOf("@", 0));
          String tempFileName = entry.getKey().substring(entry.getKey().indexOf("@", 0) + 1);
          keys[1] = tempFileName.substring(0, tempFileName.indexOf("@", 0));
          keys[2] = tempFileName.substring(tempFileName.indexOf("@", 0) + 1);
          String srcPath = FileUtil.getFileUploadPath() + File.separator + "process" + File.separator + keys[0] + File.separator + keys[1] + File.separator + keys[2];
          String targetPath = FileUtil.getFileUploadPath() + File.separator + "expire" + File.separator + keys[0] + File.separator + DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMdd") + File.separator + keys[1];
          try {
            FileUtil.move(srcPath, targetPath);
            log.info("上报对象编号:" + keys[0] + ",将过期的文件移到expire过期文件夹下:" + keys[2]);
          } catch (Exception e) {
            log.error("上报对象编号:" + keys[0] + ",将过期的文件移到expire过期文件夹下:" + keys[2] + "失败", e);
          }
          // 清理缓存
          FileConstant.uploadCountMap.remove(entry.getKey());
          FileConstant.againUploadFileMap.remove(entry.getKey());
          FileConstant.readyUploadFileMap.remove(entry.getKey());
          FileConstant.fileShouldMomentMap.remove(entry.getKey());
          FileConstant.fileContentMap.remove(entry.getKey());
        }
      }
    }
    return fileterFileMap;
  }

  /**
   * 获取文件CODE码
   *
   * @return
   */
  public Map<String, Integer> getFileCode() {
    List<UploadFileCode> uploadFileCodeList = uploadFileCodeService.get();
    Map<String, Integer> codeMap = new HashMap<>();
    for (UploadFileCode uploadFileCode : uploadFileCodeList) {
      codeMap.put(uploadFileCode.getFileTypeEnum().toString(), uploadFileCode.getFileTypeCode());
    }
    return codeMap;
  }

  /**
   * 读取excel文件内容转16进制报文
   *
   * @param filePath
   * @return
   */
  public String createFileMessageHexByExcel(String filePath, Logger log) {
    String fileMessageHex = "";
    try (
      FileInputStream inputStream = new FileInputStream(new File(filePath));
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ) {
      Workbook workbook = WorkbookFactory.create(inputStream);
      workbook.write(baos);// 临时存储流到内存
      baos.flush();
      fileMessageHex = ByteUtil.Byte2String(baos.toByteArray());
      fileMessageHex = fileMessageHex.replaceAll(" ", "");
      workbook.close();
    } catch (Exception e) {
      log.error("读取本地文件失败", e);
    }
    return fileMessageHex;
  }
}
