package com.qmth.distributed.print.business.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfReader;
import com.qmth.boot.api.exception.ApiException;
import com.qmth.boot.tools.models.ByteArray;
import com.qmth.distributed.print.business.bean.dto.PdfDto;
import com.qmth.distributed.print.business.bean.params.SerialNumberParams;
import com.qmth.distributed.print.business.entity.*;
import com.qmth.distributed.print.business.enums.ExamDetailStatusEnum;
import com.qmth.distributed.print.business.enums.PrintPlanStatusEnum;
import com.qmth.distributed.print.business.service.*;
import com.qmth.distributed.print.business.util.HtmlToPdfUtil;
import com.qmth.distributed.print.business.util.PdfUtil;
import com.qmth.teachcloud.common.bean.dto.MqDto;
import com.qmth.teachcloud.common.bean.params.ArraysParams;
import com.qmth.teachcloud.common.config.DictionaryConfig;
import com.qmth.teachcloud.common.contant.SpringContextHolder;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.*;
import com.qmth.teachcloud.common.enums.*;
import com.qmth.teachcloud.common.mapper.BasicCourseMapper;
import com.qmth.teachcloud.common.service.*;
import com.qmth.teachcloud.common.util.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @Description: 公共服务service impl
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2021/3/26
 */
@Service
public class PrintCommonServiceImpl implements PrintCommonService {
    private final static Logger log = LoggerFactory.getLogger(PrintCommonServiceImpl.class);

//    @Resource
//    OssUtil ossUtil;

    @Autowired
    private DictionaryConfig dictionaryConfig;

    @Resource
    BasicAttachmentService basicAttachmentService;

    @Autowired
    @Lazy
    private ExamTaskService examTaskService;

    @Resource
    private BasicCourseMapper basicCourseMapper;

    @Resource
    BasicCourseService basicCourseService;

    @Resource
    ExamDetailCourseService examDetailCourseService;

    @Resource
    SysOrgService sysOrgService;

    @Autowired
    private SysUserService sysUserService;

    @Resource
    BasicTemplateOrgService basicTemplateOrgService;

    @Resource
    TBTaskService tbTaskService;

    @Resource
    TBSyncTaskService tbSyncTaskService;

    @Resource
    ExamDetailService examDetailService;

    @Autowired
    private ConvertUtil convertUtil;

    @Resource
    @Lazy
    ExamTaskDetailService examTaskDetailService;

    @Resource
    ExamPrintPlanService examPrintPlanService;

    @Resource
    TFFlowApproveService tfFlowApproveService;

    @Resource
    private FileStoreUtil fileStoreUtil;

    @Resource
    TeachcloudCommonService teachcloudCommonService;

    @Resource
    ExamStudentService examStudentService;

    @Resource
    RedisUtil redisUtil;

    @Autowired
    BasicSchoolService basicSchoolService;

    @Autowired
    BasicExamService basicExamService;

    @Resource
    GradeBatchService gradeBatchService;

    @Resource
    GradeBatchPaperService gradeBatchPaperService;

    @Resource
    GradeModuleEvaluationService gradeModuleEvaluationService;

