package com.qmth.distributed.print.business.util;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.Gson;
import com.qmth.distributed.print.business.bean.dto.ExamStudentCourseDto;
import com.qmth.distributed.print.business.bean.dto.ExamStudentDto;
import com.qmth.distributed.print.business.bean.dto.PaperPdfDto;
import com.qmth.distributed.print.business.bean.dto.PdfDto;
import com.qmth.distributed.print.business.cache.CreatePdfCacheUtil;
import com.qmth.distributed.print.business.entity.*;
import com.qmth.distributed.print.business.enums.DrawRuleEnum;
import com.qmth.distributed.print.business.enums.ExamDetailStatusEnum;
import com.qmth.distributed.print.business.enums.PrintMethodEnum;
import com.qmth.distributed.print.business.service.ExamDetailService;
import com.qmth.distributed.print.business.service.PrintCommonService;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.BasicAttachment;
import com.qmth.teachcloud.common.entity.TBTask;
import com.qmth.teachcloud.common.enums.ClassifyEnum;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.enums.PageSizeEnum;
import com.qmth.teachcloud.common.enums.UploadFileEnum;
import com.qmth.teachcloud.common.service.BasicAttachmentService;
import com.qmth.teachcloud.common.service.TeachcloudCommonService;
import com.qmth.teachcloud.common.util.ConvertUtil;
import com.qmth.teachcloud.common.util.FileStoreUtil;
import com.qmth.teachcloud.common.util.RedisUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 创建pdf util
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2021/4/14
 */
@Component
public class CreatePdfUtil {
    private final static Logger log = LoggerFactory.getLogger(CreatePdfUtil.class);

//    @Resource
//    OssUtil ossUtil;

    @Resource
    BasicAttachmentService basicAttachmentService;

    @Resource
    FreemarkerUtil freemarkerUtil;

    @Resource
    @Lazy
    PrintCommonService printCommonService;

    @Resource
    ExamDetailService detailService;

    @Resource
    RedisUtil redisUtil;

    @Resource
    TeachcloudCommonService teachcloudCommonService;

    @Resource
    FileStoreUtil fileStoreUtil;

    /**
     * 创建登记表
     *
     * @param examDetail
     * @param basicAttachment
     * @param ordinaryPdfList
     * @param printCount
     */
    public void createCheckIn(ExamDetail examDetail, BasicAttachment basicAttachment, List<PdfDto> ordinaryPdfList, Integer printCount) throws Exception {
        if (Objects.isNull(basicAttachment)) {
            throw ExceptionResultEnum.ATTACHMENT_IS_NULL.exception();
        }
        String type = basicAttachment.getType();
        JSONObject jsonObject = JSONObject.parseObject(basicAttachment.getPath());

        if (Objects.nonNull(type) && Objects.equals(type, SystemConstant.PDF_PREFIX)) {
            String filePath = (String) jsonObject.get(SystemConstant.PATH);
            String url = SystemConstant.TEMP_FILES_DIR + File.separator + filePath;
            UploadFileEnum uploadFileEnum = UploadFileEnum.valueOf((String) jsonObject.get(SystemConstant.UPLOAD_TYPE));

//            File localFile = ossUtil.ossDownload(filePath, url);
            File localFile = fileStoreUtil.ossDownload(filePath, url, uploadFileEnum.getFssType());
            PdfDto pdfDto = PdfUtil.addPdfPage(localFile);
            for (int i = 0; i < printCount; i++) {
                ordinaryPdfList.add(new PdfDto(localFile.getPath(), PageSizeEnum.A4, pdfDto.getPageCount()));
            }
        } else {
            printCommonService.saveAttachmentPdf(ClassifyEnum.CHECK_IN, examDetail, basicAttachment, ordinaryPdfList, printCount, 0);
        }
    }

