package com.jiayue.ipfcst.fileupload.job;

import com.jiayue.ipfcst.common.core.util.DateTimeUtil;
import com.jiayue.ipfcst.common.data.entity.UploadFileLog;
import com.jiayue.ipfcst.common.data.repository.UploadFileLogRepository;
import com.jiayue.ipfcst.fileupload.service.UploadFileLogService;
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.mock.web.MockMultipartFile;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 将失败的文件重新上传至上报目录
 *
 * @author xsl
 * @version 3.0
 * @since 2020/12/3 9:51
 */
@Slf4j
@Service
@EnableScheduling
public class ErrorFileRepeatJob{
  @Autowired
  UploadFileLogService uploadFileLogService;
  @Autowired
  UploadFileLogRepository uploadFileLogRepository;

  @Scheduled(fixedDelay = 600000)
  public void execute() {
    log.info("失败文件重新上传至上报目录定时开始");

    File destDir = new File(FileUtil.getFileUploadPath() + File.separator + "error");
    if (!destDir.exists()) {// 如果目录不存在则创建目录
      boolean b = destDir.mkdirs();
      if (!b) // 如果创建失败则抛出异常
        throw new RuntimeException(FileUtil.getFileUploadPath() + File.separator + "error" + " 目录创建失败");
    }
    try (Stream<Path> walk = Files.walk(Paths.get(FileUtil.getFileUploadPath() + File.separator + "error"))) {
      List<String> result = walk.filter(Files::isRegularFile)
        .map(x -> x.toString()).collect(Collectors.toList());
      for (String filePath:result) {
        // 如果文件不在正常目录里不处理此文件
        File errorFile = new File(filePath);
        if (!"error".equals(errorFile.getParentFile().getParentFile().getParentFile().getParentFile().getName())){
          continue;
        }
        // 不是今天产生的文件就不用补报了
        if (!DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMdd").equals(errorFile.getParentFile().getParentFile().getName())){
          continue;
        }

        // 根据上报对象编号及文件名查找数据库中是失败状态的才可以重新上传
        String uploadObjectNo = errorFile.getParentFile().getParentFile().getParentFile().getName();
        Long st = DateTimeUtil.getMillisecondsSubDay();
        //明日凌晨
        Long et = DateTimeUtil.getMillisecondsSubDay() + 1000 * 60 * 60 * 24-1;
        UploadFileLog uploadFileLog = uploadFileLogRepository.findByUploadObjectIdAndFileNameAndCreateTimeBetween(Integer.parseInt(uploadObjectNo),errorFile.getName(),new Date(st),new Date(et));
        if (uploadFileLog==null){
          // 日志表中没找到对象下的文件，不处理此文件
          continue;
        }
        if (!"E3".equals(uploadFileLog.getFileStatusEnum().toString())){
          // 日志表中有对象下的文件，但不是上报失败状态的不处理此文件
          continue;
        }
        if (uploadFileLog.getUploadFileEndTime()!=null){
          if (new Date().getTime()>uploadFileLog.getUploadFileEndTime()){
            // 失败的文件超过最后有效时间，移动到expire过期文件夹，不再重新上报
            String targetPath = FileUtil.getFileUploadPath() + File.separator + "expire" + File.separator + uploadObjectNo + File.separator + DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMdd") + File.separator + uploadFileLog.getFileStatusEnum().toString();
            try {
              FileUtil.move(errorFile.getPath(), targetPath);
              log.info("失败定时：上报对象编号:" + uploadObjectNo + ",将过期的文件移到expire过期文件夹下:" + errorFile.getName());
            } catch (Exception e) {
              log.error("失败定时：上报对象编号:" + uploadObjectNo + ",将过期的文件移到expire过期文件夹下:" + errorFile.getName() + "失败", e);
            }
            continue;
          }
        }
        InputStream inputStream = new FileInputStream(errorFile);
        MultipartFile multipartFile = new MockMultipartFile("file",errorFile.getName(),"text/plain", inputStream);
        boolean bo = uploadFileLogService.uploadFile(Integer.parseInt(uploadObjectNo),uploadFileLog.getFileTypeEnum().toString(),multipartFile);
        inputStream.close();
        if (bo){
          // 上传成功，上传error下对象的文件
          errorFile.delete();
          log.info(filePath+"文件重新上传成功");
        }
        else{
          log.info(filePath+"文件重新上传失败");
        }
      }
    } catch (IOException e) {
      log.error("失败文件重新上传出错",e);
    }
    log.info("失败文件重新上传至上报目录定时结束");
  }
}
