package com.jiayue.ipfcst.fileupload.service;

import ch.qos.logback.classic.Logger;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.ftp.Ftp;
import cn.hutool.extra.ssh.Sftp;
import com.jiayue.ipfcst.common.core.util.DateTimeUtil;
import com.jiayue.ipfcst.common.data.constant.enums.FileStatusEnum;
import com.jiayue.ipfcst.common.data.constant.enums.ProvinceEnum;
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.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.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.*;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * FTP、SFTP上报类
 *
 * @author xsl
 * @version 3.0
 */
@Service
public class FtpUploadTransactionService extends BaseUploadFileService {
  @Autowired
  UploadFileLogRepository uploadFileLogRepository;
  @Autowired
  UploadFileLogDetailRepository uploadFileLogDetailRepository;


  @Transactional(propagation = Propagation.REQUIRED)
  public void singleUpload(UploadObject uploadObject, UploadFileChannel uploadFileChannel, Map.Entry<String, UploadFileLog> entry, Ftp ftp, Sftp sftp, String[] keys, Logger logger, List<UploadURL> uploadURLList) {

    if (FileConstant.uploadCountMap.get(entry.getKey()) == null) {
      FileMutableInteger fileMutableInteger = new FileMutableInteger(0);
      FileConstant.uploadCountMap.put(entry.getKey(), fileMutableInteger);
    }

    // 上报次数
    Integer fileUploadCount = FileConstant.uploadCountMap.get(entry.getKey()).getValue();
    fileUploadCount++;
    boolean isSuccess = false;
    String srcPath = FileUtil.getFileUploadPath() + File.separator + "process" + File.separator + keys[0] + File.separator + keys[1] + File.separator + keys[2];
    Long st = DateTimeUtil.getMillisecondsSubDay();
    //明日凌晨
    Long et = DateTimeUtil.getMillisecondsSubDay() + 1000 * 60 * 60 * 24 - 1;
    logger.info("准备上报：" + srcPath);
    try {
      if (ftp != null) {
        InputStreamReader isr = null;
        InputStream uploadFileIs = null;
        try {
          isr = new InputStreamReader(new FileInputStream(srcPath), "UTF-8");
          StringBuffer sb = new StringBuffer("");
          int len1 = 0;
          while ((len1 = isr.read()) != -1) {
            sb.append((char) len1);
          }
          isr.close();
          String str = sb.toString();
          uploadFileIs = new ByteArrayInputStream(str.getBytes(uploadObject.getUploadFileCharSetEnum().getMessage()));
          String uploadFileName = new String(new File(srcPath).getName().getBytes(uploadObject.getUploadFileCharSetEnum().getMessage()), uploadObject.getUploadFileCharSetEnum().getMessage());
          // 是否每个文件类型一个路径
          if (StrUtil.hasBlank(uploadFileChannel.getBackupC()) || "0".equals(uploadFileChannel.getBackupC())) {
            // 公用一个路径
            isSuccess = ftp.upload(uploadFileChannel.getPathService(), uploadFileName, uploadFileIs);
          } else {
            // 多路径
            UploadURL uploadURL = uploadURLList.stream().filter(c -> c.getFileTypeEnum().name().equals(keys[1])).collect(Collectors.toList()).get(0);
            isSuccess = ftp.upload(uploadURL.getUploadURL(), uploadFileName, uploadFileIs);
          }
        } catch (Exception e) {
          logger.error("ftp上传失败", e);
          throw e;
        } finally {
          if (isr != null) {
            isr.close();
          }
          if (uploadFileIs != null) {
            uploadFileIs.close();
          }
        }
      } else {
        InputStreamReader isr = null;
        InputStream uploadFileIs = null;
        try {

          //          sftp.getClient().setFilenameEncoding(uploadObject.getUploadFileCharSetEnum().getMessage());
          String uploadFileName = new String(new File(srcPath).getName().getBytes("UTF-8"), uploadObject.getUploadFileCharSetEnum().getMessage());

          // 针对海南业务上报旧文件
          ElectricField electricField = super.getElectricField();

          if (electricField.getProvinceEnum().name().equals(ProvinceEnum.E13.name())&&uploadFileName.indexOf("CSV")>0) {

            FileInputStream inputStream = new FileInputStream(new File(srcPath));
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            Workbook workbook = WorkbookFactory.create(inputStream);
            workbook.write(baos);// 临时存储流到内存

            uploadFileIs = new ByteArrayInputStream(baos.toByteArray());
            baos.flush();
            workbook.close();
            baos.close();
            inputStream.close();

          } else {
            isr = new InputStreamReader(new FileInputStream(srcPath), "UTF-8");
            StringBuffer sb = new StringBuffer("");
            int len1 = 0;
            while ((len1 = isr.read()) != -1) {
              sb.append((char) len1);
            }
            isr.close();
            String str = sb.toString();
            uploadFileIs = new ByteArrayInputStream(str.getBytes(uploadObject.getUploadFileCharSetEnum().getMessage()));
          }



          if ("E46".equals(electricField.getProvinceEnum().toString())) {
            // 海南自动生成日期路径需求
            UploadURL uploadURL = uploadURLList.stream().filter(c -> c.getFileTypeEnum().name().equals(keys[1])).collect(Collectors.toList()).get(0);
            String upPath = uploadURL.getUploadURL();
//            String[] fileNameSplit = keys[2].substring(0, keys[2].indexOf(".")).split("_");
//            String yearStr = fileNameSplit[2].substring(0, 4);
//            String monthDayStr = fileNameSplit[2].substring(4);
            // 用系统时间
            Date systemDate = new Date();
            String yearStr = DateFormatUtils.format(systemDate, "yyyy");
            String monthDayStr = DateFormatUtils.format(systemDate, "MMdd");
            upPath = upPath.replaceAll("DATE_YYYY", yearStr).replaceAll("DATE_MMDD", monthDayStr);
            logger.info("final path:" + upPath);
            sftp.mkDirs(upPath);
            sftp.getClient().put(uploadFileIs, upPath + "/" + uploadFileName);
          } else {
            if (StrUtil.hasBlank(uploadFileChannel.getBackupC()) || "0".equals(uploadFileChannel.getBackupC())) {
              // 公用一个路径
              sftp.getClient().put(uploadFileIs, uploadFileChannel.getPathService() + "/" + uploadFileName);
            } else {
              // 多路径
              UploadURL uploadURL = uploadURLList.stream().filter(c -> c.getFileTypeEnum().name().equals(keys[1])).collect(Collectors.toList()).get(0);
              sftp.getClient().put(uploadFileIs, uploadURL.getUploadURL() + "/" + uploadFileName);
            }
          }
          logger.info("上传远端put结束：" + keys[2]);
          isSuccess = true;
        } catch (Exception e) {
          throw e;
        } finally {
          if (isr != null) {
            isr.close();
          }
          if (uploadFileIs != null) {
            uploadFileIs.close();
          }
        }
      }
    } catch (Exception e) {
      isSuccess = false;
      logger.error("上报通道：" + uploadFileChannel.getChannelName() + "," + keys[2] + "上报失败", e);
      Integer id = FileConstant.fileShouldMomentMap.get(entry.getKey());
      UploadFileLogDetail uploadFileLogDetail = new UploadFileLogDetail();
      uploadFileLogDetail.setUploadObjectName(uploadObject.getUploadObjectName());
      uploadFileLogDetail.setUploadChanneId(uploadFileChannel.getId());
      uploadFileLogDetail.setUploadChannelName(uploadFileChannel.getChannelName());
      uploadFileLogDetail.setUploadFileLogId(id);
      uploadFileLogDetail.setFileName(keys[2]);
      uploadFileLogDetail.setUploadTime(new Date().getTime());
      uploadFileLogDetail.setFileStatusEnum(FileStatusEnum.E3);
      uploadFileLogDetail.setUploadFailureReason(e.getMessage());
      uploadFileLogDetailRepository.save(uploadFileLogDetail);
    } finally {
      logger.info("上报通道：" + keys[0] + "," + keys[2] + "上报次数：" + fileUploadCount);
      try {
        if (isSuccess) {
          // 更新日志表
          FileStatusEnum fileStatusEnum = null;
          if ("1".equals(uploadObject.getUploadD5000())) {
            // 上报给D5000
            fileStatusEnum = FileStatusEnum.E5;
          } else {
            fileStatusEnum = FileStatusEnum.E2;
          }
          Integer id = FileConstant.fileShouldMomentMap.get(entry.getKey());
          uploadFileLogRepository.uploadFileUpdate(fileStatusEnum, fileUploadCount, id);
          String targetPath = FileUtil.getFileUploadPath() + File.separator + "backups" + File.separator + DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMdd") + File.separator + keys[0] + File.separator + keys[1];
          logger.info("移动文件至" + targetPath);
          FileUtil.move(srcPath, targetPath);
          logger.info("上报通道：" + keys[0] + ",文件：" + keys[0] + "上报成功,移动到backups目录");
//          UploadFileLog uploadFileLog = uploadFileLogRepository.findById(id).get();
          UploadFileLogDetail uploadFileLogDetail = new UploadFileLogDetail();
          uploadFileLogDetail.setUploadObjectName(uploadObject.getUploadObjectName());
          uploadFileLogDetail.setUploadFileLogId(id);
          uploadFileLogDetail.setUploadTime(System.currentTimeMillis());
          uploadFileLogDetail.setFileName(keys[2]);
          uploadFileLogDetail.setUploadChanneId(uploadFileChannel.getId());
          uploadFileLogDetail.setUploadChannelName(uploadFileChannel.getChannelName());
          uploadFileLogDetail.setFileStatusEnum(fileStatusEnum);
          uploadFileLogDetailRepository.save(uploadFileLogDetail);

          // 上传成功，删除缓存里的文件
          FileConstant.readyUploadFileMap.remove(entry.getKey());
          FileConstant.uploadCountMap.remove(entry.getKey());
          FileConstant.fileShouldMomentMap.remove(entry.getKey());
        } else {
          logger.info("上报失败。。。。。。。。。。。。。");
//          try {
//            Process process = Runtime.getRuntime().exec("ping "+uploadFileChannel.getRemoteIp() + " -c 2");
//            InputStreamReader r = new InputStreamReader(process.getInputStream());
//            LineNumberReader returnData = new LineNumberReader(r);
//
//            String returnMsg="";
//            String line = "";
//            while ((line = returnData.readLine()) != null) {
//              returnMsg += line;
//            }
//
//            if(returnMsg.indexOf("100% loss")!=-1){
//              logger.info("与 " +uploadFileChannel.getRemoteIp() +" 连接不畅通.");
//            }
//            else{
//              logger.info("与 " +uploadFileChannel.getRemoteIp() +" 连接畅通.");
//            }
//
//            returnData.close();
//            r.close();
//            process.getInputStream().close();
//            process.getOutputStream().close();
//            process.destroy();
//
//          } catch (IOException e) {
//            logger.error("ping对方ip执行失败",e);
//          }
          // 更新日志表
          FileStatusEnum fileStatusEnum = null;
          if ("1".equals(uploadObject.getUploadD5000())) {
            // 上报给D5000
            fileStatusEnum = FileStatusEnum.E6;
          } else {
            fileStatusEnum = FileStatusEnum.E3;
          }
          Integer id = FileConstant.fileShouldMomentMap.get(entry.getKey());
          uploadFileLogRepository.uploadFileUpdate(fileStatusEnum, fileUploadCount, id);
//          uploadFileLogRepository.updateFileUploadCount(fileStatusEnum, fileUploadCount, uploadObject.getId(), keys[2]);
//          String fileMaxCount = super.getSysParameter("FILE_MAX_COUNT", "3");
//          // 上报失败
//          if (fileUploadCount >= Integer.parseInt(fileMaxCount)) {
          logger.info("上报通道：" + keys[0] + "," + "移动到error目录");
          String targetPath = FileUtil.getFileUploadPath() + File.separator + "error" + File.separator + DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMdd") + File.separator + keys[0] + File.separator + keys[1];
          FileUtil.move(srcPath, targetPath);
          FileConstant.readyUploadFileMap.remove(entry.getKey());
          FileConstant.fileShouldMomentMap.remove(entry.getKey());
          FileConstant.uploadCountMap.remove(entry.getKey());
//          } else {
//            FileMutableInteger fileMutableInteger = new FileMutableInteger(fileUploadCount);
//            FileConstant.uploadCountMap.put(entry.getKey(), fileMutableInteger);
//          }
        }
      } catch (Exception e) {
        logger.error("sftp上报后finally里异常", e);
      }
    }
  }

  public void mkdirDir(String[] dirs, String tempPath, int length, int index, Sftp sftp) {
    // 以"/a/b/c/d"为例按"/"分隔后,第0位是"";顾下标从1开始
    index++;
    if (index < length) {
      // 目录不存在，则创建文件夹
      tempPath += "/" + dirs[index];
    }
    try {
      if (sftp.exist(tempPath)) {
        if (index < length) {
          mkdirDir(dirs, tempPath, length, index, sftp);
        }
      } else {
        try {
          sftp.mkdir(tempPath);
          sftp.cd(tempPath);
        } catch (Exception e) {
          e.printStackTrace();
        }
        mkdirDir(dirs, tempPath, length, index, sftp);
      }
    } catch (Exception ex) {
      try {
        sftp.mkdir(tempPath);
        sftp.cd(tempPath);
      } catch (Exception e) {
        e.printStackTrace();
      }
      mkdirDir(dirs, tempPath, length, index, sftp);
    }
  }
}