    /**
     * 生成卷袋贴
     *
     * @param tag
     * @param basicAttachment
     * @param schoolName
     * @param examStudentList
     * @param variablePdfList
     * @param printCount
     * @param examDetailCourseList
     * @throws IOException
     */
    public void createPaperPackage(boolean tag, BasicAttachment basicAttachment, String schoolName, ExamDetail examDetail, List<ExamStudentCourseDto> examStudentList, List<PdfDto> variablePdfList, Integer printCount, List<ExamDetailCourse> examDetailCourseList) throws IOException {
        if (Objects.isNull(basicAttachment)) {
            throw ExceptionResultEnum.ATTACHMENT_IS_NULL.exception();
        }
        Map<String, Object> htmlMap = new HashMap<>();
        if (Objects.nonNull(examDetailCourseList) && examDetailCourseList.size() > 0) {
//            Set<Long> examDetailCourseIds = new HashSet<>();
//            htmlMap.put("examDetailCourseId", StringUtils.join(examDetailCourseIds, ", "));
            List<String> paperNumbers = examDetailCourseList.stream().map(s -> s.getPaperNumber()).collect(Collectors.toList());
            List<String> courseNames = examDetailCourseList.stream().map(s -> s.getCourseName()).collect(Collectors.toList());
            htmlMap.put("courseName", String.join(", ", courseNames));
            htmlMap.put("courseCode", String.join(", ", paperNumbers));
        } else {
            htmlMap.put("courseName", "");
            htmlMap.put("courseCode", "");
        }
        htmlMap.put("schoolName", schoolName);
        htmlMap.put("examSite", examDetail.getExamPlace());
        htmlMap.put("examRoom", examDetail.getExamRoom());
        htmlMap.put("startTime", DateUtil.format(new Date(examDetail.getExamStartTime()), SystemConstant.DEFAULT_DATE_PATTERN));
        htmlMap.put("endTime", DateUtil.format(new Date(examDetail.getExamEndTime()), SystemConstant.DEFAULT_DATE_PATTERN));
        htmlMap.put("paperCode", examDetail.getPackageCode());
        htmlMap.put("paperCodeImg", GoogleBarCodeUtil.createBarCode(examDetail.getPackageCode(), false));

        List<String> extendColumnList = examStudentList.stream().map(m -> m.getExtendFields()).distinct().collect(Collectors.toList());
        Set<String> startCollege = new HashSet();
        Set<String> className = new HashSet();
        Set<String> proctorCollege = new HashSet();
        Set<String> examManager = new HashSet();

        if (Objects.nonNull(extendColumnList) && extendColumnList.size() > 0) {
            for (String s : extendColumnList) {
                List<Map> mapList = JSONObject.parseArray(s, Map.class);
                for (Map map : mapList) {
                    if (Objects.equals("startCollege", map.get("code").toString())) {
                        startCollege.add(map.get("value").toString());
                    }
                    if (Objects.equals("className", map.get("code").toString())) {
                        className.add(map.get("value").toString());
                    }
                    if (Objects.equals("proctorCollege", map.get("code").toString())) {
                        proctorCollege.add(map.get("value").toString());
                    }
                    if (Objects.equals("examManager", map.get("code").toString())) {
                        examManager.add(map.get("value").toString());
                    }
                }
            }
        }

        htmlMap.put("startCollege", String.join(",", startCollege));
        htmlMap.put("className", String.join(",", className));
        htmlMap.put("proctorCollege", String.join(",", proctorCollege));
        htmlMap.put("examManager", String.join(",", examManager));

//        List<ExamStudent> tempList = examStudentList.stream().filter(s -> (Objects.nonNull(s.getSiteNumber()) && !Objects.equals("", s.getSiteNumber().trim()))).collect(Collectors.toList());
//        String minSite = "", maxSite = "";
//        if (Objects.nonNull(tempList) && tempList.size() > 0) {
//            minSite = tempList.stream().min((a, b) -> a.getSiteNumber().compareTo(b.getSiteNumber())).get().getSiteNumber();
//            maxSite = tempList.stream().max((a, b) -> a.getSiteNumber().compareTo(b.getSiteNumber())).get().getSiteNumber();
//        }

        Optional<ExamStudentCourseDto> minSite = null;
        Optional<ExamStudentCourseDto> maxSite = null;
        List<ExamStudentCourseDto> tempList = examStudentList.stream().filter(s -> (Objects.nonNull(s.getSiteNumber()) && !Objects.equals("", s.getSiteNumber().trim()))).collect(Collectors.toList());
        if (Objects.nonNull(tempList) && tempList.size() > 0) {
//            for (ExamStudentCourseDto e : tempList) {
//                char[] chars = e.getSiteNumber().toLowerCase().toCharArray();
//                String ascii = "";
//                for (int i = 0; i < chars.length; i++) {
//                    ascii = ascii + chars[i];
//                }
//                e.setAscii(ascii.hashCode());
//            }
            minSite = tempList.stream().min(Comparator.comparing(s -> s.getSiteNumber().hashCode()));
            maxSite = tempList.stream().max(Comparator.comparing(s -> s.getSiteNumber().hashCode()));
        }

        htmlMap.put("minSite", Optional.ofNullable(minSite).map(s -> s.get().getSiteNumber()).orElse(""));
        htmlMap.put("maxSite", Optional.ofNullable(maxSite).map(s -> s.get().getSiteNumber()).orElse(""));
        htmlMap.put("studentCount", examStudentList.size());

        String tagValue = tag ? "订" : null;
        htmlMap.put("tag", tagValue);

        htmlMap.computeIfAbsent("basicAttachment", v -> basicAttachment);
        htmlMap.computeIfAbsent("variablePdfList", v -> variablePdfList);
        htmlMap.computeIfAbsent("printCount", v -> printCount);
        htmlMap.computeIfAbsent("sequence", v -> 1);
        htmlMap.computeIfAbsent("examDetail", v -> examDetail);
        htmlMap.computeIfAbsent("printType", v -> ClassifyEnum.PACKAGE);
        freemarkerUtil.createPaperPackage(htmlMap);
    }

