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

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.qmth.distributed.print.business.bean.dto.CreatePdfDto;
import com.qmth.distributed.print.business.bean.dto.ExamStudentCourseDto;
import com.qmth.distributed.print.business.bean.dto.PaperPdfDto;
import com.qmth.distributed.print.business.bean.dto.PdfDto;
import com.qmth.distributed.print.business.entity.*;
import com.qmth.distributed.print.business.enums.ExamDetailStatusEnum;
import com.qmth.distributed.print.business.enums.ExamStatusEnum;
import com.qmth.distributed.print.business.enums.PrintPlanStatusEnum;
import com.qmth.distributed.print.business.service.*;
import com.qmth.distributed.print.business.templete.service.PdfTaskLogicService;
import com.qmth.distributed.print.business.util.PdfUtil;
import com.qmth.distributed.print.business.util.pdf.CreatePdfNewUtil;
import com.qmth.teachcloud.common.base.BaseEntity;
import com.qmth.teachcloud.common.bean.vo.FilePathVo;
import com.qmth.teachcloud.common.bean.vo.PaperInfoVo;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.BasicAttachment;
import com.qmth.teachcloud.common.entity.BasicExam;
import com.qmth.teachcloud.common.entity.BasicSchool;
import com.qmth.teachcloud.common.enums.*;
import com.qmth.teachcloud.common.service.BasicAttachmentService;
import com.qmth.teachcloud.common.service.BasicStudentService;
import com.qmth.teachcloud.common.service.CommonCacheService;
import com.qmth.teachcloud.common.service.FileUploadService;
import com.qmth.teachcloud.common.util.FileUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.File;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @Description: 任务处理逻辑impl
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2021/3/29
 */
@Service
public class PdfTaskLogicServiceImpl implements PdfTaskLogicService {
    private final static Logger log = LoggerFactory.getLogger(PdfTaskLogicServiceImpl.class);

    @Resource
    ExamPrintPlanService examPrintPlanService;
    @Resource
    ExamTaskService examTaskService;
    @Resource
    ExamTaskDetailService examTaskDetailService;
    @Resource
    ExamCardService examCardService;
    @Resource
    ExamStudentService examStudentService;
    @Resource
    BasicAttachmentService basicAttachmentService;
    @Resource
    ExamDetailService examDetailService;
    @Resource
    CommonCacheService commonCacheService;
    @Resource
    CreatePdfNewUtil createPdfNewUtil;
    @Resource
    BasicCardRuleService basicCardRuleService;
    @Autowired
    ExamDetailCourseService examDetailCourseService;
    @Autowired
    BasicStudentService basicStudentService;
    @Autowired
    ExamTaskPrintService examTaskPrintService;
    @Resource
    BasicExamService basicExamService;
    @Resource
    ExamTaskAssignPaperTypeService examTaskAssignPaperTypeService;
    @Resource
    private FileUploadService fileUploadService;

    @Override
    public void executeCreatePdfLogic(TBTaskPdf tbTaskPdf, StringJoiner stringJoinerSummary) {
        CreatePdfDto createPdfDto = new CreatePdfDto();
        try {
            long startTime = System.currentTimeMillis();
            addSummary(stringJoinerSummary, "开始处理数据");
            // 更新状态（考场状态、印刷计划状态）
            updatePdfDataStatus(tbTaskPdf);

            ExamDetail examDetail = examDetailService.getById(tbTaskPdf.getId());
            if (examDetail == null) {
                throw ExceptionResultEnum.EXAM_DETAIL_IS_NULL.exception();
            }
            createPdfDto.setExamDetail(examDetail);
            ExamPrintPlan examPrintPlan = examPrintPlanService.getById(examDetail.getPrintPlanId());
            if (examPrintPlan == null) {
                throw ExceptionResultEnum.EXAM_PRINT_IS_NULL.exception();
            }
            createPdfDto.setExamPrintPlan(examPrintPlan);
            List<ExamDetailCourse> examDetailCourseList = examDetailCourseService.listByExamDetailId(tbTaskPdf.getId());
            if (CollectionUtils.isEmpty(examDetailCourseList)) {
                throw ExceptionResultEnum.EXAM_DETAIL_COURSE_IS_NULL.exception();
            }
            createPdfDto.setExamDetailCourseList(examDetailCourseList);

            createPdfCore(tbTaskPdf, createPdfDto, stringJoinerSummary);
            long endTime = System.currentTimeMillis();
            addSummary(stringJoinerSummary, "pdf文件生成成功，共处理" + examDetail.getTotalSubjects() + "科次。耗时：" + (endTime - startTime) / 1000 + "秒");
        } catch (Exception e) {
            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
        } finally {
            if (CollectionUtils.isNotEmpty(createPdfDto.getFileTempList())) {
                for (File file : createPdfDto.getFileTempList()) {
                    FileUtil.deleteFile(file);
                }
            }
            //

        }
    }

