package com.jiayue.ipfcst.fileupload.service;

import ch.qos.logback.classic.Logger;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.extra.ftp.FtpConfig;
import cn.hutool.extra.ftp.Ftp;
import cn.hutool.extra.ftp.FtpMode;
import cn.hutool.extra.ssh.JschUtil;
import cn.hutool.extra.ssh.Sftp;
import com.jiayue.ipfcst.common.data.constant.enums.ChannelStatusEnum;
import com.jiayue.ipfcst.common.data.entity.UploadFileChannel;
import com.jiayue.ipfcst.common.data.entity.UploadFileLog;
import com.jiayue.ipfcst.common.data.entity.UploadObject;
import com.jiayue.ipfcst.common.data.entity.UploadURL;
import com.jiayue.ipfcst.common.data.repository.UploadFileLogDetailRepository;
import com.jiayue.ipfcst.common.data.repository.UploadFileLogRepository;
import com.jiayue.ipfcst.common.data.repository.UploadURLRepository;
import com.jiayue.ipfcst.fileupload.config.AppenderFactory;
import com.jiayue.ipfcst.fileupload.util.FileConstant;

import com.jiayue.ipfcst.fileupload.util.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.jcraft.jsch.Session;

import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class FtpUploadService  {
  @Autowired
  UploadFileChannelService uploadFileChannelService;
  @Autowired
  UploadFileLogRepository uploadFileLogRepository;
  @Autowired
  UploadFileLogDetailRepository uploadFileLogDetailRepository;
  @Autowired
  UploadObjectService uploadObjectService;
  @Autowired
  FtpUploadTransactionService ftpUploadTransactionService;
  @Autowired
  AppenderFactory appenderFactory;
  @Autowired
  UploadURLRepository uploadURLRepository;

  /**
   * 开启FTP客户端上报文件
   */
  public void startFtpUpload() {
    Date d = new Date();
    List<UploadObject> uploadObjectList = uploadObjectService.get();
    // 过滤出ftp/sftp的上报对象
    uploadObjectList = uploadObjectList.stream().filter(s -> s.getUploadProtocolEnum().toString().equals("E4") || s.getUploadProtocolEnum().toString().equals("E5")).collect(Collectors.toList());
    if (uploadObjectList.size() > 0) {
      // 获取通道信息
      List<UploadFileChannel> uploadFileChannels = uploadFileChannelService.get();
      // 遍历ftp的上报对象
      for (UploadObject uploadObject : uploadObjectList) {
        //找出可用的ftp通道
        List<UploadFileChannel> uploadFileChannelList = uploadFileChannels.stream().filter(s -> s.getChannelStatusEnum().equals(ChannelStatusEnum.E1) && s.getUploadObjectId().equals(uploadObject.getId())).collect(Collectors.toList());
        // 创建通道对应的日志
        Logger logger = appenderFactory.getLogger(uploadObject.getUploadObjectName(), uploadObject.getUploadProtocolEnum().getMessage(),uploadObject.getObjectNo());

        for (UploadFileChannel uploadFileChannel : uploadFileChannelList) {
          List<UploadURL> uploadURLList = uploadURLRepository.findByUploadChannelId(uploadFileChannel.getId());

          if (uploadObject.getUploadProtocolEnum().toString().equals("E4")){
            // FTP方式上报
            Ftp ftp = null;
            try {
              FtpMode mode = null;
              if ("E1".equals(uploadFileChannel.getFtpPassiveModeEnum().toString())){
                // 主动模式
                mode = FtpMode.Active;
              }
              else{
                // 被动模式
                mode = FtpMode.Passive;
              }

              FtpConfig ftpConfig = new FtpConfig();
              ftpConfig.setHost(uploadFileChannel.getRemoteIp());
              ftpConfig.setPort(Integer.parseInt(uploadFileChannel.getRemotePort()));
              ftpConfig.setPassword(uploadFileChannel.getUploadPassword());
              ftpConfig.setUser(uploadFileChannel.getUploadUserName());
              ftpConfig.setCharset(Charset.forName(uploadObject.getUploadFileCharSetEnum().getMessage()));
              ftpConfig.setConnectionTimeout(5*1000L);
              try {
                ftp = new Ftp(ftpConfig, mode);
                logger.info(uploadFileChannel.getChannelName()+"ftp客户端连接成功");
                // 连接成功，设置通道状态
                FileConstant.channelStatusMap.put(uploadObject.getId() + "-" + uploadFileChannel.getId(), "1");
              }
              catch (Exception e){
                // 连接失败，设置通道状态
                FileConstant.channelStatusMap.put(uploadObject.getId() + "-" + uploadFileChannel.getId(), "0");
                throw e;
              }

              // 获取缓存中的上报文件
              logger.debug("上报文件缓存数量：" + FileConstant.readyUploadFileMap.size());
              Map<String, UploadFileLog> fileMap = new HashMap<>();
              fileMap.putAll(FileConstant.readyUploadFileMap);
              for (Map.Entry<String, UploadFileLog> entry : fileMap.entrySet()) {
                String[] keys = entry.getKey().split("@");
                if (keys[0].equals(uploadObject.getObjectNo())) {
                  // 获取缓存中对应的上报对象的文件
                  logger.info("在缓存中找到通道["+uploadFileChannel.getChannelName()+"]文件："+keys[2]);
                  ftpUploadTransactionService.singleUpload(uploadObject,uploadFileChannel,entry,ftp,null,keys,logger,uploadURLList);
                }
              }
            }
            catch (Exception e){
              logger.error(uploadFileChannel.getChannelName()+"上报失败",e);
//              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 ex) {
//                logger.error("ping对方ip执行失败",ex);
//              }
            }
            finally {
              if (ftp!=null){
                IoUtil.close(ftp);
                logger.info(uploadFileChannel.getChannelName()+"ftp客户端关闭连接");
              }
            }
          }
          else{
            // SFTP方式上报
            Sftp sftp = null;
            try{
              try {
                FtpConfig ftpConfig = new FtpConfig(uploadFileChannel.getRemoteIp(), Integer.parseInt(uploadFileChannel.getRemotePort()), uploadFileChannel.getUploadUserName(), uploadFileChannel.getUploadPassword(), CharsetUtil.CHARSET_UTF_8);
                ftpConfig.setConnectionTimeout(10000L);
                sftp = new Sftp(ftpConfig);
                logger.info(uploadFileChannel.getChannelName()+":sftp连接创建成功");
                // 连接成功，设置通道状态
                FileConstant.channelStatusMap.put(uploadObject.getId() + "-" + uploadFileChannel.getId(), "1");
              }
              catch (Exception e){
                logger.error(uploadFileChannel.getChannelName()+":sftp连接失败",e);
                // 连接失败，设置通道状态
                FileConstant.channelStatusMap.put(uploadObject.getId() + "-" + uploadFileChannel.getId(), "0");
                throw e;
              }
              // 获取缓存中的上报文件
              logger.debug("当前文件缓存数量：" + FileConstant.readyUploadFileMap.size());
              Map<String, UploadFileLog> fileMap = new HashMap<>();
              fileMap.putAll(FileConstant.readyUploadFileMap);
              for (Map.Entry<String, UploadFileLog> entry : fileMap.entrySet()) {
                String[] keys = entry.getKey().split("@");
                UploadFileLog uploadFileLog = entry.getValue();
                if (uploadFileLog.getUploadFileEndTime() == null) {
                  if (keys[0].equals(uploadObject.getObjectNo())) {
                    // 获取缓存中对应的上报对象的文件
                    logger.info("在缓存中找到通道["+uploadFileChannel.getChannelName()+"]文件："+keys[2]+",将文件送入到上报程序中。");
                    ftpUploadTransactionService.singleUpload(uploadObject,uploadFileChannel,entry,null,sftp,keys,logger,uploadURLList);
                  }
                } else {
                  if (d.getTime() <= uploadFileLog.getUploadFileEndTime()) {
                    if (keys[0].equals(uploadObject.getObjectNo())) {
                      // 获取缓存中对应的上报对象的文件
                      logger.info("在缓存中找到通道["+uploadFileChannel.getChannelName()+"]文件："+keys[2]+",将文件送入到上报程序中。");
                      ftpUploadTransactionService.singleUpload(uploadObject,uploadFileChannel,entry,null,sftp,keys,logger,uploadURLList);
                    }
                  } 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 + "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());
                  }
                }

              }
            }
            catch (Exception e){
              logger.error(uploadFileChannel.getChannelName()+"上报失败",e);
            }
            finally {
              if (sftp!=null){
                logger.info("sftp客户端关闭");
                sftp.close();
              }
            }
          }
        }
      }
    }
  }
}