    /**
     * 创建签到表
     *
     * @param basicAttachment
     * @param schoolName
     * @param examDetail
     * @param examStudentList
     * @param variablePdfList
     * @param printCount
     * @param examDetailCourseList
     */
    public void createSignBook(BasicAttachment basicAttachment, String schoolName, ExamDetail examDetail, List<ExamStudentCourseDto> examStudentList, List<PdfDto> variablePdfList, Integer printCount, List<ExamDetailCourse> examDetailCourseList) throws IOException {
        if (Objects.isNull(basicAttachment)) {
            throw ExceptionResultEnum.ATTACHMENT_IS_NULL.exception();
        }
        Map<String, Object> htmlMap = new HashMap<>();
        if (Objects.nonNull(examDetailCourseList) && examDetailCourseList.size() > 0) {
            List<String> paperNumbers = examDetailCourseList.stream().map(s -> s.getPaperNumber()).collect(Collectors.toList());
            List<String> courseNames = examDetailCourseList.stream().map(s -> s.getCourseName()).collect(Collectors.toList());
            htmlMap.put("courseName", String.join(", ", courseNames));
            htmlMap.put("courseCode", String.join(", ", paperNumbers));
        } else {
            htmlMap.put("courseName", "");
            htmlMap.put("courseCode", "");
        }
        htmlMap.put("schoolName", schoolName);
        htmlMap.put("examRoom", examDetail.getExamRoom());

        List<String> extendColumnList = examStudentList.stream().map(m -> m.getExtendFields()).distinct().collect(Collectors.toList());
        Set<String> classTeacher = new HashSet();
        if (Objects.nonNull(extendColumnList) && extendColumnList.size() > 0) {
            for (String s : extendColumnList) {
                List<Map> mapList = JSONObject.parseArray(s, Map.class);
                for (Map map : mapList) {
                    if (Objects.equals("classTeacher", map.get("code").toString())) {
                        classTeacher.add(map.get("value").toString());
                    }
                }
            }
        }
        htmlMap.put("classTeacher", String.join(",", classTeacher));
        htmlMap.put("startTime", DateUtil.format(new Date(examDetail.getExamStartTime()), SystemConstant.DEFAULT_DATE_PATTERN));
        htmlMap.put("endTime", DateUtil.format(new Date(examDetail.getExamEndTime()), SystemConstant.DEFAULT_DATE_PATTERN));
        htmlMap.put("paperCode", examDetail.getPackageCode());
        htmlMap.put("paperCodeImg", GoogleBarCodeUtil.createBarCode(examDetail.getPackageCode(), false));

        int totalCount = examStudentList.size();
        if (totalCount > 0) {
            List<Map> subList = new ArrayList<>();
            int pageCount = totalCount % 80 == 0 ? totalCount / 80 : totalCount / 80 + 1;
            for (int i = 0; i < pageCount; i++) {
                Map subMap = new HashMap();
                subMap.put("index", i + 1);
                int studentCount;
                List<ExamStudentCourseDto> subStudents;
                if (pageCount == 1) {
                    studentCount = totalCount;
                    subStudents = examStudentList;
                } else if (pageCount > 1 && i == pageCount - 1) {
                    studentCount = totalCount - (pageCount - 1) * 80;
                    subStudents = examStudentList.subList(80 * i, examStudentList.size());
                } else {
                    studentCount = 80;
                    subStudents = examStudentList.subList(80 * i, 80 * (i + 1));
                }
                subMap.put("studentCount", studentCount);
                List<ExamStudentDto> examStudentList1 = new ArrayList<>();
                List<ExamStudentDto> examStudentList2 = new ArrayList<>();

                Gson gson = new Gson();
                int mod = subStudents.size() % 2;
                int htmlTableCount = mod == 0 ? subStudents.size() / 2 : subStudents.size() / 2 + 1;
                for (int j = 0; j < htmlTableCount; j++) {
                    ExamStudentDto examStudentDto = gson.fromJson(gson.toJson(subStudents.get(j)), ExamStudentDto.class);
                    examStudentDto.setIndex(j + 1);
                    examStudentDto.setName(examStudentDto.getStudentName());
                    examStudentDto.setExtendFields(getClassName(examStudentDto.getExtendFields()));
                    examStudentList1.add(examStudentDto);
                }
                for (int j = htmlTableCount; j < subStudents.size(); j++) {
                    ExamStudentDto examStudentDto = gson.fromJson(gson.toJson(subStudents.get(j)), ExamStudentDto.class);
                    examStudentDto.setIndex(j + 1);
                    examStudentDto.setName(examStudentDto.getStudentName());
                    examStudentDto.setExtendFields(getClassName(examStudentDto.getExtendFields()));
                    examStudentList2.add(examStudentDto);
                }
                if (examStudentList1.size() > examStudentList2.size()) {
                    for (int j = subStudents.size() - htmlTableCount; j < examStudentList1.size(); j++) {
                        examStudentList2.add(new ExamStudentDto());
                    }
                }
                subMap.put("studentList1", examStudentList1);
                subMap.put("studentList2", examStudentList2);
                subList.add(subMap);
            }
            htmlMap.put("subList", subList);
        }
        htmlMap.computeIfAbsent("basicAttachment", v -> basicAttachment);
        htmlMap.computeIfAbsent("variablePdfList", v -> variablePdfList);
        htmlMap.computeIfAbsent("printCount", v -> printCount);
        htmlMap.computeIfAbsent("sequence", v -> 2);
        htmlMap.computeIfAbsent("examDetail", v -> examDetail);
        htmlMap.computeIfAbsent("printType", v -> ClassifyEnum.SIGN);
        freemarkerUtil.createSignBook(htmlMap);
    }