    @Transactional
    public void createPdfCore(TBTaskPdf tbTaskPdf, CreatePdfDto createPdfDto, StringJoiner stringJoinerSummary) {
        ExamDetailStatusEnum examDetailStatusEnum = null;
        try {
            // 抽取卷型，更新考场、考生对应卷型值
            updateAssignPaperType(tbTaskPdf, createPdfDto);
            // 查询生成pdf需要文件
            assemblePdfFile(tbTaskPdf, createPdfDto);
            addSummary(stringJoinerSummary, "处理数据结束，准备生成pdf");
            // 生成pdf文件并合并
            //合并（试卷+备用试卷）
            String dirNamePaper = createPdfNewUtil.mergeA3Pdf(createPdfDto.getPaperPdfList());
            //合并A3（题卡+备用题卡）
            String dirNameCardA3 = createPdfNewUtil.mergeA3Pdf(createPdfDto.getCardPdfList());
            // 生成A4文件
            createA4File(tbTaskPdf, createPdfDto.getExamDetailCourseList(), createPdfDto.getFileTempList());
            // 更新文件路径、更新考场状态、印刷计划状态
            createPdfNewUtil.mergePdfSaveDb(dirNamePaper, dirNameCardA3, tbTaskPdf);
        } catch (Exception e) {
            examDetailStatusEnum = ExamDetailStatusEnum.NEW;
            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
        } finally {
            if (ExamDetailStatusEnum.NEW.equals(examDetailStatusEnum)) {
                examDetailService.updateStatusById(tbTaskPdf.getId(), examDetailStatusEnum);
            }
        }

    }

    private void updatePdfDataStatus(TBTaskPdf tbTaskPdf) {
        //查询printPlan
        ExamPrintPlan examPrintPlan = examPrintPlanService.getById(tbTaskPdf.getPrintPlanId());
        if (Objects.isNull(examPrintPlan)) {
            throw ExceptionResultEnum.EXAM_PRINT_IS_NULL.exception();
        }
        UpdateWrapper<ExamDetail> examDetailQueryWrapper = new UpdateWrapper<>();
        LambdaUpdateWrapper<ExamDetail> lambda = examDetailQueryWrapper.lambda();
        lambda.set(ExamDetail::getStatus, ExamDetailStatusEnum.CREATING);
        lambda.eq(ExamDetail::getId, tbTaskPdf.getId());
        lambda.eq(ExamDetail::getStatus, ExamDetailStatusEnum.NEW);
        examDetailService.update(examDetailQueryWrapper);

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

    @Transactional
    public void updateAssignPaperType(TBTaskPdf tbTaskPdf, CreatePdfDto createPdfDto) {
        for (ExamDetailCourse examDetailCourse : createPdfDto.getExamDetailCourseList()) {
            ExamTaskAssignPaperType examTaskAssignPaperType = examTaskAssignPaperTypeService.extractPaperType(tbTaskPdf, examDetailCourse);
            List<ExamStudent> examStudentList = examStudentService.listByExamDetailCourseId(examDetailCourse.getId());
            // 考生实际关联试卷类型
            List<String> relatePaperTypes = new ArrayList<>();
            List<String> paperTypes = Arrays.stream(examTaskAssignPaperType.getPaperType().split(",")).sorted(Comparator.comparing(String::valueOf)).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(examStudentList)) {
                AtomicInteger atomicInteger = new AtomicInteger(0);
                for (ExamStudent examStudent : examStudentList) {
                    int i1 = atomicInteger.getAndIncrement();
                    int mod = i1 % paperTypes.size();
                    examStudent.setPaperType(paperTypes.get(mod));
                    if (!relatePaperTypes.contains(examStudent.getPaperType())) {
                        relatePaperTypes.add(examStudent.getPaperType());
                    }
                }
            } else if (examDetailCourse.getTotalSubjects() != null) {
                if (examDetailCourse.getTotalSubjects().intValue() - paperTypes.size() >= 0) {
                    relatePaperTypes.addAll(paperTypes);
                } else {
                    for (int i = 0; i < examDetailCourse.getTotalSubjects().intValue(); i++) {
                        relatePaperTypes.add(paperTypes.get(i));
                    }
                }
            } else {
                relatePaperTypes.addAll(paperTypes);
            }

            // 更新卷型数据
            if (!CollectionUtils.isEqualCollection(paperTypes, relatePaperTypes)) {
                examTaskAssignPaperType.setPaperType(String.join(",", relatePaperTypes));
                examTaskAssignPaperTypeService.updateByMultiId(examTaskAssignPaperType);
            }

            examDetailCourse.setPaperType(String.join(",", relatePaperTypes));
            examDetailCourseService.updateById(examDetailCourse);

            examStudentService.updateBatchById(examStudentList);
        }
    }