    /**
     * 保存附件
     *
     * @param classifyEnum
     * @param examDetail
     * @param basicAttachment
     * @param pdfList
     * @param printCount
     * @param sequence
     * @return
     * @throws IOException
     */
    @Override
    @Transactional
    public BasicAttachment saveAttachmentPdf(ClassifyEnum classifyEnum, ExamDetail examDetail, BasicAttachment basicAttachment, List<PdfDto> pdfList, Integer printCount, Integer sequence) throws IOException, DocumentException {
        try {
            BasicSchool basicSchool = basicSchoolService.getById(examDetail.getSchoolId());
            Map<String, List<String>> flowSchoolCodeMap = SystemConstant.getFlowSchoolCodeMap();

            boolean oss = dictionaryConfig.sysDomain().isOss();
            JSONObject jsonObject = JSONObject.parseObject(basicAttachment.getPath());
            String type = basicAttachment.getType();
            String filePath = null;
            String url = null;
            File htmlFile = null;
            if (Objects.nonNull(type) && Objects.equals(type, SystemConstant.FTL_PREFIX)) {
                filePath = (String) jsonObject.get(SystemConstant.HTML_PATH);
                if (filePath.contains(SystemConstant.TEMP_FILES_DIR)) {
                    url = filePath;
                } else {
                    url = SystemConstant.TEMP_FILES_DIR + File.separator + filePath;
                }
                htmlFile = new File(url);
            } else if (Objects.nonNull(type) && Objects.equals(type, SystemConstant.HTML_PREFIX)) {
                filePath = (String) jsonObject.get(SystemConstant.PATH);
                if (filePath.contains(SystemConstant.TEMP_FILES_DIR)) {
                    url = filePath;
                } else {
                    url = SystemConstant.TEMP_FILES_DIR + File.separator + filePath;
                }
                UploadFileEnum uploadType = Enum.valueOf(UploadFileEnum.class, (String) jsonObject.get(SystemConstant.UPLOAD_TYPE));
//                htmlFile = ossUtil.ossDownload(filePath, url);
                if (oss) {
                    htmlFile = fileStoreUtil.ossDownload(filePath, url, uploadType.getFssType());
                } else {
                    htmlFile = new File(filePath);
                }
            }
            LocalDateTime nowTime = LocalDateTime.now();
            StringJoiner pdfStringJoiner = new StringJoiner("");
            pdfStringJoiner.add(UploadFileEnum.PDF.getTitle()).add(File.separator);
            pdfStringJoiner.add(String.valueOf(nowTime.getYear())).add(File.separator)
                    .add(String.format("%02d", nowTime.getMonthValue())).add(File.separator)
                    .add(String.format("%02d", nowTime.getDayOfMonth()));
            pdfStringJoiner.add(File.separator).add(SystemConstant.getUuid()).add(SystemConstant.PDF_PREFIX);

            String pdfDirName = pdfStringJoiner.toString();
            String pdfDirNameStr = pdfStringJoiner.toString().replace("\\", "/");
            String destUrl = SystemConstant.PDF_TEMP_FILES_DIR + File.separator + pdfDirName;

            File pdfFile = new File(destUrl);
            if (!pdfFile.exists()) {
                pdfFile.getParentFile().mkdirs();
                pdfFile.createNewFile();
            }
            if (flowSchoolCodeMap.get(SystemConstant.GDYKDX_FLOW_KEY).contains(basicSchool.getCode())) {
                HtmlToPdfUtil.convert(htmlFile.getPath(), destUrl, PageSizeEnum.A3);
            } else if (flowSchoolCodeMap.get(SystemConstant.JXZYY_FLOW_KEY).contains(basicSchool.getCode())) {
                HtmlToPdfUtil.convert(htmlFile.getPath(), destUrl, PageSizeEnum.A4);
            } else {
                HtmlToPdfUtil.convert(htmlFile.getPath(), destUrl, PageSizeEnum.A4);
            }

//            File pdfFile = asposePdfUtil.documentToPdf(htmlFile.getPath(), destUrl, PaperSize.A4);
            String htmlFileMd5 = DigestUtils.md5Hex(new FileInputStream(htmlFile));
            byte[] data = ByteArray.fromFile(pdfFile).value();
            String md5 = ByteArray.md5(data).toHexString();
            InputStream ins = new ByteArrayInputStream(data);
            //String pdfFileMd5 = DigestUtils.md5Hex(new FileInputStream(pdfFile));
            PdfDto pdfDto = PdfUtil.addPdfPage(pdfFile);
            if (oss) {//上传至oss
                fileStoreUtil.ossUpload(pdfDirNameStr, ins, md5, fileStoreUtil.getUploadEnumByPath(pdfDirNameStr).getFssType());
//                htmlFile.delete();
                ins.close();
            }
            JSONObject attachmentPath = JSONObject.parseObject(examDetail.getAttachmentPath());
            attachmentPath = Objects.isNull(attachmentPath) ? new JSONObject() : attachmentPath;
            JSONArray jsonArray = (JSONArray) attachmentPath.get(SystemConstant.PATH);
            jsonArray = Objects.isNull(jsonArray) ? new JSONArray() : jsonArray;
            JSONObject object = new JSONObject();
            object.put("printType", classifyEnum.name());
            object.put(SystemConstant.HTML_PATH, filePath);
            object.put("htmlMd5", htmlFileMd5);
            object.put("pdfMd5", md5);
            if (!oss) {
                object.put(SystemConstant.PDF_PATH, pdfFile.getPath());
                object.put(SystemConstant.TYPE, SystemConstant.LOCAL);
            } else {
                object.put(SystemConstant.PDF_PATH, pdfDirNameStr);
                object.put(SystemConstant.TYPE, SystemConstant.OSS);
            }
            object.put(SystemConstant.UPLOAD_TYPE, new UploadFileEnum[]{
                    UploadFileEnum.HTML,
                    UploadFileEnum.PDF
            });
            jsonArray.add(object);
            attachmentPath.put(SystemConstant.PATH, jsonArray);
            examDetail.setAttachmentPath(attachmentPath.toJSONString());
            basicAttachment.setPages(pdfDto.getActualPageCount());
            for (int i = 0; i < printCount; i++) {
                if (flowSchoolCodeMap.get(SystemConstant.GDYKDX_FLOW_KEY).contains(basicSchool.getCode())) {
                    pdfList.add(new PdfDto(pdfFile.getPath(), PageSizeEnum.A3, pdfDto.getPageCount(), sequence));
                } else if (flowSchoolCodeMap.get(SystemConstant.JXZYY_FLOW_KEY).contains(basicSchool.getCode())) {
                    pdfList.add(new PdfDto(pdfFile.getPath(), PageSizeEnum.A4, pdfDto.getPageCount(), sequence));
                } else {
                    pdfList.add(new PdfDto(pdfFile.getPath(), PageSizeEnum.A4, pdfDto.getPageCount(), sequence));
                }
            }
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return basicAttachment;
    }

    /**
     * 保存html附件
     *
     * @param fileName
     * @param htmlContent
     * @param userId
     * @param localFileList
     * @return
     * @throws IOException
     */
    @Override
    @Transactional
    public BasicAttachment saveAttachmentHtml(String fileName, String htmlContent, Long userId, List<PdfDto> localFileList) throws IOException {
        BasicAttachment basicAttachment = null;
        PdfDto pdfDto = null;
        try {
            byte[] bytes = htmlContent.getBytes();
            int size = bytes.length;
            boolean oss = dictionaryConfig.sysDomain().isOss();
            LocalDateTime nowTime = LocalDateTime.now();
            StringJoiner stringJoiner = new StringJoiner("");
            if (!oss) {
                stringJoiner.add(SystemConstant.TEMP_FILES_DIR).add(File.separator);
            }
            stringJoiner.add(UploadFileEnum.HTML.getTitle()).add(File.separator)
                    .add(String.valueOf(nowTime.getYear())).add(File.separator)
                    .add(String.format("%02d", nowTime.getMonthValue())).add(File.separator)
                    .add(String.format("%02d", nowTime.getDayOfMonth()));

            JSONObject jsonObject = new JSONObject();
            stringJoiner.add(File.separator).add(SystemConstant.getUuid()).add(SystemConstant.HTML_PREFIX);
            String fileMd5 = null;
            if (oss) {//上传至oss
                String dirName = stringJoiner.toString().replaceAll("\\\\", "/");
//                ossUtil.ossUpload(dirName, htmlContent);
                fileStoreUtil.ossUpload(dirName, htmlContent, fileStoreUtil.getUploadEnumByPath(dirName).getFssType());
                jsonObject.put(SystemConstant.TYPE, SystemConstant.OSS);
                jsonObject.put(SystemConstant.PATH, dirName);
                String url = SystemConstant.TEMP_FILES_DIR + File.separator + dirName;
//                File localHtmlFile = ossUtil.ossDownload(dirName, url);
                File localHtmlFile = fileStoreUtil.ossDownload(dirName, url, fileStoreUtil.getUploadEnumByPath(dirName).getFssType());
                StringJoiner pdfStringJoiner = new StringJoiner("");
                pdfStringJoiner.add(UploadFileEnum.PDF.getTitle()).add(File.separator);
                pdfStringJoiner.add(String.valueOf(nowTime.getYear())).add(File.separator)
                        .add(String.format("%02d", nowTime.getMonthValue())).add(File.separator)
                        .add(String.format("%02d", nowTime.getDayOfMonth()));
                pdfStringJoiner.add(File.separator).add(SystemConstant.getUuid()).add(SystemConstant.PDF_PREFIX);

                String pdfDirName = pdfStringJoiner.toString();
                String destUrl = SystemConstant.PDF_TEMP_FILES_DIR + File.separator + pdfDirName;
//                destUrl = destUrl.replaceAll("\\\\","/");

                HtmlToPdfUtil.convert(localHtmlFile.getPath(), destUrl, PageSizeEnum.A3);
//                File pdfFile = asposePdfUtil.documentToPdf(localHtmlFile.getPath(), destUrl, PaperSize.A3);
                File pdfFile = new File(destUrl);
                if (!pdfFile.exists()) {
                    pdfFile.getParentFile().mkdirs();
                    pdfFile.createNewFile();
                }
                pdfDto = PdfUtil.addPdfPage(pdfFile);
                localFileList.add(new PdfDto(pdfFile.getPath(), PageSizeEnum.A3, pdfDto.getPageCount()));
                fileMd5 = DigestUtils.md5Hex(new FileInputStream(pdfFile));
//                ossUtil.ossUpload(pdfDirName, pdfFile, BinaryUtil.toBase64String(HexUtils.decodeHex(fileMd5)));
                pdfDirName = pdfDirName.replaceAll("\\\\", "/");
                fileStoreUtil.ossUpload(pdfDirName, pdfFile, BinaryUtil.toBase64String(HexUtils.decodeHex(fileMd5)), fileStoreUtil.getUploadEnumByPath(pdfDirName).getFssType());
//                localHtmlFile.delete();
                jsonObject.put(SystemConstant.PDF_PATH, pdfDirName);
                // htmlMd5
                jsonObject.put("htmlMd5", DigestUtils.md5Hex(new FileInputStream(localHtmlFile)));
                jsonObject.put("pdfMd5", fileMd5);
            } else {//上传至服务器
                File finalFile = new File(stringJoiner.toString());
                if (!finalFile.exists()) {
                    finalFile.getParentFile().mkdirs();
                    finalFile.createNewFile();
                }
                FileCopyUtils.copy(bytes, new File(stringJoiner.toString()));
                jsonObject.put(SystemConstant.TYPE, SystemConstant.LOCAL);
                jsonObject.put(SystemConstant.PATH, stringJoiner.toString());
                String destUrl = finalFile.getPath().replaceAll(UploadFileEnum.HTML.name().toLowerCase(), UploadFileEnum.PDF.name().toLowerCase());
                HtmlToPdfUtil.convert(finalFile.getPath(), destUrl, PageSizeEnum.A3);
                File pdfFile = new File(destUrl);
                if (!pdfFile.exists()) {
                    pdfFile.getParentFile().mkdirs();
                    pdfFile.createNewFile();
                }
                pdfDto = PdfUtil.addPdfPage(pdfFile);
                fileMd5 = DigestUtils.md5Hex(new FileInputStream(pdfFile));
                localFileList.add(new PdfDto(pdfFile.getPath(), PageSizeEnum.A3, pdfDto.getPageCount()));

                jsonObject.put(SystemConstant.PDF_PATH, destUrl);
                jsonObject.put("htmlMd5", DigestUtils.md5Hex(new FileInputStream(finalFile)));
                jsonObject.put("pdfMd5", fileMd5);
            }
            jsonObject.put(SystemConstant.UPLOAD_TYPE, new UploadFileEnum[]{
                    UploadFileEnum.HTML, UploadFileEnum.PDF
            });
            basicAttachment = new BasicAttachment(jsonObject.toJSONString(), fileName, SystemConstant.HTML_PREFIX, new BigDecimal(size), fileMd5, userId);
            basicAttachment.setPages(pdfDto.getActualPageCount());
            basicAttachmentService.save(basicAttachment);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            basicAttachmentService.deleteAttachment(basicAttachment);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return basicAttachment;
    }

    /**
     * 保存html附件和该html转成pdf的附件
     *
     * @param fileName    文件名称
     * @param htmlContent html内容
     * @param userId      创建人
     * @return 两个附件对象
     */
    @Transactional
    @Override
    public BasicAttachment saveAttachmentHtmlAndPdf(String fileName, String htmlContent, Long userId) {
        BasicAttachment basicAttachment = null;
        try {
            byte[] bytes = htmlContent.getBytes();
            int size = bytes.length;
            boolean oss = dictionaryConfig.sysDomain().isOss();
            LocalDateTime nowTime = LocalDateTime.now();
            StringJoiner stringJoiner = new StringJoiner("");
            if (!oss) {
                stringJoiner.add(SystemConstant.TEMP_FILES_DIR).add(File.separator);
            }
            stringJoiner.add(UploadFileEnum.HTML.getTitle()).add(File.separator)
                    .add(String.valueOf(nowTime.getYear())).add(File.separator)
                    .add(String.format("%02d", nowTime.getMonthValue())).add(File.separator)
                    .add(String.format("%02d", nowTime.getDayOfMonth()));

            JSONObject jsonObject = new JSONObject();
            stringJoiner.add(File.separator).add(SystemConstant.getUuid()).add(SystemConstant.HTML_PREFIX);
            String fileMd5 = null;

            if (oss) {//上传至oss
                String dirName = stringJoiner.toString().replaceAll("\\\\", "/");
                fileStoreUtil.ossUpload(dirName, htmlContent, fileStoreUtil.getUploadEnumByPath(dirName).getFssType());
                jsonObject.put(SystemConstant.TYPE, SystemConstant.OSS);
                jsonObject.put(SystemConstant.PATH, dirName);
                String url = SystemConstant.TEMP_FILES_DIR + File.separator + dirName;
                File localHtmlFile = fileStoreUtil.ossDownload(dirName, url, fileStoreUtil.getUploadEnumByPath(dirName).getFssType());
                StringJoiner pdfStringJoiner = new StringJoiner("");
                pdfStringJoiner.add(UploadFileEnum.PDF.getTitle()).add(File.separator);
                pdfStringJoiner.add(String.valueOf(nowTime.getYear())).add(File.separator)
                        .add(String.format("%02d", nowTime.getMonthValue())).add(File.separator)
                        .add(String.format("%02d", nowTime.getDayOfMonth()));
                pdfStringJoiner.add(File.separator).add(SystemConstant.getUuid()).add(SystemConstant.PDF_PREFIX);

                String pdfDirName = pdfStringJoiner.toString();
                String destUrl = SystemConstant.PDF_TEMP_FILES_DIR + File.separator + pdfDirName;
//                destUrl = destUrl.replaceAll("\\\\","/");

                HtmlToPdfUtil.convert(localHtmlFile.getPath(), destUrl, PageSizeEnum.A4);
//                File pdfFile = asposePdfUtil.documentToPdf(localHtmlFile.getPath(), destUrl, PaperSize.A3);
                File pdfFile = new File(destUrl);
                if (!pdfFile.exists()) {
                    pdfFile.getParentFile().mkdirs();
                    pdfFile.createNewFile();
                }
                fileMd5 = DigestUtils.md5Hex(new FileInputStream(pdfFile));
//                ossUtil.ossUpload(pdfDirName, pdfFile, BinaryUtil.toBase64String(HexUtils.decodeHex(fileMd5)));
                pdfDirName = pdfDirName.replaceAll("\\\\", "/");
                fileStoreUtil.ossUpload(pdfDirName, pdfFile, BinaryUtil.toBase64String(HexUtils.decodeHex(fileMd5)), fileStoreUtil.getUploadEnumByPath(pdfDirName).getFssType());
//                localHtmlFile.delete();
                jsonObject.put(SystemConstant.PDF_PATH, pdfDirName);
                // htmlMd5
                jsonObject.put("htmlMd5", DigestUtils.md5Hex(new FileInputStream(localHtmlFile)));
                jsonObject.put("pdfMd5", fileMd5);
            } else {//上传至服务器
                File finalFile = new File(stringJoiner.toString());
                if (!finalFile.exists()) {
                    finalFile.getParentFile().mkdirs();
                    finalFile.createNewFile();
                }
                FileCopyUtils.copy(bytes, new File(stringJoiner.toString()));
                fileMd5 = DigestUtils.md5Hex(new FileInputStream(stringJoiner.toString()));
                jsonObject.put(SystemConstant.TYPE, SystemConstant.LOCAL);
                jsonObject.put(SystemConstant.PATH, stringJoiner.toString());
                String destUrl = finalFile.getPath().replaceAll(UploadFileEnum.HTML.name().toLowerCase(), UploadFileEnum.PDF.name().toLowerCase());
                HtmlToPdfUtil.convert(finalFile.getPath(), destUrl, PageSizeEnum.A3);
                File pdfFile = new File(destUrl);
                if (!pdfFile.exists()) {
                    pdfFile.getParentFile().mkdirs();
                    pdfFile.createNewFile();
                }
                fileMd5 = DigestUtils.md5Hex(new FileInputStream(pdfFile));

                jsonObject.put(SystemConstant.PDF_PATH, destUrl);
                jsonObject.put("htmlMd5", DigestUtils.md5Hex(new FileInputStream(finalFile)));
                jsonObject.put("pdfMd5", fileMd5);
            }
            jsonObject.put(SystemConstant.UPLOAD_TYPE, new UploadFileEnum[]{
                    UploadFileEnum.HTML, UploadFileEnum.PDF
            });
            basicAttachment = new BasicAttachment(jsonObject.toJSONString(), fileName, SystemConstant.HTML_PREFIX, new BigDecimal(size), fileMd5, userId);
            basicAttachmentService.save(basicAttachment);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            basicAttachmentService.deleteAttachment(basicAttachment);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return basicAttachment;
    }

    /**
     * 保存附件公用
     *
     * @param file
     * @param md5
     * @param type
     * @param objId
     * @return
     */
    @Override
    public BasicAttachment saveAttachmentCommon(MultipartFile file, String md5, UploadFileEnum type, Long objId) {
        if (Objects.isNull(type)) {
            throw ExceptionResultEnum.ATTACHMENT_TYPE_EMPTY.exception();
        }
        BasicAttachment basicAttachment = null;
        try {
            SysUser requestUser = (SysUser) ServletUtil.getRequestUser();
            int temp = file.getOriginalFilename().lastIndexOf(".");
            String fileName = file.getOriginalFilename().substring(0, temp);
            String format = file.getOriginalFilename().substring(temp, file.getOriginalFilename().length());
            List<String> attachmentTypeList = dictionaryConfig.sysDomain().getAttachmentType();
            if (Objects.nonNull(format)) {
                long count = attachmentTypeList.stream().filter(s -> format.equalsIgnoreCase(s)).count();
                if (count == 0) {
                    throw ExceptionResultEnum.ERROR.exception("文件格式只能为" + attachmentTypeList.toString());
                }
            }
            int attachmentLength = dictionaryConfig.sysDomain().getAttachmentLength().intValue();
            if (Objects.nonNull(fileName) && fileName.length() > attachmentLength) {
                throw ExceptionResultEnum.ERROR.exception("文件名长度不能超过" + attachmentLength + "个字符");
            }
            long size = file.getSize();
            BigDecimal b = new BigDecimal(size);
            BigDecimal num = new BigDecimal(1024);
            b = b.divide(num, 2, BigDecimal.ROUND_HALF_UP).divide(num, 2, BigDecimal.ROUND_HALF_UP)
                    .setScale(2, BigDecimal.ROUND_HALF_UP);
            double attachmentSize = dictionaryConfig.sysDomain().getAttachmentSize().doubleValue();
            if (b.doubleValue() > attachmentSize) {
                throw ExceptionResultEnum.ERROR.exception("文件大小不能超过" + attachmentSize + "MB");
            }
            log.info("fileName:{}", fileName);
            log.info("format:{}", format);
            log.info("size:{}", b);
            log.info("getOriginalFilename:{}", file.getOriginalFilename());
            String fileMd5 = DigestUtils.md5Hex(file.getBytes());
            log.info("fileMd5:{}", fileMd5);
            log.info("md5:{}", md5);
            if (!Objects.equals(fileMd5, md5)) {
                throw ExceptionResultEnum.MD5_EQUALS_FALSE.exception();
            }
            boolean oss = dictionaryConfig.sysDomain().isOss();
            LocalDateTime nowTime = LocalDateTime.now();
            StringJoiner stringJoiner = new StringJoiner("");
            if (!oss) {
                stringJoiner.add(SystemConstant.TEMP_FILES_DIR).add(File.separator);
            }
            stringJoiner.add(type.getTitle()).add(File.separator);
//            else if (type == UploadFileEnum.PAPER) {//试卷需要单独
//                stringJoiner.add(type.getTitle()).add(File.separator);
//            } else if (type == UploadFileEnum.UPLOAD) {
//                stringJoiner.add(type.getTitle()).add(File.separator);
//            }
            stringJoiner.add(String.valueOf(nowTime.getYear())).add(File.separator)
                    .add(String.format("%02d", nowTime.getMonthValue())).add(File.separator)
                    .add(String.format("%02d", nowTime.getDayOfMonth()));

            JSONObject jsonObject = new JSONObject();
            stringJoiner.add(File.separator).add(SystemConstant.getUuid()).add(format);
            if (oss) {//上传至oss\
                String dirName = stringJoiner.toString().replaceAll("\\\\", "/");
                fileStoreUtil.ossUpload(dirName, file.getInputStream(), md5, type.getFssType());

                jsonObject.put(SystemConstant.TYPE, SystemConstant.OSS);
                jsonObject.put(SystemConstant.PATH, dirName);
            } else {//上传至服务器
                File finalFile = new File(stringJoiner.toString());
                if (!finalFile.exists()) {
                    finalFile.getParentFile().mkdirs();
                    finalFile.createNewFile();
                }
                FileUtils.copyInputStreamToFile(file.getInputStream(), finalFile);
                jsonObject.put(SystemConstant.TYPE, SystemConstant.LOCAL);
                jsonObject.put(SystemConstant.PATH, stringJoiner.toString());
            }
            jsonObject.put(SystemConstant.UPLOAD_TYPE, type);

            basicAttachment = new BasicAttachment(jsonObject.toJSONString(), fileName, format, b, fileMd5, requestUser.getId(), objId);
            basicAttachmentService.save(basicAttachment);

            // pdf需要读取总页数
            Integer pages = 0;
            if (".pdf".equals(format)) {
                PdfReader pdfReader = new PdfReader(file.getBytes());
                pages = pdfReader.getNumberOfPages();
            }
            basicAttachment.setPages(pages);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            basicAttachmentService.deleteAttachment(basicAttachment);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return basicAttachment;
    }

    /**
     * 保存附件
     *
     * @param file
     * @param md5
     * @param type
     * @return
     */
    @Override
    @Transactional
    public BasicAttachment saveAttachment(MultipartFile file, String md5, UploadFileEnum type) {
        return saveAttachmentCommon(file, md5, type, null);
    }

    /**
     * 保存附件
     *
     * @param file
     * @param md5
     * @param type
     * @param objId
     * @return
     */
    @Override
    @Transactional
    public BasicAttachment saveAttachment(MultipartFile file, String md5, UploadFileEnum type, Long objId) {
        return saveAttachmentCommon(file, md5, type, objId);
    }

    /**
     * 科目删除
     *
     * @param id
     * @return
     */
    @Override
    public boolean remove(Long id) {
        // code是否已有命题任务
        BasicCourse course = basicCourseMapper.selectById(id);
        List<ExamTask> taskList = examTaskService.listByCourseCode(course.getSchoolId(), course.getCode());
        if (taskList != null && taskList.size() > 0) {
            throw ExceptionResultEnum.ERROR.exception("课程绑定命题任务，不能删除");
        }
        return basicCourseService.removeById(id);
    }

    /**
     * 保存科目
     *
     * @param course
     * @param userId
     * @return
     */
    @Override
    public boolean saveCourse(BasicCourse course, Long userId) {
        Long schoolId = course.getSchoolId();
        course.setSchoolId(schoolId);

        QueryWrapper<BasicCourse> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(BasicCourse::getSchoolId, course.getSchoolId()).eq(BasicCourse::getCode, course.getCode());
        BasicCourse basicCourse = basicCourseService.getOne(queryWrapper);

        // 新增
        if (Objects.isNull(course.getId())) {
            if (basicCourse != null) {
                throw ExceptionResultEnum.ERROR.exception("课程已存在");
            }
            course.setId(SystemConstant.getDbUuid());
            course.setCreateId(userId);
            course.setCreateTime(System.currentTimeMillis());
        }
        // 修改
        else {
            if (basicCourse != null && basicCourse.getId().longValue() != course.getId().longValue()) {
                throw ExceptionResultEnum.ERROR.exception("课程已存在");
            }

            // 旧code是否已有命题任务
            BasicCourse oldCourse = basicCourseService.getById(course.getId());
            List<ExamTask> taskList = examTaskService.listByCourseCode(oldCourse.getSchoolId(), oldCourse.getCode());
            if (taskList != null && taskList.size() > 0) {
                throw ExceptionResultEnum.ERROR.exception("课程绑定命题任务，不能修改");
            }
            course.setUpdateId(userId);
            course.setUpdateTime(System.currentTimeMillis());
        }
        return basicCourseService.saveOrUpdate(course);
    }

    /**
     * 分页查询
     *
     * @param code
     * @param name
     * @param pageNumber
     * @param pageSize
     * @return
     */
    @Override
    public IPage<BasicCourse> list(String code, String name, Integer pageNumber, Integer pageSize) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        code = SystemConstant.translateSpecificSign(code);
        name = SystemConstant.translateSpecificSign(name);
        Page<BasicCourse> page = new Page<>(pageNumber, pageSize);
        IPage<BasicCourse> courseIPage = basicCourseMapper.listPage(page, schoolId, SystemConstant.translateSpecificSign(code), SystemConstant.translateSpecificSign(name));
        return courseIPage;
    }

    /**
     * 科目查询
     *
     * @param param
     * @param printPlanIdList
     * @return
     */
    @Override
    public List<BasicCourse> list(String param, List<Long> printPlanIdList, Long teachingRoomId) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        Set<Long> orgIds = teachcloudCommonService.listSubOrgIds(teachingRoomId);
        if (printPlanIdList.size() == 0) {
            QueryWrapper<BasicCourse> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(BasicCourse::getSchoolId, schoolId)
                    .eq(BasicCourse::getEnable, true)
                    .in(BasicCourse::getTeachingRoomId, orgIds);
            if (StringUtils.isNotBlank(param)) {
                queryWrapper.lambda().and(i -> i.like(BasicCourse::getCode, SystemConstant.translateSpecificSign(param))
                        .or().like(BasicCourse::getName, SystemConstant.translateSpecificSign(param)));
            }
            return basicCourseService.list(queryWrapper);
        } else {
            return examDetailCourseService.listCoursesByPrintPlanId(param, printPlanIdList);
        }
    }

    /**
     * 机构禁用
     *
     * @param org
     * @return
     */
    @Override
    public boolean enable(SysOrg org) {
        // 禁用时，校验机构
        if (!org.getEnable()) {
            validateOrg(org.getId());
        }
        UpdateWrapper<SysOrg> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().set(SysOrg::getEnable, org.getEnable()).eq(SysOrg::getId, org.getId());
        return sysOrgService.update(updateWrapper);
    }

    /**
     * 机构删除
     *
     * @param id
     * @return
     */
    @Override
    public boolean sysOrgRemove(Long id) {
        // 机构校验
        validateOrg(id);
        return sysOrgService.removeById(id);
    }

    private void validateOrg(Long id) {
        // 机构下是否有用户
        List<SysUser> sysUsers = sysUserService.listByOrgId(id);
        if (sysUsers != null && sysUsers.size() > 0) {
            throw ExceptionResultEnum.ERROR.exception("该机构下有用户，不能删除");
        }

        // 机构下是否有子机构
        QueryWrapper<SysOrg> orgQueryWrapper = new QueryWrapper<>();
        orgQueryWrapper.lambda().eq(SysOrg::getParentId, id);
        List<SysOrg> sysOrgs = sysOrgService.list(orgQueryWrapper);
        if (sysOrgs != null && sysOrgs.size() > 0) {
            throw ExceptionResultEnum.ERROR.exception("该机构下有子机构，不能删除");
        }

        QueryWrapper<BasicTemplateOrg> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(BasicTemplateOrg::getOrgId, id);
        List<BasicTemplateOrg> basicTemplateOrgs = basicTemplateOrgService.list(queryWrapper);
        if (basicTemplateOrgs != null && basicTemplateOrgs.size() > 0) {
            throw ExceptionResultEnum.ERROR.exception("机构已绑定，不能删除");
        }
    }

    /**
     * 更新任务状态
     */
    @Override
    @Transactional
    public void updateStatus() throws IOException {
        //不是自动生成pdf的全部改为失败
//        UpdateWrapper<TBTask> tbTaskUpdateWrapper = new UpdateWrapper<>();
//        tbTaskUpdateWrapper.lambda().set(TBTask::getStatus, TaskStatusEnum.FINISH)
//                .set(TBTask::getSummary, "系统提交:网络异常或程序异常中断!")
//                .set(TBTask::getResult, TaskResultEnum.ERROR)
//                .isNotNull(TBTask::getStatus).ne(TBTask::getStatus, TaskStatusEnum.FINISH)
//                .ne(TBTask::getType, TaskTypeEnum.CREATE_PDF);
//        this.update(tbTaskUpdateWrapper);

        QueryWrapper<TBTask> tbTaskQueryWrapper = new QueryWrapper<>();
        tbTaskQueryWrapper.lambda().eq(TBTask::getType, TaskTypeEnum.CREATE_PDF)
                .ne(TBTask::getStatus, TaskStatusEnum.FINISH)
                .ne(TBTask::getResult, TaskResultEnum.SUCCESS).or().isNull(TBTask::getResult)
                .orderByDesc(TBTask::getStatus);
        List<TBTask> tbTasks = tbTaskService.list(tbTaskQueryWrapper);
        if (Objects.nonNull(tbTasks) && tbTasks.size() > 0) {
            for (TBTask tbTask : tbTasks) {
                Map<String, Object> map = new HashMap<>();
                if (Objects.nonNull(tbTask.getRemark())) {
                    JSONArray jsonArray = JSONArray.parseArray(tbTask.getRemark());
                    ArraysParams arraysParams = new ArraysParams(jsonArray.toArray(new Long[jsonArray.size()]));
                    map.computeIfAbsent("examDetailCourseIds", v -> Arrays.asList(arraysParams.getIds()));
                }
                map.computeIfAbsent(SystemConstant.TASK, v -> tbTask);
                map.computeIfAbsent(SystemConstant.USER, v -> sysUserService.getById(tbTask.getCreateId()));
//                asyncCreatePdfTempleteService.createPdf(map, null);
                MqDto mqDto = new MqDto(MqTagEnum.PDF.getCode(), map, String.valueOf(tbTask.getId()));
                redisUtil.sendMessage(mqDto.getTopic(), mqDto);
            }
        }
    }

    /**
     * 重新生成pdf失败任务
     *
     * @throws IOException
     */
    @Override
    @Transactional
    public void resetCreatePdfTask() throws IOException {
        QueryWrapper<TBTask> tbTaskQueryWrapper = new QueryWrapper<>();
        tbTaskQueryWrapper.lambda().eq(TBTask::getType, TaskTypeEnum.CREATE_PDF)
                .eq(TBTask::getStatus, TaskStatusEnum.FINISH).isNotNull(TBTask::getStatus)
                .eq(TBTask::getResult, TaskResultEnum.ERROR).last("limit 0,100");
        List<TBTask> tbTasks = tbTaskService.list(tbTaskQueryWrapper);
        if (Objects.nonNull(tbTasks) && tbTasks.size() > 0) {
            for (TBTask tbTask : tbTasks) {
                if (tbTask.getResetCount() < dictionaryConfig.sysDomain().getAutoCreatePdfResetMaxCount()) {
                    Map<String, Object> map = new HashMap<>();
//                    tbTask.setVersion(new AtomicInteger(tbTask.getVersion()).incrementAndGet());
                    if (Objects.nonNull(tbTask.getRemark())) {
                        JSONArray jsonArray = JSONArray.parseArray(tbTask.getRemark());
                        ArraysParams arraysParams = new ArraysParams(jsonArray.toArray(new Long[jsonArray.size()]));
                        map.computeIfAbsent("examDetailCourseIds", v -> Arrays.asList(arraysParams.getIds()));
                    }
                    map.computeIfAbsent(SystemConstant.TASK, v -> tbTask);
                    map.computeIfAbsent(SystemConstant.USER, v -> sysUserService.getById(tbTask.getCreateId()));
//                    asyncCreatePdfTempleteService.createPdf(map, null);
                    MqDto mqDto = new MqDto(MqTagEnum.PDF.getCode(), map, String.valueOf(tbTask.getId()));
                    redisUtil.sendMessage(mqDto.getTopic(), mqDto);
                }
            }
        }
    }

    /**
     * 保存任务
     *
     * @param file
     * @param taskTypeEnum
     * @return
     */
    @Override
    @Transactional
    public Map<String, Object> saveTask(MultipartFile file, TaskTypeEnum taskTypeEnum) {
        BasicAttachment basicAttachment = null;
        Map<String, Object> map = null;
        try {
            PrintCommonService printCommonService = SpringContextHolder.getBean(PrintCommonService.class);
            basicAttachment = printCommonService.saveAttachment(file, ServletUtil.getRequestMd5(), UploadFileEnum.FILE);
            if (Objects.isNull(basicAttachment)) {
                throw ExceptionResultEnum.ATTACHMENT_ERROR.exception();
            } else {
                map = new HashMap<>();
                TBTask tbTask = tbTaskService.saveTaskCommon(basicAttachment, taskTypeEnum, map, null);
                tbTaskService.save(tbTask);
            }
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (Objects.nonNull(basicAttachment)) {
                basicAttachmentService.deleteAttachment(basicAttachment);
            }
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return map;
    }

    @Override
    @Transactional
    public Map<String, Object> saveTask(Long printPlanId, MultipartFile file, TaskTypeEnum taskTypeEnum) {
        BasicAttachment basicAttachment = null;
        Map<String, Object> map = null;
        try {
            PrintCommonService printCommonService = SpringContextHolder.getBean(PrintCommonService.class);
            basicAttachment = printCommonService.saveAttachment(file, ServletUtil.getRequestMd5(), UploadFileEnum.FILE);
            if (Objects.isNull(basicAttachment)) {
                throw ExceptionResultEnum.ATTACHMENT_ERROR.exception();
            } else {
                map = new HashMap<>();
                TBTask tbTask = tbTaskService.saveTaskCommon(basicAttachment, taskTypeEnum, map, null);
                tbTask.setPrintPlanId(printPlanId);
                tbTaskService.save(tbTask);
            }
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (Objects.nonNull(basicAttachment)) {
                basicAttachmentService.deleteAttachment(basicAttachment);
            }
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return map;
    }

    @Override
    @Transactional
    public Map<String, Object> saveTask(TaskTypeEnum taskTypeEnum) {
        Map<String, Object> map = null;
        try {
            map = new HashMap<>();
            TBTask tbTask = tbTaskService.saveTaskCommon(null, taskTypeEnum, map, null);
            tbTaskService.save(tbTask);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return map;
    }

    @Override
    @Transactional
    public Map<String, Object> saveTask(Long printPlanId, TaskTypeEnum taskTypeEnum) {
        Map<String, Object> map = null;
        try {
            map = new HashMap<>();
            TBTask tbTask = tbTaskService.saveTaskCommon(null, taskTypeEnum, map, null);
            tbTask.setPrintPlanId(printPlanId);
            tbTaskService.save(tbTask);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return map;
    }

    @Transactional
    @Override
    public Map<String, Object> savePush(PushTypeEnum pushTypeEnum) {
        Map<String, Object> map = null;
        try {
            map = new HashMap<>();
            TBSyncTask tbSyncTask = tbSyncTaskService.savePushCommon(pushTypeEnum, map, null);
            tbSyncTaskService.save(tbSyncTask);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return map;
    }

    /**
     * 校验课程关联考场是否提交打印
     *
     * @param schoolId
     * @param printPlanId
     * @param courseCode
     * @param paperNumber
     * @return
     */
    @Override
    public Boolean checkExamDetailStatus(Long schoolId, Long printPlanId, String courseCode, String paperNumber) {
        List<ExamDetail> examDetails;
        if (printPlanId != null) {
            examDetails = examDetailService.listByPrintPlanIdAndCourseCodeAndPaperNumber(schoolId, printPlanId, courseCode, paperNumber);
        } else {
            examDetails = examDetailService.listByCourseCodeAndPaperNumber(schoolId, courseCode, paperNumber);
        }
        if (examDetails != null && examDetails.size() > 0) {
            long count = examDetails.stream().filter(m -> !ExamDetailStatusEnum.NEW.name().equals(m.getStatus().name()) && !ExamDetailStatusEnum.READY.name().equals(m.getStatus().name())).count();
            if (count > 0) {
                throw ExceptionResultEnum.ERROR.exception("已有印刷任务进入打印状态，不能修改");
            }
        }
        return true;
    }

    /**
     * 生成唯一的试卷编号
     *
     * @param schoolId
     * @return
     */
    @Override
    public String createPaperNumber(Long schoolId) {
        String date = DateUtil.today().replace("-", "");
        String paperNumber = convertUtil.getIncre(date, "paperNumber" + schoolId, 5);
        QueryWrapper<ExamTask> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ExamTask::getSchoolId, schoolId).eq(ExamTask::getPaperNumber, paperNumber);
        ExamTask examTask = examTaskService.getOne(queryWrapper);
        if (examTask != null) {
            return createPaperNumber(schoolId);
        } else {
            return paperNumber;
        }
    }

    /**
     * 校验是否可以提交
     *
     * @param schoolId
     * @param courseCode
     * @param paperNumber
     * @param user
     * @throws IOException
     */
    @Override
    public void checkData(Long schoolId, String courseCode, String paperNumber, SysUser user) throws IOException {
        // 校验命题任务是否提交
        ExamTask examTask = examTaskService.getByCourseCodeAndPaperNumber(schoolId, courseCode, paperNumber);
        BasicExam basicExam = basicExamService.getById(examTask.getExamId());
        if (basicExam != null && ExamModelEnum.MODEL3.equals(basicExam.getExamModel())) {
            log.info("考试模式为模式3，不生成pdf");
            return;
        }

        if (examTask != null && !examTask.getEnable()) {
            log.info("命题任务已禁用");
            return;
        }
        ExamTaskDetail examTaskDetail = examTaskDetailService.getByExamTaskId(examTask.getId());
        if (!examTaskDetail.getEnable()) {
            log.info("卷库已禁用");
            return;
        }
        TFFlowApprove tfFlowApprove = tfFlowApproveService.findByFlowId(examTask.getFlowId());
        // 1.命题任务已完成
        if (tfFlowApprove != null && tfFlowApprove.getStatus() == FlowStatusEnum.FINISH) {
            // 2.校验考务数据是否导入
            List<ExamDetail> examDetails = examDetailService.listByCourseCodeAndPaperNumber(schoolId, courseCode, paperNumber);
            if (examDetails != null && examDetails.size() > 0) {

                // 3.检查examDetailId下有无其它课程
                for (ExamDetail examDetail : examDetails) {
                    List<ExamDetailCourse> examDetailCourses = examDetailCourseService.listByExamDetailIdAndStatus(examDetail.getId());
                    // 4.没有未完成的命题任务
                    if (examDetailCourses.isEmpty()) {
                        // 更新考场状态为初始新建状态
                        UpdateWrapper<ExamDetail> examDetailUpdateWrapper = new UpdateWrapper<>();
                        examDetailUpdateWrapper.lambda().set(ExamDetail::getStatus, ExamDetailStatusEnum.NEW).eq(ExamDetail::getId, examDetail.getId());
                        examDetailService.update(examDetailUpdateWrapper);

                        //所有考场都撤回，印刷任务状态改为就绪
                        QueryWrapper<ExamDetail> queryWrapper = new QueryWrapper<>();
                        queryWrapper.lambda().eq(ExamDetail::getPrintPlanId, examDetail.getPrintPlanId()).notIn(ExamDetail::getStatus, ExamDetailStatusEnum.NEW, ExamDetailStatusEnum.READY);
                        List<ExamDetail> examDetailss = examDetailService.list(queryWrapper);
                        if (examDetailss.isEmpty()) {
                            UpdateWrapper<ExamPrintPlan> printPlanUpdateWrapper = new UpdateWrapper<>();
                            printPlanUpdateWrapper.lambda().set(ExamPrintPlan::getStatus, PrintPlanStatusEnum.READY).eq(ExamPrintPlan::getId, examDetail.getPrintPlanId());
                            examPrintPlanService.update(printPlanUpdateWrapper);
                        }

                        Map<String, Object> map = tbTaskService.saveTask(TaskTypeEnum.CREATE_PDF, examDetail.getPrintPlanId(), user, examDetail.getId());
//                        asyncCreatePdfTempleteService.createPdf(map, null);
                        MqDto mqDto = new MqDto(MqTagEnum.PDF.getCode(), map, String.valueOf(map.get(SystemConstant.TB_TASK_ID)));
                        redisUtil.sendMessage(mqDto.getTopic(), mqDto);
                    }
                }
            }
        }
    }

    @Override
    public List<ExamStudent> createBatchStudent(Long schoolId, String extendFields, List<String> classIds, Long examDetailCourseId, SysUser sysUser) {
        AtomicInteger atomicInteger = new AtomicInteger(1);
        List<ExamStudent> examStudentAll = new ArrayList<>();
        SerialNumberParams ticketNumberParams = new SerialNumberParams("ticketNumber-" + schoolId, DateUtil.format(new Date(), "yyyyMM"), 6);

        for (String classId : classIds) {
            List<ExamStudent> basicStudents = examStudentService.listExamStudentBySchoolIdAndClazzId(schoolId, classId);

            basicStudents = basicStudents.stream().map(examStudent -> {
                examStudent.setId(SystemConstant.getDbUuid());
                examStudent.setSchoolId(schoolId);
                examStudent.setOrgId(sysUser.getOrgId());
                examStudent.setExamDetailCourseId(examDetailCourseId);
                // 准考证号（年月+000001）
                examStudent.setTicketNumber(createTempNumber(ticketNumberParams));
                examStudent.setExtendFields(extendFields);
                examStudent.setSiteNumber(String.valueOf(atomicInteger.getAndIncrement()));
                examStudent.setCreateId(sysUser.getId());
                return examStudent;
            }).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(basicStudents)) {
                examStudentAll.addAll(basicStudents);
            }
        }

        return examStudentAll;
    }

    @Override
    public String createTempNumber(SerialNumberParams serialNumberParams) {
        return convertUtil.getIncre(serialNumberParams.getPrefix(), serialNumberParams.getModel(), serialNumberParams.getDigit());
    }

    /**
     * 保存任务附件(导出)
     *
     * @param fos
     * @param oss
     * @return
     */
    @Override
    public String saveTaskAttachment(ByteArrayOutputStream fos, boolean oss) throws IOException {
        InputStream inputStream = null;
        JSONObject jsonObject = null;
        try {
            inputStream = new ByteArrayInputStream(fos.toByteArray());
            LocalDateTime nowTime = LocalDateTime.now();
            StringJoiner stringJoiner = new StringJoiner("");
            if (!oss) {
                stringJoiner.add(SystemConstant.TEMP_FILES_DIR).add(File.separator);
            }
            stringJoiner.add(UploadFileEnum.FILE.getTitle()).add(File.separator);
            stringJoiner.add(String.valueOf(nowTime.getYear())).add(File.separator)
                    .add(String.format("%02d", nowTime.getMonthValue())).add(File.separator)
                    .add(String.format("%02d", nowTime.getDayOfMonth()))
                    .add(File.separator).add(SystemConstant.getUuid()).add(".").add(SystemConstant.XLSX);
            jsonObject = new JSONObject();
            String dirName = stringJoiner.toString().replaceAll("\\\\", "/");
            if (oss) {//上传至oss
                fileStoreUtil.ossUpload(dirName, inputStream, DigestUtils.md5Hex(new ByteArrayInputStream(fos.toByteArray())), UploadFileEnum.FILE.getFssType());
                jsonObject.put(SystemConstant.TYPE, SystemConstant.OSS);
            } else {
                File finalFile = new File(stringJoiner.toString());
                if (!finalFile.exists()) {
                    finalFile.getParentFile().mkdirs();
                    finalFile.createNewFile();
                }
                FileUtils.copyInputStreamToFile(inputStream, finalFile);
                jsonObject.put(SystemConstant.TYPE, SystemConstant.LOCAL);
            }
            jsonObject.put(SystemConstant.PATH, dirName);
            jsonObject.put(SystemConstant.UPLOAD_TYPE, UploadFileEnum.FILE);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
        } finally {
            if (Objects.nonNull(inputStream)) {
                inputStream.close();
            }
        }
        return Objects.nonNull(jsonObject) ? jsonObject.toJSONString() : null;
    }

    @Override
    public String createCourseSequence(Long schoolId, String courseCode) {
        String key = "courseCode-" + courseCode + schoolId;
        String sequence = convertUtil.getIncre("", key, 1);
        if ("1".equals(sequence)) {
            QueryWrapper<ExamTask> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(ExamTask::getSchoolId, schoolId).eq(ExamTask::getCourseCode, courseCode);
            List<ExamTask> examTasks = examTaskService.list(queryWrapper);
            if (examTasks != null && examTasks.size() > 0) {
                String maxSequence = examTasks.stream().max(Comparator.comparing(ExamTask::getSequence)).get().getSequence();
                if (StringUtils.isNotBlank(maxSequence)) {
                    String incMaxSequence = String.valueOf(Integer.parseInt(maxSequence) + 1);
                    redisUtil.set(key, incMaxSequence);
                    return incMaxSequence;
                }
            }
        }
        return sequence;
    }

    @Override
    public void updateGradeBatchStatus(Long schoolId, String paperNumber, String paperType) {
        QueryWrapper<GradeBatchPaper> gradeBatchPaperQueryWrapper = new QueryWrapper<>();
        gradeBatchPaperQueryWrapper.lambda().eq(GradeBatchPaper::getSchoolId, schoolId).eq(GradeBatchPaper::getPaperNumber, paperNumber).eq(GradeBatchPaper::getPaperType, paperType);
        List<GradeBatchPaper> gradeBatchPaperList = gradeBatchPaperService.list(gradeBatchPaperQueryWrapper);
        if (!gradeBatchPaperList.isEmpty()) {
            for (GradeBatchPaper gradeBatchPaper : gradeBatchPaperList) {
                QueryWrapper<GradeBatchPaper> queryWrapperList = new QueryWrapper<>();
                queryWrapperList.lambda().eq(GradeBatchPaper::getBatchId, gradeBatchPaper.getBatchId());
                List<GradeBatchPaper> gradeBatchPaperAll = gradeBatchPaperService.list(queryWrapperList);
                if (!gradeBatchPaperAll.isEmpty()) {
                    long count = gradeBatchPaperAll.stream().filter(m -> !GradeAnalyzePaperStatusEnum.READY_TO_CALCULATE.equals(m.getStatus())).count();
                    if (count == 0) {
                        // 更新批次状态
                        UpdateWrapper<GradeBatch> updateWrapper = new UpdateWrapper<>();
                        updateWrapper.lambda().set(GradeBatch::getStatus, GradeAnalyzePaperStatusEnum.READY_TO_CALCULATE).eq(GradeBatch::getId, gradeBatchPaper.getBatchId());
                    }
                }
            }
        }
    }
}