    /**
     * 替换html通用模版
     *
     * @param examCardDetail
     * @return
     */
    public String replaceHtmlTemplete(ExamCardDetail examCardDetail) {
        String content = examCardDetail.getHtmlContent();
        log.info("contentTemp:{}", content);
        content = content.replaceAll("<img src=\"data:image/png;base64,\\$\\{examNumber\\}\">", "");
        content = content.replaceAll("\\$\\{examNumberStr\\}", "");
        return content;
    }

    /**
     * 替换自定义题卡参数
     *
     * @param examCardDetail
     * @return
     * @throws IOException
     */
    public String replaceHtmlCard(ExamCardDetail examCardDetail, BasicCardRule basicCardRule) throws IOException {
        //通用题卡
        String cardTemp = examCardDetail.getHtmlContent();
        cardTemp = cardTemp.replaceAll("\\$\\{paperTypeName\\}", "");
        //随机生成试卷条码并将图片转成base64
        cardTemp = cardTemp.replaceAll("\\$\\{paperType\\}", "");
        cardTemp = cardTemp.replaceAll("<img src=\"data:image/png;base64,\\$\\{examNumber\\}\">", "");
        cardTemp = cardTemp.replaceAll("\\$\\{examNumberStr\\}", "");
        if (Objects.nonNull(basicCardRule) && Objects.nonNull(basicCardRule.getExtendFields())) {
            JSONArray jsonObjectExtend = (JSONArray) JSONArray.parse(basicCardRule.getExtendFields());//扩展字段
            if (Objects.nonNull(jsonObjectExtend)) {
                for (int i = 0; i < jsonObjectExtend.size(); i++) {
                    JSONObject object = (JSONObject) jsonObjectExtend.get(i);
                    cardTemp = cardTemp.replaceAll("\\$\\{" + object.get("code") + "\\}", "");
                }
            }
        }
        cardTemp = cardTemp.replaceAll("\\$\\{examDate\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{examTime\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{ticketNumber\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{siteNumber\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{paperTypeName\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{studentCode\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{studentName\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{courseName\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{courseCode\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{examPlace\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{examRoom\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{paperNumber\\}", "");

        //通用题卡生成卷袋贴条码
//        String packageCodeDiv = "<div class=\"page-box page-box-0\"><div class=\"package-number\" style=\"position: absolute;width: 200px;height: 40px;top: 10px;right: 25%;margin-left: -100px;text-align: center;z-index: 99;\"><img src=\"data:image/png;base64," + packageCodeImg + "\" style=\"display: block; height: 28px; width: 100%\" /><p style=\"line-height: 1; font-size: 12px; margin: 0;\">" + packageCode + "</p></div>";
//        cardTemp = cardTemp.replaceAll("<div class=\"page-box page-box-0\">", packageCodeDiv);
        return cardTemp;
    }

    /**
     * 获取题卡attachmentId
     *
     * @param examCardDetail
     * @param attachmentIds
     */
    public void getCardAttachmentId(ExamCardDetail examCardDetail, Set<Long> attachmentIds) {
        if (Objects.nonNull(examCardDetail.getAttachmentId()) && !Objects.equals("", examCardDetail.getAttachmentId())) {
            JSONObject jsonObjectCard = JSONObject.parseObject(examCardDetail.getAttachmentId());
            JSONArray jsonArrayCard = (JSONArray) jsonObjectCard.get("card");
            for (int i = 0; i < jsonArrayCard.size(); i++) {
                JSONObject object = (JSONObject) jsonArrayCard.get(i);
                if (Objects.nonNull(object.get("attachmentId")) && !Objects.equals("", object.get("attachmentId"))) {
                    attachmentIds.add((Long) (object.get("attachmentId")));
                }
            }
        }
    }

    /**
     * 获取试卷pdf
     *
     *
     * @param stuPaperType
     * @param paperPdfDto
     * @param pdfList
     * @return
     * @throws IOException
     */
    public PdfDto getExamStudentPaperPdf(String stuPaperType, List<PaperPdfDto> paperPdfDto, List<PdfDto> pdfList) throws IOException {
        Set<Integer> pagesList = new HashSet<>();
        if (!CollectionUtils.isEmpty(paperPdfDto)) {
            for (PaperPdfDto dto : paperPdfDto) {
                if(stuPaperType.equals(dto.getType())){
                    int pages = dto.getPages();
                    pagesList.add(pages);
                    PdfDto pdfDto = PdfUtil.addPdfPage(dto.getFile());
                    pdfList.add(new PdfDto(dto.getFile().getPath(), PageSizeEnum.A3, pdfDto.getPageCount()));
                }
            }
            int pageCount = pagesList.stream().mapToInt(Integer::intValue).sum();
            return new PdfDto(PageSizeEnum.A3, pageCount);
        } else {
            return null;
        }
    }