    private void assemblePdfFile(TBTaskPdf tbTaskPdf, CreatePdfDto createPdfDto) throws Exception {
        ExamDetail examDetail = createPdfDto.getExamDetail();
        ExamPrintPlan examPrintPlan = createPdfDto.getExamPrintPlan();

        for (ExamDetailCourse examDetailCourse : createPdfDto.getExamDetailCourseList()) {
            String[] paperTypes = examDetailCourse.getPaperType().split(",");

            //查询命题任务绑定的试卷和题卡
            ExamTask examTask = examTaskService.getByExamIdAndCourseCodeAndPaperNumber(tbTaskPdf.getExamId(), examDetailCourse.getCourseCode(), examDetailCourse.getPaperNumber());
            if (examTask == null) {
                throw ExceptionResultEnum.EXAM_TASK_IS_NULL.exception();
            } else if (examTask.getReview()) {
                examTask = examTaskService.findExamTaskByFlowStatus(tbTaskPdf.getSchoolId(), tbTaskPdf.getExamId(), examDetailCourse.getCourseCode(), examDetailCourse.getPaperNumber(), FlowStatusEnum.FINISH);
            } else {
                if (!ExamStatusEnum.SUBMIT.equals(examTask.getStatus())) {
                    throw ExceptionResultEnum.EXAM_TASK_NOT_SUBMIT.exception();
                } else if (!examTask.getEnable()) {
                    throw ExceptionResultEnum.EXAM_TASK_ENABLE.exception();
                }
            }
            ExamTaskDetail examTaskDetail = examTaskDetailService.getByExamTaskId(examTask.getId());

            CreatePdfTypeEnum createPdfType = tbTaskPdf.getCreateType();
            String printContent = examPrintPlan.getPrintContent();
            if (StringUtils.isBlank(printContent)) {
                throw ExceptionResultEnum.ERROR.exception("印刷计划未设置打印内容，[试卷、题卡]至少选择一项");
            }
            // 计算备份数量，默认最小为1份。
            int backupCount = SystemConstant.calcBackupCount(examDetail.getBackupCount(), examDetail.getTotalSubjects(), 1);

            List<ExamStudent> examStudentList = examStudentService.listByExamDetailCourseId(examDetailCourse.getId());
            // 试卷数据组装
            if ((CreatePdfTypeEnum.ALL.equals(createPdfType) || CreatePdfTypeEnum.PAPER.equals(createPdfType)) && printContent.contains("PAPER")) {
                List<PaperPdfDto> paperPdfDtoList = createPdfNewUtil.getPaperPdfFile(examDetailCourse.getPaperType(), examTaskDetail.getPaperInfoVoList(null), createPdfDto);
                // 生成考生试卷
                if (CollectionUtils.isNotEmpty(examStudentList)) {
                    for (ExamStudent t : examStudentList) {
                        String[] waterMarkNames = {t.getStudentName(), t.getTicketNumber()};
                        createPdfNewUtil.getExamStudentPaperPdf(t.getPaperType(), paperPdfDtoList, createPdfDto, waterMarkNames);
                    }
                } else if (examDetail.getTotalSubjects() != null) {
                    AtomicInteger atomicInteger = new AtomicInteger(0);
                    int i = 0;
                    while (i < examDetail.getTotalSubjects()) {
                        int seq = atomicInteger.getAndIncrement();
                        int mod = seq % paperTypes.length;
                        createPdfNewUtil.getExamStudentPaperPdf(paperTypes[mod], paperPdfDtoList, createPdfDto, null);
                        i++;
                    }
                } else {
                    throw ExceptionResultEnum.ERROR.exception("考试数据有误，未找到考生或者印刷数量");
                }

                // 获取备份试卷
                PdfDto pdfDto = createPdfNewUtil.getBackupPaperPdfList(paperPdfDtoList, backupCount, createPdfDto);
                if (Objects.nonNull(pdfDto)) {
                    examDetailCourse.setPaperPagesA3(pdfDto.getPageCount());
                }
            }

            // 题卡数据组装
            if ((CreatePdfTypeEnum.ALL.equals(createPdfType) || CreatePdfTypeEnum.CARD_A3.equals(createPdfType)) && printContent.contains("CARD")) {
                //查询题卡规则
                BasicCardRule basicCardRule = basicCardRuleService.getById(examTask.getCardRuleId());
                Map<String, ExamCard> examCardMap = new HashMap<>();
                ExamCard examCard;
                for (PaperInfoVo paperInfoVo : examTaskDetail.getPaperInfoVoList(null)) {
                    if (StringUtils.isNotBlank(paperInfoVo.getCardId())) {
                        examCard = examCardService.getById(paperInfoVo.getCardId());
                        if (Objects.isNull(examCard)) {
                            throw ExceptionResultEnum.EXAM_CARD_IS_NULL.exception();
                        }
                        examCardMap.put(paperInfoVo.getName(), examCard);
                    }
                }

                JSONArray stuJsonArray = new JSONArray();
                if (examStudentList != null && examStudentList.size() > 0) {
                    for (ExamStudent t : examStudentList) {
                        // 用带条码的模板
                        createPdfNewUtil.examStudentHtml(examCardMap.get(t.getPaperType()).getHtmlContent(), t, t.getPaperType(), examDetail, tbTaskPdf.getCreateId(), createPdfDto.getCardPdfList(), createPdfDto.getFileTempList(), basicCardRule);
                    }
                    examStudentService.updateBatchById(examStudentList);
                } else if (examDetailCourse.getTotalSubjects() != null) {
                    AtomicInteger atomicInteger = new AtomicInteger(0);
                    Map<String, BasicAttachment> stringBasicAttachmentMap = new HashMap<>();
                    int i = 0;
                    while (i < examDetailCourse.getTotalSubjects()) {
                        int seq = atomicInteger.getAndIncrement();
                        int mod = seq % examTaskDetail.getDrawCount();
                        String tempPaperType = paperTypes[mod];
                        BasicAttachment basicAttachment = createPdfNewUtil.examStudentHtml(examCardMap.get(tempPaperType).getHtmlContent(), null, tempPaperType, examDetail, tbTaskPdf.getCreateId(), createPdfDto.getCardPdfList(), createPdfDto.getFileTempList(), basicCardRule);

                        if (!stringBasicAttachmentMap.containsKey(tempPaperType)) {
                            stringBasicAttachmentMap.put(tempPaperType, basicAttachment);
                            JSONObject object = new JSONObject();
                            object.put("name", tempPaperType);
                            object.put("attachmentId", basicAttachment.getId());
                            stuJsonArray.add(object);
                        }
                        i++;
                    }
                    examDetailCourse.setCommonAttachmentId(stuJsonArray.toJSONString());
                } else {
                    throw ExceptionResultEnum.ERROR.exception("数据错误：未找到考生或者印刷数量");
                }

                JSONObject jsonObject = new JSONObject();
                JSONArray jsonArray = new JSONArray();
                for (String s : paperTypes) {
                    examCard = examCardMap.get(s);
                    for (int i = 1; i <= backupCount; i++) {
                        String backupPackageCode = examDetail.getPackageCode() + String.format(SystemConstant.DATE_TIME_FORMAT, i);
                        String replaceBackupCardHtmlContent = createPdfNewUtil.replaceBackupCardHtmlParam(examCard.getHtmlContent(), s, basicCardRule, backupPackageCode);
                        File pdfFile = PdfUtil.htmlToPdf(replaceBackupCardHtmlContent);
                        PdfDto pdfDto = PdfUtil.addPdfPage(pdfFile);
                        FilePathVo filePathVo = fileUploadService.uploadFile(pdfFile, UploadFileEnum.PDF, pdfFile.getName());
                        BasicAttachment basicAttachment = new BasicAttachment(JSON.toJSONString(filePathVo), pdfFile.getName(), SystemConstant.PDF_PREFIX, new BigDecimal(pdfFile.length()), filePathVo.getMd5(), tbTaskPdf.getCreateId());
                        basicAttachmentService.save(basicAttachment);

                        examDetailCourse.setCardPagesA3(pdfDto.getActualPageCount());

                        // 备用题卡
                        createPdfDto.getCardPdfList().add(new PdfDto(pdfFile.getPath(), PageSizeEnum.A3, pdfDto.getPageCount()));

                        JSONObject object = new JSONObject();
                        object.put("name", s);
                        object.put("attachmentId", basicAttachment.getId());
                        object.put("packageCode", backupPackageCode);
                        jsonArray.add(object);
                    }
                }
                jsonObject.put("card", jsonArray);
                examDetailCourse.setAttachmentId(jsonObject.toJSONString());
            }
            examDetailCourseService.updateById(examDetailCourse);
        }
    }