    /**
     * 获取试卷pdf
     *
     * @param paperPdfDto
     * @param backupCount
     * @param pdfList
     * @return
     * @throws IOException
     */
    public PdfDto getPaperPdf(List<PaperPdfDto> paperPdfDto, Integer backupCount, List<PdfDto> pdfList) throws IOException {
        Set<Integer> pagesList = new HashSet<>();
        boolean tag = false;
        if (!CollectionUtils.isEmpty(paperPdfDto)) {
            for (PaperPdfDto dto : paperPdfDto) {
                int pages = dto.getPages();
                pagesList.add(pages);
                tag = pages > 2;
                PdfDto pdfDto = PdfUtil.addPdfPage(dto.getFile());
                for (int j = 1; j <= backupCount; j++) {
                    pdfList.add(new PdfDto(dto.getFile().getPath(), PageSizeEnum.A3, pdfDto.getPageCount()));
                }
            }
            int pageCount = pagesList.stream().mapToInt(Integer::intValue).sum();
            return new PdfDto(PageSizeEnum.A3, pageCount, tag);
        } else {
            return null;
        }
    }

    /**
     * 获取考试试卷
     *
     * @param paperType
     * @param examTaskDetail
     * @return
     * @throws IOException
     */
    public List<PaperPdfDto> getPaperPdfFile(String paperType, ExamTaskDetail examTaskDetail) throws Exception {
        String[] paperTypes = paperType.split(",");
        List<PaperPdfDto> paperPdfDtoList = new ArrayList<>();
        PaperPdfDto paperPdfDto = null;
        JSONArray jsonArrayPaper = JSONArray.parseArray(examTaskDetail.getPaperAttachmentIds());
        for (int i = 0; i < jsonArrayPaper.size(); i++) {
            JSONObject object = (JSONObject) jsonArrayPaper.get(i);
            if (Objects.nonNull(object.get("attachmentId")) && !Objects.equals("", object.get("attachmentId"))) {
                Long attachmentId = Long.parseLong((String) (object.get("attachmentId")));
                BasicAttachment basicAttachment = basicAttachmentService.getById(attachmentId);
                if (Objects.isNull(basicAttachment)) {
                    throw ExceptionResultEnum.ATTACHMENT_IS_NULL.exception();
                }
                String name = (String) object.get("name");
                for (String type : paperTypes) {
                    if (Objects.equals(name.toUpperCase(), type.toUpperCase())) {
                        File file = teachcloudCommonService.getFile(basicAttachment.getPath(), false);
                        int pages = (int) object.get("pages");
                        paperPdfDto = new PaperPdfDto(type, file, pages);
                        paperPdfDtoList.add(paperPdfDto);
                        break;
                    }
                }

            }
        }
        return paperPdfDtoList;
    }