    /**
     * 创建A4文件
     *
     * @param tbTaskPdf
     * @param examDetailCourseList
     * @param fileTempList
     * @throws Exception
     */
    @Transactional
    public void createA4File(TBTaskPdf tbTaskPdf, List<ExamDetailCourse> examDetailCourseList, List<File> fileTempList) throws Exception {
        CreatePdfTypeEnum createPdfType = tbTaskPdf.getCreateType();
        ExamPrintPlan examPrintPlan = examPrintPlanService.getById(tbTaskPdf.getPrintPlanId());
        ExamDetail examDetail = examDetailService.getById(tbTaskPdf.getId());
        BasicSchool basicSchool = commonCacheService.schoolCache(tbTaskPdf.getSchoolId());
        // 印品
        String ordinaryContent = examPrintPlan.getOrdinaryContent();
        if ((CreatePdfTypeEnum.ALL.equals(createPdfType) || CreatePdfTypeEnum.CHECK_IN.equals(createPdfType)) && StringUtils.isNotBlank(ordinaryContent)) {
            //获取普通印品
            JSONArray jsonArrayOrdinary = JSONArray.parseArray(ordinaryContent);
            for (int i = 0; i < jsonArrayOrdinary.size(); i++) {
                JSONObject jsonObjectOrdinary = jsonArrayOrdinary.getJSONObject(i);
                if (Objects.nonNull(jsonObjectOrdinary.get("attachmentId")) && !Objects.equals("", jsonObjectOrdinary.get("attachmentId"))) {
                    Long attachmentId = Long.parseLong((String) jsonObjectOrdinary.get("attachmentId"));
                    BasicAttachment basicAttachment = basicAttachmentService.getById(attachmentId);
                    createPdfNewUtil.createCheckIn(examDetail, basicAttachment, (Integer) jsonObjectOrdinary.get("backupCount"), fileTempList);
                }
            }
        }
        BasicExam basicExam = basicExamService.getById(examPrintPlan.getExamId());
        if (basicExam.getCategory().equals(ExamCategoryEnum.FORMAL)) {
            String variableContent = examPrintPlan.getVariableContent();
            if (StringUtils.isNotBlank(variableContent)) {
                List<Long> examDetailCourseListIds = examDetailCourseList.stream().map(BaseEntity::getId).collect(Collectors.toList());
                List<ExamStudentCourseDto> examStudentCourseDtoList = examStudentService.queryBySchoolIdAndExamDetailCourseIds(basicSchool.getId(), examDetailCourseListIds);
                //获取变量印品
                JSONArray jsonArrayVariable = JSONArray.parseArray(variableContent);
                for (int i = 0; i < jsonArrayVariable.size(); i++) {
                    JSONObject jsonObjectVariable = jsonArrayVariable.getJSONObject(i);
                    String type = (String) jsonObjectVariable.get("type");
                    if (Objects.nonNull(jsonObjectVariable.get("templateId")) && !Objects.equals("", jsonObjectVariable.get("templateId"))) {
                        Long templateId = Long.parseLong((String) jsonObjectVariable.get("templateId"));
                        if ((CreatePdfTypeEnum.ALL.equals(createPdfType) || CreatePdfTypeEnum.SIGN.equals(createPdfType)) && Objects.nonNull(type) && Objects.equals(type.toUpperCase(), "SIGN")) {//签到表
                            createPdfNewUtil.createSignBook(templateId, basicSchool.getName(), examDetail, examStudentCourseDtoList, (Integer) jsonObjectVariable.get("backupCount"), examDetailCourseList);
                        } else if ((CreatePdfTypeEnum.ALL.equals(createPdfType) || CreatePdfTypeEnum.PACKAGE.equals(createPdfType)) && Objects.nonNull(type) && Objects.equals(type.toUpperCase(), "PACKAGE")) {//卷袋贴
                            Integer backupCount = SystemConstant.calcBackupCount(examDetail.getBackupCount(), examDetail.getTotalSubjects(), 1);
                            createPdfNewUtil.createPaperPackage(templateId, basicSchool.getName(), examDetail, examStudentCourseDtoList, backupCount, (Integer) jsonObjectVariable.get("backupCount"), examDetailCourseList, examPrintPlan.getExamId());
                        }
                    }
                }
            }
        }
        examDetailService.updateById(examDetail);
    }

    /**
     * 写入概要信息
     *
     * @param stringJoinerSummary
     * @param message
     */
    private void addSummary(StringJoiner stringJoinerSummary, String message) {
        // 时间：事件
        stringJoinerSummary.add(MessageFormat.format("{0}{1}{2}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), "->", message));
    }

}