    /**
     * 抽取试卷
     *
     * @param examPrintPlan
     * @param examTaskDetail
     * @param key
     * @return
     */
    public String getPaperType(ExamPrintPlan examPrintPlan, ExamTaskDetail examTaskDetail, String key) {
        //抽取卷型
        DrawRuleEnum drawRule = Objects.nonNull(examPrintPlan.getDrawRule()) ? examPrintPlan.getDrawRule() : DrawRuleEnum.ONE;
        //未曝光卷型
        String unexposedPaperType = examTaskDetail.getUnexposedPaperType();
        //已曝光卷型
        String exposedPaperType = examTaskDetail.getExposedPaperType();
        // 单次抽取套数
        int drawCount = examTaskDetail.getDrawCount().intValue();
        if (drawRule == DrawRuleEnum.ONE) {
            if (Objects.isNull(unexposedPaperType) || Objects.equals(unexposedPaperType.trim(), "")) {
                CreatePdfCacheUtil.deletePaperType(key);
                throw ExceptionResultEnum.PAPER_ERROR.exception();
            }
        } else {
            if ((Objects.isNull(exposedPaperType) || Objects.equals(exposedPaperType.trim(), "")) && (Objects.isNull(unexposedPaperType) || Objects.equals(unexposedPaperType.trim(), ""))) {
                CreatePdfCacheUtil.deletePaperType(key);
                throw ExceptionResultEnum.PAPER_ERROR.exception();
            }
        }
        String paperType = null;
        String[] paperTypes = null;
        boolean lock = true;
        for (int i = 0; i < SystemConstant.MAX_RETRY_COUNT; i++) {
            lock = redisUtil.lock(key, SystemConstant.REDIS_CACHE_TIME_OUT);
            if (lock) {
                try {
                    paperType = CreatePdfCacheUtil.getPaperType(key);
                    if (Objects.isNull(paperType) || (StringUtils.isNotBlank(unexposedPaperType) && !unexposedPaperType.contains(paperType))) {
                        if (drawRule == DrawRuleEnum.ONE) {
                            paperTypes = unexposedPaperType.split(",");
                            if (paperTypes.length - drawCount < 0) {
                                throw ExceptionResultEnum.ERROR.exception("没有可用卷型");
                            }
                        } else {
                            if (Objects.nonNull(unexposedPaperType)) {
                                paperTypes = unexposedPaperType.split(",");
                            } else {
                                paperTypes = exposedPaperType.split(",");
                            }
                        }
                        paperType = randomPaperType(paperTypes, exposedPaperType, drawCount);
                        CreatePdfCacheUtil.setPaperType(key, paperType);
                    }
                    break;
                } catch (Exception e) {
                    log.error("请求出错", e);
                } finally {
                    redisUtil.releaseLock(key);
                }
            } else {//未获取到锁，等待500毫秒继续获取
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        log.info("getPaperType key:{},paperType:{},lock:{}", key, paperType, lock);
        if (!lock) {
            log.info("getPaperType 未获取到锁,key:{}", key);
            throw ExceptionResultEnum.PAPER_TYPE_ERROR.exception();
        }
        return paperType;
    }

    private String randomPaperType(String[] unexposedPaperTypes, String exposedPaperTypes, int drawCount) {
        List<String> finalTypes = new ArrayList<>();
        List<String> unexposedPaperTypesList = new ArrayList<>(Arrays.asList(unexposedPaperTypes));
        List<String> exposedPaperTypesList =StringUtils.isBlank(exposedPaperTypes) ? new ArrayList<>() : new ArrayList<>(Arrays.asList(exposedPaperTypes.split(",")));
        if (unexposedPaperTypesList.size() - drawCount >= 0) {
            for (int i = 0; i < drawCount; i++) {
                int paperRandom = new Random().nextInt(unexposedPaperTypesList.size());
                finalTypes.add(unexposedPaperTypesList.get(paperRandom));
                unexposedPaperTypesList.remove(paperRandom);
            }

        } else {
            for (int i = 0; i < unexposedPaperTypesList.size(); i++) {
                int paperRandom = new Random().nextInt(unexposedPaperTypesList.size());
                finalTypes.add(unexposedPaperTypesList.get(paperRandom));
                unexposedPaperTypesList.remove(paperRandom);
            }
            for (int i = 0; i < drawCount - unexposedPaperTypesList.size(); i++) {
                int paperRandom = new Random().nextInt(exposedPaperTypesList.size());
                finalTypes.add(exposedPaperTypesList.get(paperRandom));
                exposedPaperTypesList.remove(paperRandom);
            }
        }
        finalTypes = finalTypes.stream().sorted(Comparator.comparing(String::valueOf)).collect(Collectors.toList());
        return String.join(",", finalTypes);
    }

    /**
     * 合并A3 pdf
     *
     * @param list
     * @return
     * @throws IOException
     */
    public String mergeA3Pdf(List<PdfDto>... list) throws IOException {
        List<PdfDto> mergePdfA3List = new ArrayList<>();
        for (int i = 0; i < list.length; i++) {
            mergePdfA3List.addAll(list[i]);
        }
        List<String> pathA3List = mergePdfA3List.stream().map(PdfDto::getPath).collect(Collectors.toList());
        return PdfUtil.mergePdf(pathA3List.toArray(new String[mergePdfA3List.size()]), null);
    }

    /**
     * 合并A4 pdf
     *
     * @param list
     * @return
     * @throws IOException
     */
    public String mergeA4Pdf(List<PdfDto>... list) throws IOException {
        List<PdfDto> mergePdfA4List = new ArrayList<>();
        for (int i = 0; i < list.length; i++) {
            mergePdfA4List.addAll(list[i]);
        }
        List<String> pathA4List = mergePdfA4List.stream().map(PdfDto::getPath).collect(Collectors.toList());
        return PdfUtil.mergePdf(pathA4List.toArray(new String[mergePdfA4List.size()]), null);
    }

    /**
     * 合并pdf后保存数据库
     *
     * @param dirNameA4
     * @param dirNameA3
     * @param tbTask
     * @param userId
     * @param examDetail
     * @param basicExamRule
     * @param mergePdfDeleteList
     * @return
     * @throws IOException
     */
    @Transactional
    public BasicAttachment mergePdfSaveDb(String dirNameA4,
                                          String dirNameA3,
                                          TBTask tbTask,
                                          Long userId,
                                          ExamDetail examDetail,
                                          BasicExamRule basicExamRule,
                                          List<PdfDto> mergePdfDeleteList) throws Exception {
        StringJoiner stringJoiner = new StringJoiner("").add(SystemConstant.PDF_TEMP_FILES_DIR).add(File.separator);
        // oss上只认"/"，windows生成的路径分隔符全部替换为"/"
        File localA4PdfFile = null, localA3PdfFile = null;
        BasicAttachment basicAttachment = null;
        if (Objects.nonNull(dirNameA4)) {
            dirNameA4 = dirNameA4.replaceAll("\\\\", "/");
            localA4PdfFile = new File(stringJoiner.toString() + File.separator + dirNameA4);
        }
        if (Objects.nonNull(dirNameA3)) {
            dirNameA3 = dirNameA3.replaceAll("\\\\", "/");
            localA3PdfFile = new File(stringJoiner.toString() + File.separator + dirNameA3);
            basicAttachment = basicAttachmentService.saveAttachmentPdf(dirNameA3, userId);
            tbTask.setImportFileName(basicAttachment.getName());
            tbTask.setImportFilePath(basicAttachment.getPath());
            examDetail.setAttachmentId(basicAttachment.getId());
        }
        examDetail.setPagesA3(PdfUtil.getPdfPages(localA3PdfFile));
        examDetail.setPagesA4(PdfUtil.getPdfPages(localA4PdfFile));
        if (PrintMethodEnum.AUTO == basicExamRule.getPrintMethod()) {
            examDetail.setStatus(ExamDetailStatusEnum.WAITING);
        } else {
            examDetail.setStatus(ExamDetailStatusEnum.READY);
        }
        detailService.saveOrUpdate(examDetail);
        if (Objects.nonNull(localA3PdfFile)) {
//            ossUtil.ossUpload(dirNameA3, localA3PdfFile, DigestUtils.md5Hex(new FileInputStream(localA3PdfFile)));
            fileStoreUtil.ossUpload(dirNameA3, localA3PdfFile, DigestUtils.md5Hex(new FileInputStream(localA3PdfFile)),fileStoreUtil.getUploadEnumByPath(dirNameA3).getFssType());
            localA3PdfFile.delete();
        }
        if (Objects.nonNull(localA4PdfFile)) {
            localA4PdfFile.delete();
        }
        //删除题卡临时文件
        for (PdfDto pdfDto : mergePdfDeleteList) {
            if (Objects.nonNull(pdfDto)) {
                new File(pdfDto.getPath()).delete();
            }
        }
//        for (PdfDto pdfDto : mergePdfA3List) {
//            if (Objects.nonNull(pdfDto)) {
//                new File(pdfDto.getPath()).delete();
//            }
//        }
//        for (PdfDto pdfDto : mergePdfA4List) {
//            if (Objects.nonNull(pdfDto)) {
//                new File(pdfDto.getPath()).delete();
//            }
//        }
        return basicAttachment;
    }

    /**
     * 删除附件
     *
     * @param attachmentIds
     * @param ftlList
     */
    public void deleteAttachment(Set<Long> attachmentIds, Set<File> ftlList) {
        if (Objects.nonNull(attachmentIds) && attachmentIds.size() > 0) {
            QueryWrapper<BasicAttachment> basicAttachmentQueryWrapper = new QueryWrapper<>();
            basicAttachmentQueryWrapper.lambda().in(BasicAttachment::getId, attachmentIds);
            basicAttachmentService.batchDeleteAttachment(basicAttachmentService.list(basicAttachmentQueryWrapper));
            basicAttachmentService.removeByIds(attachmentIds);
        }
        if (Objects.nonNull(ftlList) && ftlList.size() > 0) {
            for (File file : ftlList) {
                file.delete();
            }
        }
    }

    /**
     * 考生题卡html
     *
     * @param attachmentIds
     * @param studentContent
     * @param t
     * @param examDetail
     * @param examDetailCourse
     * @param userId
     * @param examStudentPdfList
     * @return
     * @throws IOException
     */
    public BasicAttachment examStudentHtml(Set<Long> attachmentIds, String studentContent, ExamStudent t, ExamDetail examDetail, ExamDetailCourse examDetailCourse, Long userId, List<PdfDto> examStudentPdfList) throws IOException {
        if (Objects.nonNull(t.getAttachmentId())) {
            attachmentIds.add(t.getAttachmentId());
        }
        String studentHtml = studentContent;
        if (Objects.nonNull(t.getExtendFields())) {
            JSONArray jsonObjectExtend = (JSONArray) JSONArray.parse(t.getExtendFields());//扩展字段
            if (Objects.nonNull(jsonObjectExtend)) {
                for (int i = 0; i < jsonObjectExtend.size(); i++) {
                    JSONObject object = (JSONObject) jsonObjectExtend.get(i);
                    studentHtml = studentHtml.replaceAll("\\$\\{" + object.get("code") + "\\}", String.valueOf(object.get("value")));
                }
            }
        }
        //生成学生考号条码并将图片转成base64
        if (Objects.nonNull(t.getTicketNumber())) {
            studentHtml = studentHtml.replaceAll("\\$\\{examNumber\\}", GoogleBarCodeUtil.createBarCode(t.getTicketNumber(), false));
        }
        studentHtml = studentHtml.replaceAll("\\$\\{examNumberStr\\}", t.getTicketNumber());
        //随机生成学生试卷条码并将图片转成base64
        if (Objects.nonNull(t.getPaperType())) {
            studentHtml = studentHtml.replaceAll("\\$\\{paperType\\}", GoogleBarCodeUtil.createBarCode(SystemConstant.convertPaperType(t.getPaperType()), false));
        }
        Map<String, Object> map = ConvertUtil.analyzeDateAndTime(examDetail.getExamStartTime(), examDetail.getExamEndTime());
        String examDate = Objects.nonNull(map.get("date")) ? (String) map.get("date") : "";
        String examTime = Objects.nonNull(map.get("time")) ? (String) map.get("time") : "";
        studentHtml = studentHtml.replaceAll("\\$\\{examDate\\}", examDate);
        studentHtml = studentHtml.replaceAll("\\$\\{examTime\\}", examTime);
        studentHtml = studentHtml.replaceAll("\\$\\{ticketNumber\\}", t.getTicketNumber());
        studentHtml = studentHtml.replaceAll("\\$\\{siteNumber\\}", t.getSiteNumber());
        studentHtml = studentHtml.replaceAll("\\$\\{paperTypeName\\}", t.getPaperType());
        studentHtml = studentHtml.replaceAll("\\$\\{studentCode\\}", t.getStudentCode());
        studentHtml = studentHtml.replaceAll("\\$\\{studentName\\}", t.getStudentName());
        studentHtml = studentHtml.replaceAll("\\$\\{courseName\\}", examDetailCourse.getCourseName());
        studentHtml = studentHtml.replaceAll("\\$\\{courseCode\\}", examDetailCourse.getCourseCode());
        studentHtml = studentHtml.replaceAll("\\$\\{examPlace\\}", examDetail.getExamPlace());
        studentHtml = studentHtml.replaceAll("\\$\\{examRoom\\}", examDetail.getExamRoom());
        studentHtml = studentHtml.replaceAll("\\$\\{paperNumber\\}", examDetailCourse.getPaperNumber());

        //学生题卡
        BasicAttachment examStudentAttachment = printCommonService.saveAttachmentHtml(examDetail.getSchoolId() + "|" + examDetailCourse.getCourseCode() + "|" + t.getTicketNumber(), studentHtml, userId, examStudentPdfList);
        t.setAttachmentId(examStudentAttachment.getId());
        return examStudentAttachment;
    }

    /**
     * 通用题卡html
     *
     * @param cardContent
     * @param examDetailCourse
     * @param examCard
     * @param jsonArray
     * @param userId
     * @param cardPdfList
     * @param basicCardRule
     * @return
     * @throws IOException
     */
    public BasicAttachment cardHtml(String sequence, String cardContent, ExamDetail examDetail, ExamDetailCourse examDetailCourse, ExamCard examCard, JSONArray jsonArray, Long userId, List<PdfDto> cardPdfList, BasicCardRule basicCardRule) throws IOException {
        //通用题卡
        String cardTemp = cardContent;
        cardTemp = cardTemp.replaceAll("\\$\\{paperTypeName\\}", examDetailCourse.getPaperType());
        //随机生成试卷条码并将图片转成base64
        if (Objects.nonNull(examDetailCourse.getPaperType())) {
            cardTemp = cardTemp.replaceAll("\\$\\{paperType\\}", GoogleBarCodeUtil.createBarCode(SystemConstant.convertPaperType(examDetailCourse.getPaperType()), false));
        }
        if (Objects.nonNull(basicCardRule) && Objects.nonNull(basicCardRule.getExtendFields())) {
            JSONArray jsonObjectExtend = (JSONArray) JSONArray.parse(basicCardRule.getExtendFields());//扩展字段
            if (Objects.nonNull(jsonObjectExtend)) {
                for (int i = 0; i < jsonObjectExtend.size(); i++) {
                    JSONObject object = (JSONObject) jsonObjectExtend.get(i);
                    cardTemp = cardTemp.replaceAll("\\$\\{" + object.get("code") + "\\}", "");
                }
            }
        }
        cardTemp = cardTemp.replaceAll("\\$\\{examDate\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{examTime\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{ticketNumber\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{siteNumber\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{paperTypeName\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{studentCode\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{studentName\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{courseName\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{courseCode\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{examPlace\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{examRoom\\}", "");
        cardTemp = cardTemp.replaceAll("\\$\\{paperNumber\\}", "");

        //通用题卡生成卷袋贴条码
        String packageCode = examDetail.getPackageCode() + sequence;
        String packageCodeImg = null;
        if (Objects.nonNull(packageCode)) {
            packageCodeImg = GoogleBarCodeUtil.createBarCode(packageCode, false);
        }
        String packageCodeDiv = "<div class=\"page-box page-box-0\"><div class=\"package-number\" style=\"position: absolute;width: 200px;height: 40px;top: 10px;right: 25%;margin-left: -100px;text-align: center;z-index: 99;\"><img src=\"data:image/png;base64," + packageCodeImg + "\" style=\"display: block; height: 28px; width: 100%\" /><p style=\"line-height: 1; font-size: 12px; margin: 0;\">" + packageCode + "</p></div>";
        cardTemp = cardTemp.replaceAll("<div class=\"page-box page-box-0\">", packageCodeDiv);
        BasicAttachment cardAttachment = printCommonService.saveAttachmentHtml(examCard.getSchoolId() + "|" + examDetailCourse.getCourseCode(), cardTemp, userId, cardPdfList);
        JSONObject object = new JSONObject();
        object.put("name", examDetailCourse.getPaperType());
        object.put("examDetailCourseId", examDetailCourse.getId());
        object.put("attachmentId", cardAttachment.getId());
        object.put("packageCode", packageCode);
        jsonArray.add(object);
        return cardAttachment;
    }

    /**
     * 获取班级名称
     *
     * @param extendCloumn
     * @return
     */
    private String getClassName(String extendCloumn) {
        List<Map> mapList = JSONObject.parseArray(extendCloumn, Map.class);
        for (Map map : mapList) {
            if (Objects.equals("className", map.get("code").toString())) {
                return map.get("value").toString();
            }
        }
        return null;
    }
}
