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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
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.qmth.distributed.print.business.bean.dto.*;
import com.qmth.distributed.print.business.bean.dto.client.PrintSingleDto;
import com.qmth.distributed.print.business.bean.dto.client.UrlMd5Dto;
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.mapper.ClientMapper;
import com.qmth.distributed.print.business.service.*;
import com.qmth.teachcloud.common.bean.vo.FilePathVo;
import com.qmth.teachcloud.common.bean.vo.PaperInfoVo;
import com.qmth.teachcloud.common.bean.vo.PrintPathVo;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.BasicAttachment;
import com.qmth.teachcloud.common.entity.BasicSchool;
import com.qmth.teachcloud.common.entity.SysPrivilege;
import com.qmth.teachcloud.common.entity.SysUser;
import com.qmth.teachcloud.common.enums.ClassifyEnum;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.enums.RoleTypeEnum;
import com.qmth.teachcloud.common.service.*;
import com.qmth.teachcloud.common.util.ExamTaskUtil;
import com.qmth.teachcloud.common.util.ExcelUtil;
import com.qmth.teachcloud.common.util.ServletUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 客户端
 */
@Service
public class ClientServiceImpl implements ClientService {

    @Resource
    private ExamTaskService examTaskService;
    @Resource
    private ExamTaskDetailService examTaskDetailService;
    @Resource
    private ClientStatusService clientStatusService;
    @Resource
    private ExamDetailService examDetailService;
    @Resource
    private ExamDetailCourseService examDetailCourseService;
    @Resource
    private ClientPrintDataService clientPrintDataService;
    @Resource
    private BasicAttachmentService basicAttachmentService;
    @Resource
    private ExamPrintPlanService examPrintPlanService;
    @Resource
    private ExamStudentService examStudentService;
    @Resource
    private ExamCardService examCardService;
    @Resource
    private TeachcloudCommonService teachcloudCommonService;
    @Resource
    private SysPrivilegeService sysPrivilegeService;
    @Resource
    private SysUserService sysUserService;
    @Resource
    private BasicSchoolService basicSchoolService;
    @Resource
    private ClientMapper clientMapper;

    @Override
    public IPage<ClientExamTaskDto> listTryTask(String machineCode, Long orgId, Long semesterId, Long examId, Long printPlanId, String courseCode, String paperNumber, Boolean isTry, Boolean isPass, Integer pageNumber, Integer pageSize) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        Page<ClientExamTaskDto> page = new Page<>(pageNumber, pageSize);
        // 印刷任务状态为印刷中（PRINTING）,考场状态为待打印（WAITING）
        String[] examDetailStatus = {ExamDetailStatusEnum.NEW.name(), ExamDetailStatusEnum.READY.name(), ExamDetailStatusEnum.CANCEL.name()};
        return clientMapper.pageTryTask(page, schoolId, semesterId, examId, machineCode, orgId, printPlanId, courseCode, paperNumber, isTry, isPass, PrintPlanStatusEnum.PRINTING.name(), examDetailStatus);
    }

    @Override
    public List<Map<String, Object>> getPaperUrl(List<JSONObject> objects) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        List<Map<String, Object>> finalList = new ArrayList<>();
        for (JSONObject object : objects) {
            Long printPlanId = object.getLong("printPlanId");
            Long examTaskId = object.getLong("examTaskId");
            ExamTask examTask = examTaskService.getById(examTaskId);
            Map<String, Object> map = new HashMap<>();
            map.put("printPlanId", printPlanId);
            map.put("courseCode", examTask.getCourseCode());
            map.put("courseName", examTask.getCourseName());
            map.put("paperNumber", examTask.getPaperNumber());
            List<Map<String, String>> mapList = this.getPaperUrl(schoolId, printPlanId, examTaskId);
            map.put("list", mapList);
            finalList.add(map);
        }
        return finalList;
    }

    @Override
    public Boolean tagPass(Long printPlanId, String courseCode, String courseName, String paperNumber, String machineCode, Boolean isPass, Long userId) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        return clientStatusService.tagPass(schoolId, printPlanId, courseCode, courseName, paperNumber, machineCode, isPass, userId);
    }

    @Override
    public Boolean updatePrintProgress(Long examDetailId, String machineCode, Integer printProgress, Boolean isPrint) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        ExamDetail examDetail = examDetailService.getById(examDetailId);
        // 撤回提示
        if (ExamDetailStatusEnum.NEW.name().equals(examDetail.getStatus())
                || ExamDetailStatusEnum.READY.name().equals(examDetail.getStatus())) {
            throw ExceptionResultEnum.ERROR.exception("该任务已被撤回");
        }

        if (isPrint) {
            // 更新考场进度、状态、打印结束时间
            UpdateWrapper<ExamDetail> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().set(ExamDetail::getPrintProgress, printProgress).set(ExamDetail::getPrintEndTime, System.currentTimeMillis()).set(ExamDetail::getStatus, ExamDetailStatusEnum.FINISH).eq(ExamDetail::getId, examDetailId);
            examDetailService.update(updateWrapper);

            // 所有考场打印完成，更新印刷计划状态
            examPrintPlanService.updateStatusById(examDetail.getPrintPlanId(), PrintPlanStatusEnum.FINISH);

            // 记录机器打印数量
            SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
            ClientPrintData clientPrintData = new ClientPrintData();
            clientPrintData.setId(SystemConstant.getDbUuid());
            clientPrintData.setSchoolId(schoolId);
            clientPrintData.setExamDetailId(examDetailId);
            clientPrintData.setMachineCode(machineCode);
            clientPrintData.setPaperPages(examDetail.getPaperPages());
            clientPrintData.setCardPages(examDetail.getCardPages());
            clientPrintData.setPagesA4(examDetail.getPagesA4());
            clientPrintData.setCreateId(sysUser.getId());
            clientPrintData.setCreateTime(System.currentTimeMillis());
            clientPrintDataService.save(clientPrintData);
        } else {
            // 更新打印结束时间
            UpdateWrapper<ExamDetail> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().set(ExamDetail::getPrintEndTime, System.currentTimeMillis()).eq(ExamDetail::getId, examDetailId);
            examDetailService.update(updateWrapper);
        }
        return true;
    }

    @Override
    public IPage<ClientExamStudentDto> listStudent(Long examDetailId, String studentCode, String studentName, String courseCode, Integer pageNumber, Integer pageSize) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        // 撤回提示
        ExamDetail examDetail = examDetailService.getById(examDetailId);
        if (ExamDetailStatusEnum.NEW.name().equals(examDetail.getStatus())
                || ExamDetailStatusEnum.READY.name().equals(examDetail.getStatus())) {
            throw ExceptionResultEnum.ERROR.exception("该任务已被撤回");
        }
        Page<ClientExamStudentDto> page = new Page<>(pageNumber, pageSize);
        return clientMapper.listClientExamStudentPage(page, schoolId, examDetailId, SystemConstant.translateSpecificSign(studentCode), SystemConstant.translateSpecificSign(studentName), courseCode);
    }


    @Override
    public Map<String, Object> getReprintData(Long examDetailId, String studentCode, String type) {
        Map<String, Object> finalMap = new HashMap<>();
        ExamDetail examDetail = examDetailService.getById(examDetailId);
        // 撤回提示
        if (ExamDetailStatusEnum.NEW.name().equals(examDetail.getStatus())
                || ExamDetailStatusEnum.READY.name().equals(examDetail.getStatus())) {
            throw ExceptionResultEnum.ERROR.exception("该任务已被撤回");
        }

        ExamPrintPlan examPrintPlan = examPrintPlanService.getById(examDetail.getPrintPlanId());
        String printContent = examPrintPlan.getPrintContent();
        // 取试卷
        List<Map<String, Object>> examDetailCourses = examDetailCourseService.listClientByExamDetailIdAndStatus(examDetailId);
        Map<String, Map<String, String>> map = mapCourseUrl(examDetailCourses);
        // 生成试卷List
        if (printContent.contains("PAPER")) {
            finalMap.put("paper", splicePaperContent(examDetailCourses, map, studentCode, type));
        }
        if (printContent.contains("CARD")) {
            // 生成题卡List
            finalMap.put("card", spliceCardContent(examDetailCourses, studentCode, type));
        }
        //

        String variableContent = examPrintPlan.getVariableContent();
        String ordinaryContent = examPrintPlan.getOrdinaryContent();
        List<Map> variableList = JSONObject.parseArray(variableContent, Map.class);
        List<Map> otherList = new ArrayList<>();
        //印品附件信息
        String attachmentPath = examDetail.getAttachmentPath();
        if (StringUtils.isNotBlank(attachmentPath)) {
            JSONObject jsonObject = JSONObject.parseObject(attachmentPath);
            String pathString = jsonObject.getString("path");
            List<Map> pathList = JSONObject.parseArray(pathString, Map.class);
            if (!pathList.isEmpty()) {
                for (Map contentMap : variableList) {
                    spliceOtherContent(otherList, pathList, contentMap);
                }
                List<Map> ordinaryList = JSONObject.parseArray(ordinaryContent, Map.class);
                for (Map contentMap : ordinaryList) {
                    spliceOtherContent(otherList, pathList, contentMap);
                }
            }
        }
        finalMap.put("other", otherList);
        return finalMap;
    }

    @Override
    public IPage<ClientPrintTaskDto> listClientPrintTask(String machineCode, Long orgId, Long semesterId, Long examId, String printPlanId, String status, String courseCode, String paperNumber, String examPlace, String examRoom, Long examStartTime, Long examEndTime, Boolean isDownload, Boolean validate, Integer pageNumber, Integer pageSize) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        Page<ClientPrintTaskDto> page = new Page<>(pageNumber, pageSize);
        // 以下状态考场状态不可查询
        String[] examDetailStatus = new String[]{ExamDetailStatusEnum.NEW.name(), ExamDetailStatusEnum.READY.name(), ExamDetailStatusEnum.CANCEL.name()};
        IPage<ClientPrintTaskDto> clientPrintTaskDtoIPage = clientMapper.listClientPrintTask(page, schoolId, semesterId, examId, machineCode, printPlanId, status, courseCode, paperNumber, examPlace, examRoom, examStartTime, examEndTime, isDownload, validate, orgId, examDetailStatus);
        for (ClientPrintTaskDto record : clientPrintTaskDtoIPage.getRecords()) {
            // 试卷、题卡
            String printContent = record.getPrintContent();
            record.setIncluedPaper(!StringUtils.isBlank(printContent) && printContent.contains("PAPER"));
            record.setIncluedCard(!StringUtils.isBlank(printContent) && printContent.contains("CARD"));

            //印品
            String variableContent = record.getVariableContent();
            List<Map> variableList = JSONObject.parseArray(variableContent, Map.class);
            record.setIncluedSign(false);
            record.setIncluedPackage(false);
            for (Map map : variableList) {
                String type = map.get("type").toString();
                String templateId = map.get("templateId").toString();
                if (ClassifyEnum.SIGN.name().equals(type) && StringUtils.isNotBlank(templateId)) {
                    record.setIncluedSign(true);
                }
                if (ClassifyEnum.PACKAGE.name().equals(type) && StringUtils.isNotBlank(templateId)) {
                    record.setIncluedPackage(true);
                }
            }
            String ordinaryContent = record.getOrdinaryContent();
            List<Map> ordinaryList = JSONObject.parseArray(ordinaryContent, Map.class);
            record.setIncluedCheckin(false);
            for (Map map : ordinaryList) {
                String type = map.get("type").toString();
                String templateId = map.get("templateId").toString();
                if (ClassifyEnum.CHECK_IN.name().equals(type) && StringUtils.isNotBlank(templateId)) {
                    record.setIncluedCheckin(true);
                }
            }

            if (StringUtils.isNotBlank(record.getClassName())) {
                record.setClassName(String.join(",", new HashSet<>(Arrays.asList(record.getClassName().split(",")))));
            }
        }
        return clientPrintTaskDtoIPage;
    }

    @Transactional
    @Override
    public List<Map<String, Object>> getPrintData(String examDetailIds, String machineCode, Boolean isPrint, String printUser) {
        String[] strings = examDetailIds.split(",");
        if (strings.length == 0) {
            throw ExceptionResultEnum.ERROR.exception("请选择数据");
        }

        List<Map<String, Object>> finalList = new ArrayList<>();
        for (String string : strings) {
            Long examDetailId = Long.valueOf(string);
            ExamDetail examDetail = examDetailService.getById(examDetailId);
            // 撤回提示
            if (ExamDetailStatusEnum.NEW.equals(examDetail.getStatus()) || ExamDetailStatusEnum.READY.equals(examDetail.getStatus())) {
                throw ExceptionResultEnum.ERROR.exception("该任务已被撤回");
            }
            if (isPrint && StringUtils.isBlank(printUser)) {
                throw ExceptionResultEnum.ERROR.exception("打印员不能为空");
            }
            if (isPrint && StringUtils.isNotBlank(examDetail.getPrintUser()) && !examDetail.getPrintUser().equals(printUser)) {
                throw ExceptionResultEnum.ERROR.exception("卷袋编号[" + examDetail.getPackageCode() + "]的打印任务已被印刷员[" + examDetail.getPrintUser() + "]占用");
            }

            // 课程、试卷信息
            List<Map<String, Object>> examDetailCourses = examDetailCourseService.listClientByExamDetailIdAndStatus(examDetailId);

            Map<String, Object> finalMap = new HashMap<>();
            ExamPrintPlan examPrintPlan = examPrintPlanService.getById(examDetail.getPrintPlanId());
            // 2.取生成的完整的pdf
            String printContent = examPrintPlan.getPrintContent();
            // 是否包含试卷、题卡
            if (StringUtils.isNotBlank(printContent)) {
                // 试卷、题卡map
                Map<String, Object> detailMap = new HashMap<>();
                // 备用试卷、备用题卡map
                Map<String, Object> backupMap = new HashMap<>();
                // 备份数量
                int backupCount = SystemConstant.calcBackupCount(examDetail.getBackupCount(), examDetail.getTotalSubjects(), 1);
                if (printContent.contains("PAPER")) {
                    if (examDetail.getAttachmentId() == null) {
                        throw ExceptionResultEnum.ERROR.exception("考场pdf文件未生成");
                    }

                    BasicAttachment attachment = basicAttachmentService.getById(examDetail.getAttachmentId());
                    if (attachment == null) {
                        throw ExceptionResultEnum.ERROR.exception("考场pdf文件记录异常");
                    }

                    Map<String, String> totalPathUrl = teachcloudCommonService.filePreviewByAttachmentId(examDetail.getAttachmentId(), false);
                    if (StringUtils.isBlank(totalPathUrl.get("url"))) {
                        throw ExceptionResultEnum.ERROR.exception("考场pdf文件丢失");
                    }

                    finalMap.put("paperTotal", totalPathUrl);
                    // 取试卷
                    Map<String, Map<String, String>> map = mapCourseUrl(examDetailCourses);
                    // 生成试卷List
                    detailMap.put("paper", splicePaperContent(examDetailCourses, map, null, null));
                    //试卷
                    List<Map<String, String>> keyMaps = examDetailCourses.stream().map(m -> {
                        Map<String, String> stringMap = new HashMap<>();
                        stringMap.put("courseCode", m.get("courseCode").toString());
                        stringMap.put("courseName", m.get("courseName").toString());
                        stringMap.put("paperNumber", m.get("paperNumber").toString());
                        stringMap.put("paperType", m.get("paperType").toString());
                        return stringMap;
                    }).distinct().collect(Collectors.toList());
                    List<ClientPrintBackupDataDto> paperBackupList = new ArrayList<>();
                    for (Map<String, String> keyMap : keyMaps) {
                        List<String> paperTypes = Arrays.stream(keyMap.get("paperType").split(",")).sorted(Comparator.comparing(String::valueOf)).collect(Collectors.toList());
                        for (String paperType : paperTypes) {
                            for (int i = 0; i < backupCount; i++) {
                                ClientPrintBackupDataDto clientPrintBackupDataDto = new ClientPrintBackupDataDto();
                                clientPrintBackupDataDto.setCourseCode(keyMap.get("courseCode"));
                                clientPrintBackupDataDto.setCourseName(keyMap.get("courseName"));
                                clientPrintBackupDataDto.setPaperNumber(keyMap.get("paperNumber"));
                                clientPrintBackupDataDto.setPaperType(paperType);
                                StringJoiner sj = new StringJoiner(SystemConstant.DELIMITER);
                                String key = sj.add(keyMap.get("courseCode")).add(keyMap.get("paperNumber")).add(paperType).toString();
                                clientPrintBackupDataDto.setMd5(map.get(key).get("md5"));
                                clientPrintBackupDataDto.setUrl(map.get(key).get("url"));
                                paperBackupList.add(clientPrintBackupDataDto);
                            }
                        }
                    }
                    backupMap.put("paper", paperBackupList);
                }

                if (printContent.contains("CARD")) {
                    Map<String, String> totalCardPathUrl = teachcloudCommonService.filePreviewByAttachmentId(examDetail.getCardAttachmentId(), false);
                    finalMap.put("cardTotal", totalCardPathUrl);

                    // 生成题卡List
                    detailMap.put("card", spliceCardContent(examDetailCourses, null, null));

                    // 备用题卡
                    List<ClientPrintBackupDataDto> cardBackupList = new ArrayList<>();
//                    for (Map<String, Object> examDetailCours : examDetailCourses) {
//                        String attachmentIds = examDetailCours.get("cardAttachmentIds").toString();
//                        if (StringUtils.isBlank(attachmentIds)) {
//                            throw ExceptionResultEnum.ERROR.exception("备用题卡未生成");
//                        }
//                        JSONObject jsonObject = JSONObject.parseObject(attachmentIds);
//                        List<Map> backupCards = JSONObject.parseArray(JSONObject.toJSONString(jsonObject.get("card")), Map.class);
//                        for (Map backupCard : backupCards) {
//                            ClientPrintBackupDataDto clientPrintBackupDataDto = new ClientPrintBackupDataDto();
//                            clientPrintBackupDataDto.setCourseCode(examDetailCours.get("courseCode").toString());
//                            clientPrintBackupDataDto.setCourseName(examDetailCours.get("courseName").toString());
//                            clientPrintBackupDataDto.setPaperNumber(examDetailCours.get("paperNumber").toString());
//                            clientPrintBackupDataDto.setPaperType(backupCard.get("name").toString());
//                            Map<String, String> urlMap = teachcloudCommonService.filePreviewByAttachmentId(Long.valueOf(backupCard.get("attachmentId").toString()), false);
//                            clientPrintBackupDataDto.setMd5(urlMap.get("md5"));
//                            clientPrintBackupDataDto.setUrl(urlMap.get("url"));
//                            cardBackupList.add(clientPrintBackupDataDto);
//                        }
//                    }
                    backupMap.put("card", cardBackupList);
                }
                detailMap.put("backup", backupMap);
                finalMap.put("detail", detailMap);
            }

            //3.5
            String variableContent = examPrintPlan.getVariableContent();
            String ordinaryContent = examPrintPlan.getOrdinaryContent();
            List<Map> variableList = JSONObject.parseArray(variableContent, Map.class);
            List<Map> otherList = new ArrayList<>();
            //印品附件信息
            String attachmentPath = examDetail.getAttachmentPath();
            if (StringUtils.isNotBlank(attachmentPath)) {
                JSONObject jsonObject = JSONObject.parseObject(attachmentPath);
                String pathString = jsonObject.getString("path");
                List<Map> pathList = JSONObject.parseArray(pathString, Map.class);
                if (!pathList.isEmpty()) {
                    for (Map contentMap : variableList) {
                        int count = Integer.parseInt(contentMap.get("backupCount").toString());
                        for (int i = 0; i < count; i++) {
                            spliceOtherContent(otherList, pathList, contentMap);
                        }
                    }
                    List<Map> ordinaryList = JSONObject.parseArray(ordinaryContent, Map.class);
                    for (Map contentMap : ordinaryList) {
                        int count = Integer.parseInt(contentMap.get("backupCount").toString());
                        for (int i = 0; i < count; i++) {
                            spliceOtherContent(otherList, pathList, contentMap);
                        }

                    }
                }
            }
            finalMap.put("other", otherList);

            // 更新印刷中状态，更新曝光卷型、未曝光卷型,打印开始时间
            if (isPrint) {
                // 更新exam_detail状态为印刷中
                UpdateWrapper<ExamDetail> examDetailUpdateWrapper = new UpdateWrapper<>();
                examDetailUpdateWrapper.lambda().set(ExamDetail::getStatus, ExamDetailStatusEnum.PRINTING).set(ExamDetail::getPrintStartTime, System.currentTimeMillis()).set(ExamDetail::getPrintUser, printUser).eq(ExamDetail::getId, examDetailId);
                examDetailService.update(examDetailUpdateWrapper);

                // 更新曝光卷型、未曝光卷型
                for (Map<String, Object> examDetailCours : examDetailCourses) {
                    String examDetailCourseId = examDetailCours.get("examDetailCourseId").toString();
                    // 考生使用卷型
                    List<String> studentPaperTypes = examStudentService.listPaperTypeByExamDetailCourseId(examDetailCourseId);
                    Object exposedPaperType = examDetailCours.get("exposedPaperType");
                    Set<String> exposedPaperSet = Objects.isNull(exposedPaperType) ? new HashSet<>() : new HashSet<>(Arrays.asList(exposedPaperType.toString().split(",")));
                    Object unexposedPaperType = examDetailCours.get("unexposedPaperType");
                    Set<String> unexposedPaperSet = Objects.isNull(unexposedPaperType) ? new HashSet<>() : new HashSet<>(Arrays.asList(unexposedPaperType.toString().split(",")));
                    if (!studentPaperTypes.isEmpty()) {
                        for (String studentPaperType : studentPaperTypes) {
                            exposedPaperSet.add(studentPaperType);
                            unexposedPaperSet.remove(studentPaperType);
                        }
                    }
                    String examTaskId = examDetailCours.get("examTaskId").toString();
                    UpdateWrapper<ExamTaskDetail> examTaskDetailUpdateWrapper = new UpdateWrapper<>();
                    String exposedPaper = String.join(",", exposedPaperSet);
                    String unexposedPaper = String.join(",", unexposedPaperSet);
                    examTaskDetailUpdateWrapper.lambda()
                            .set(ExamTaskDetail::getExposedPaperType, StringUtils.isBlank(exposedPaper) ? null : exposedPaper)
                            .set(ExamTaskDetail::getUnexposedPaperType, StringUtils.isBlank(unexposedPaper) ? null : unexposedPaper)
                            .eq(ExamTaskDetail::getExamTaskId, examTaskId);
                    examTaskDetailService.update(examTaskDetailUpdateWrapper);
                }
            }
            finalMap.put("examDetailId", examDetailId);
            finalList.add(finalMap);
        }
        return finalList;
    }

    @Override
    public List<Map<String, Object>> getPrintDataBatch(String machineCode, Long orgId, Long semesterId, Long examId, String printPlanId, String status, String courseCode, String paperNumber, String examPlace, String examRoom, Long examStartTime, Long examEndTime, Boolean isDownload, Boolean validate) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
//        Set<Long> orgIds = teachcloudCommonService.listSubOrgIds(null);
        // 以下状态考场状态不可查询
        String[] examDetailStatus = new String[]{ExamDetailStatusEnum.NEW.name(), ExamDetailStatusEnum.READY.name(), ExamDetailStatusEnum.CANCEL.name()};
        List<ClientPrintTaskDto> pirntTaskDtoList = clientMapper.listClientPrintTask(schoolId, semesterId, examId, machineCode, printPlanId, status, courseCode, paperNumber, examPlace, examRoom, examStartTime, examEndTime, isDownload, validate, orgId, examDetailStatus);
        // 撤回
        long count = pirntTaskDtoList.stream().map(m -> {
            ExamDetail examDetail = examDetailService.getById(m.getExamDetailId());
            if (ExamDetailStatusEnum.NEW.name().equals(examDetail.getStatus())
                    || ExamDetailStatusEnum.READY.name().equals(examDetail.getStatus())) {
                return m.getExamDetailId();
            }
            return null;
        }).filter(m -> StringUtils.isNotBlank(m)).count();
        if (count > 0) {
            throw ExceptionResultEnum.ERROR.exception("有任务被撤回，请刷新列表后再试");
        }
        List<Map<String, Object>> finalList = new ArrayList<>();
        for (ClientPrintTaskDto clientPrintTaskDto : pirntTaskDtoList) {
            List<Map<String, Object>> list = getPrintData(clientPrintTaskDto.getExamDetailId(), null, false, null);
            finalList.addAll(list);
        }
        return finalList;
    }

    @Override
    public Map<String, Object> getUrlByExamDetailId(Long examDetailId) {
        Map<String, Object> finalMap = new HashMap<>();
        ExamDetail examDetail = examDetailService.getById(examDetailId);
        BasicAttachment attachment = basicAttachmentService.getById(examDetail.getAttachmentId());
        finalMap.put("paperTotal", attachment == null ? null : teachcloudCommonService.filePreviewByAttachmentId(attachment.getId(), false));

        BasicAttachment cardAttachment = basicAttachmentService.getById(examDetail.getCardAttachmentId());
        finalMap.put("cardTotal", cardAttachment == null ? null : teachcloudCommonService.filePreviewByAttachmentId(cardAttachment.getId(), false));

        ExamPrintPlan examPrintPlan = examPrintPlanService.getById(examDetail.getPrintPlanId());

        List<Map> otherList = new ArrayList<>();
        //印品附件信息
        String attachmentPath = examDetail.getAttachmentPath();
        if (StringUtils.isNotBlank(attachmentPath)) {
            JSONObject jsonObject = JSONObject.parseObject(attachmentPath);
            String pathString = jsonObject.getString("path");
            List<Map> pathList = JSONObject.parseArray(pathString, Map.class);
            if (!pathList.isEmpty()) {
                List<Map> variableList = JSONObject.parseArray(examPrintPlan.getVariableContent(), Map.class);
                for (Map contentMap : variableList) {
                    spliceOtherContent(otherList, pathList, contentMap);
                }
                List<Map> ordinaryList = JSONObject.parseArray(examPrintPlan.getOrdinaryContent(), Map.class);
                for (Map contentMap : ordinaryList) {
                    spliceOtherContent(otherList, pathList, contentMap);
                }
            }
        }
        finalMap.put("other", otherList);
        return finalMap;
    }

    @Override
    public Boolean updateDownload(Long examDetailId, String machineCode, Boolean isDownload) {
        ExamDetail examDetail = examDetailService.getById(examDetailId);
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        QueryWrapper<ExamDetailCourse> examDetailCourseQueryWrapper = new QueryWrapper<>();
        examDetailCourseQueryWrapper.lambda().eq(ExamDetailCourse::getSchoolId, schoolId).eq(ExamDetailCourse::getExamDetailId, examDetailId);
        List<ExamDetailCourse> examDetailCourses = examDetailCourseService.list(examDetailCourseQueryWrapper);
        for (ExamDetailCourse examDetailCours : examDetailCourses) {
            QueryWrapper<ClientStatus> clientStatusQueryWrapper = new QueryWrapper<>();
            clientStatusQueryWrapper.lambda().eq(ClientStatus::getSchoolId, schoolId).eq(ClientStatus::getExamDetailId, examDetailId).eq(ClientStatus::getPrintPlanId, examDetail.getPrintPlanId()).eq(ClientStatus::getCourseCode, examDetailCours.getCourseCode()).eq(ClientStatus::getPaperNumber, examDetailCours.getPaperNumber()).eq(ClientStatus::getMachineCode, machineCode);
            ClientStatus clientStatus = clientStatusService.getOne(clientStatusQueryWrapper);
            if (clientStatus == null) {
                clientStatus = new ClientStatus();
                clientStatus.setId(SystemConstant.getDbUuid());
                clientStatus.setSchoolId(schoolId);
                clientStatus.setExamDetailId(examDetailId);
                clientStatus.setPrintPlanId(examDetail.getPrintPlanId());
                clientStatus.setMachineCode(machineCode);
                clientStatus.setCourseCode(examDetailCours.getCourseCode());
                clientStatus.setCourseName(examDetailCours.getCourseName());
                clientStatus.setPaperNumber(examDetailCours.getPaperNumber());
                clientStatus.setTry(false);
                clientStatus.setPass(false);
                clientStatus.setDownload(isDownload);
                clientStatusService.save(clientStatus);
            } else {
                clientStatus.setDownload(isDownload);
                clientStatusService.updateById(clientStatus);
            }
        }
        return true;
    }

    @Override
    public Boolean validateData(Long examDetailId, String packageCode, String lastCode) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        ExamDetail examDetail = examDetailService.getById(examDetailId);
        if (examDetail == null) {
            throw ExceptionResultEnum.ERROR.exception("考场数据有误");
        }

        // 撤回提示
        if (ExamDetailStatusEnum.NEW.name().equals(examDetail.getStatus())
                || ExamDetailStatusEnum.READY.name().equals(examDetail.getStatus())) {
            throw ExceptionResultEnum.ERROR.exception("该任务已被撤回");
        }

        if (StringUtils.isBlank(packageCode)) {
            throw ExceptionResultEnum.ERROR.exception("卷袋编号不能为空");
        }
        if (!packageCode.equals(examDetail.getPackageCode())) {
            throw ExceptionResultEnum.ERROR.exception("卷袋编号与系统数据不一致");
        }

        ExamPrintPlan examPrintPlan = examPrintPlanService.getById(examDetail.getPrintPlanId());
        String printContent = examPrintPlan.getPrintContent();
        if (StringUtils.isBlank(printContent)) {
            throw ExceptionResultEnum.ERROR.exception("打印内容没有包含试卷、题卡，无需校验");
        }
        Integer backupCount = SystemConstant.calcBackupCount(examDetail.getBackupCount(), examDetail.getTotalSubjects(), 1);
        // 有备用题卡
        if (printContent.contains("CARD")) {
            QueryWrapper<ExamDetailCourse> courseQueryWrapper = new QueryWrapper<>();
            courseQueryWrapper.lambda().eq(ExamDetailCourse::getExamDetailId, examDetailId).orderByDesc(ExamDetailCourse::getPaperNumber);
            List<ExamDetailCourse> examDetailCourses = examDetailCourseService.list(courseQueryWrapper);
            if (examDetailCourses.isEmpty()) {
                throw ExceptionResultEnum.ERROR.exception("考场下课程数据异常");
            }

            if (backupCount > 0) {
                if (StringUtils.isBlank(lastCode)) {
                    throw ExceptionResultEnum.ERROR.exception("最后一张备卡条码数据异常");
                }

                // 取最后一个课程数据（包含最后一张备卡条码信息）
                ExamDetailCourse examDetailCourselast = examDetailCourses.get(examDetailCourses.size() - 1);
                if (examDetailCourselast == null) {
                    throw ExceptionResultEnum.ERROR.exception("题卡数据异常");
                }
                String attachmentIds = examDetailCourselast.getAttachmentId();
                if (StringUtils.isBlank(attachmentIds)) {
                    throw ExceptionResultEnum.ERROR.exception("备卡数据异常");
                }
                JSONObject jsonObject = JSONObject.parseObject(attachmentIds);
                String backupAttachmentIds = JSONObject.toJSONString(jsonObject.get("card"));
                List<Map> list = JSONObject.parseArray(backupAttachmentIds, Map.class);
                Map map = list.get(list.size() - 1);
                String backupPackageCode = map.get("packageCode").toString();

                if (!lastCode.equals(backupPackageCode)) {
                    throw ExceptionResultEnum.ERROR.exception("最后一张备卡条码与系统数据不匹配");
                }

                String lastCodeSub = lastCode.substring(0, lastCode.length() - 2);
                if (!packageCode.equals(lastCodeSub)) {
                    throw ExceptionResultEnum.ERROR.exception("最后一张备卡条码与试卷编号不属于同一考场");
                }
            } else {
                // 无备卡，取最后一个考生考号
                if (StringUtils.isBlank(lastCode)) {
                    throw ExceptionResultEnum.ERROR.exception("最后一张题卡条码数据异常");
                }
                List<Long> examDetailCourseIds = examDetailCourses.stream().map(m -> m.getId()).collect(Collectors.toList());
                QueryWrapper<ExamStudent> studentQueryWrapper = new QueryWrapper<>();
                studentQueryWrapper.lambda().in(ExamStudent::getExamDetailCourseId, examDetailCourseIds);
                List<ExamStudent> examStudents = examStudentService.list(studentQueryWrapper);
                if (CollectionUtils.isEmpty(examStudents)) {
                    throw ExceptionResultEnum.ERROR.exception("考生数据异常");
                }
                examStudents.sort(Comparator.comparing(ExamStudent::getSiteNumber));
                ExamStudent examStudent = examStudents.get(examStudents.size() - 1);
                if (StringUtils.isBlank(examStudent.getTicketNumber())) {
                    throw ExceptionResultEnum.ERROR.exception("考生考号异常");
                }
                if (lastCode.equals(examStudent.getTicketNumber())) {
                    throw ExceptionResultEnum.ERROR.exception("最后一张题卡条码与系统数据不匹配");
                }
            }

            UpdateWrapper<ExamDetail> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().set(ExamDetail::getValidate, true).eq(ExamDetail::getId, examDetailId);
            examDetailService.update(updateWrapper);
        }
        return true;
    }

    @Override
    public List<Map<String, Object>> getBatchUrl(String machineCode, Long orgId, Long semesterId, Long examId, Long printPlanId, String courseCode, String paperNumber, Boolean isTry, Boolean isPass) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        // 印刷任务状态为印刷中（PRINTING）,考场状态为待打印（WAITING）
        String[] examDetailStatus = {ExamDetailStatusEnum.NEW.name(), ExamDetailStatusEnum.READY.name(), ExamDetailStatusEnum.CANCEL.name()};
        List<ClientExamTaskDto> clientExamTaskDtos = clientMapper.pageTryTask(schoolId, semesterId, examId, machineCode, orgId, printPlanId, courseCode, paperNumber, isTry, isPass, PrintPlanStatusEnum.PRINTING.name(), examDetailStatus);
        List<Map<String, Object>> list = new ArrayList<>();
        for (ClientExamTaskDto clientExamTaskDto : clientExamTaskDtos) {
            Map<String, Object> map = new HashMap<>();
            map.put("printPlanId", clientExamTaskDto.getPrintPlanId());
            map.put("courseCode", clientExamTaskDto.getCourseCode());
            map.put("courseName", clientExamTaskDto.getCourseName());
            map.put("paperNumber", clientExamTaskDto.getPaperNumber());
            List<Map<String, String>> mapList = this.getPaperUrl(schoolId, Long.valueOf(clientExamTaskDto.getPrintPlanId()), Long.valueOf(clientExamTaskDto.getExamTaskId()));
            map.put("list", mapList);
            list.add(map);
        }
        return list;
    }

    @Override
    public void exportClientPrintTask(HttpServletResponse response, String machineCode, Long orgId, Long semesterId, Long examId, String printPlanId, String status, String courseCode, String paperNumber, String examPlace, String examRoom, Long examStartTime, Long examEndTime, Boolean isDownload, Boolean validate) throws Exception {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        // 以下状态考场状态不可查询
        String[] examDetailStatus = new String[]{ExamDetailStatusEnum.NEW.name(), ExamDetailStatusEnum.READY.name(), ExamDetailStatusEnum.CANCEL.name()};
        List<ClientPrintTaskDto> printTaskDtoIList = clientMapper.listClientPrintTask(schoolId, semesterId, examId, machineCode, printPlanId, status, courseCode, paperNumber, examPlace, examRoom, examStartTime, examEndTime, isDownload, validate, orgId, examDetailStatus);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        printTaskDtoIList = printTaskDtoIList.stream().map(m -> {
            if (m.getExamStartTime() != null) {
                String eStartTime = simpleDateFormat.format(new Date(m.getExamStartTime()));
                m.setExamStartTimeStr(eStartTime);
            }
            if (m.getExamEndTime() != null) {
                String eEndTime = simpleDateFormat.format(new Date(m.getExamEndTime()));
                m.setExamEndTimeStr(eEndTime);
            }
            if (m.getPrintStartTime() != null) {
                String pStartTime = simpleDateFormat.format(new Date(m.getPrintStartTime()));
                m.setPrintStartTimeStr(pStartTime);
            }
            if (m.getPrintEndTime() != null) {
                String pEndTime = simpleDateFormat.format(new Date(m.getPrintEndTime()));
                m.setPrintEndTimeStr(pEndTime);
            }
            m.setStatusStr(ExamDetailStatusEnum.valueOf(m.getStatus()).getName());
            m.setValidateStr(m.getValidate() ? "是" : "否");
            m.setDownloadStr(m.getDownload() ? "是" : "否");
            return m;
        }).collect(Collectors.toList());
        ExcelUtil.excelExport("印刷管理", ClientPrintTaskDto.class, printTaskDtoIList, response);
    }

    @Override
    public ClientPrintTaskTotalDto taskTotalData(Long semesterId, Long examId, String printPlanId, Long orgId, String status, String courseCode, String paperNumber, String examPlace, String examRoom, Long examStartTime, Long examEndTime, Boolean isDownload, Boolean validate, String machineCode) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        String[] examDetailStatus = new String[]{ExamDetailStatusEnum.NEW.name(), ExamDetailStatusEnum.READY.name(), ExamDetailStatusEnum.CANCEL.name()};
        ClientPrintTaskTotalDto clientPrintTaskTotalDto = clientMapper.clientTaskTotalData(schoolId, semesterId, examId, printPlanId, status, courseCode, paperNumber, examPlace, examRoom, examStartTime, examEndTime, isDownload, validate, machineCode, orgId, examDetailStatus);
        if (clientPrintTaskTotalDto != null) {
            // 累计a3,a4
            List<ClientPrintData> list = clientPrintDataService.listBySchoolIdAndMachineCode(schoolId, machineCode);
            if (!list.isEmpty()) {
                int paperPages = list.stream().filter(m -> m.getPaperPages() != null).mapToInt(ClientPrintData::getPaperPages).sum();
                clientPrintTaskTotalDto.setHostPaperPages(paperPages / 2);
                int cardPages = list.stream().filter(m -> m.getCardPages() != null).mapToInt(ClientPrintData::getCardPages).sum();
                clientPrintTaskTotalDto.setHostCardPages(cardPages / 2);
                int pagesA4 = list.stream().filter(m -> m.getPagesA4() != null).mapToInt(ClientPrintData::getPagesA4).sum();
                clientPrintTaskTotalDto.setHostPagesA4(pagesA4 / 2);
            }

            // 试卷总计
            String paperNumberStrs = clientPrintTaskTotalDto.getPaperNumberAndType();
            if (StringUtils.isNotBlank(paperNumberStrs)) {
                String[] paperNumbers = paperNumberStrs.split(",");
                Set<String> paperNumberSet = new HashSet<>(Arrays.asList(paperNumbers));
                clientPrintTaskTotalDto.setPaperCount(paperNumberSet.size());
            }
        }

        return clientPrintTaskTotalDto;
    }

    @Override
    public IPage<ClientPrintStatisticsDto> listClientPrintStatistics(Long orgId, Long semesterId, Long examId, String printPlanId, String examPlace, Long examStartTime, Long examEndTime, String courseCode, String paperNumber, Integer pageNumber, Integer pageSize) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        Page<ClientPrintStatisticsDto> page = new Page<>(pageNumber, pageSize);
        return examPrintPlanService.listClientPrintStatistics(page, schoolId, semesterId, examId, printPlanId, examPlace, examStartTime, examEndTime, courseCode, paperNumber, orgId);
    }

    @Override
    public ClientPrintStatisticsTotalDto clientStatisticsTotalData(Long orgId, Long semesterId, Long examId, Long printPlanId, String examPlace, Long examStartTime, Long examEndTime, String courseCode, String paperNumber) {
        return examPrintPlanService.clientStatisticsTotalData(orgId, semesterId, examId, printPlanId, examPlace, examStartTime, examEndTime, courseCode, paperNumber);
    }

    @Override
    public boolean updatePassword(Long userId, String password) {
        SysUser sysUser = sysUserService.getById(userId);
        if (sysUser == null) {
            throw ExceptionResultEnum.ERROR.exception("用户不存在");
        }
        if (StringUtils.isBlank(password)) {
            throw ExceptionResultEnum.ERROR.exception("请输入新密码");
        }
        UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().set(SysUser::getPassword, password)
                .eq(SysUser::getId, userId);
        return sysUserService.update(updateWrapper);
    }

    @Override
    public List<BasicSchool> listSchool(String code) {
        return basicSchoolService.listSchool(code);
    }

    @Override
    public Set<String> getRoleByUserId(Long userId) {
        Set<String> roles = new HashSet<>();
        List<SysPrivilege> sysPrivileges = sysPrivilegeService.getClientUrlByUserId(userId);
        long printCount = sysPrivileges.stream().filter(m -> "打印端".equals(m.getName()) && "client".equals(m.getUrl())).count();
        if (printCount > 0) {
            roles.add(RoleTypeEnum.PRINT.name());
        }
        long scanCount = sysPrivileges.stream().filter(m -> "扫描端".equals(m.getName()) && "scan".equals(m.getUrl())).count();
        if (scanCount > 0) {
            roles.add(RoleTypeEnum.SCANNER.name());
        }
        return roles;
    }

    @Override
    public IPage<PrintSingleDto> getSingleData(Long semesterId, Long examId, Long printPlanId, Long courseCode, Long paperNumber, Integer pageNumber, Integer pageSize) {
        Page<PrintSingleDto> page = new Page<>(pageNumber, pageSize);
        String[] examDetailStatus = {ExamDetailStatusEnum.NEW.name(), ExamDetailStatusEnum.READY.name(), ExamDetailStatusEnum.CANCEL.name()};
        IPage<PrintSingleDto> clientExamTaskDtoList = clientMapper.pagePrintSingleData(page, semesterId, examId, printPlanId, courseCode, paperNumber, examDetailStatus);
        for (PrintSingleDto record : clientExamTaskDtoList.getRecords()) {
            ExamTaskDetail examTaskDetail = examTaskDetailService.getByExamIdAndCourseCodeAndPaperNumber(record.getExamId(), record.getCourseCode(), record.getPaperNumber());
            List<PaperInfoVo> paperInfoVoList = examTaskDetail.getPaperInfoVoList(record.getPaperType());
            // 试卷
            List<UrlMd5Dto> paperList = new ArrayList<>();
            // 题卡
            List<UrlMd5Dto> cardList = new ArrayList<>();
            for (PaperInfoVo paperInfoVo : paperInfoVoList) {
                BasicAttachment basicAttachment = basicAttachmentService.getById(paperInfoVo.getAttachmentId());
                String url = teachcloudCommonService.filePreview(Long.valueOf(paperInfoVo.getAttachmentId()));
                paperList.add(new UrlMd5Dto(url, basicAttachment.getMd5()));
                ExamCard examCard = examCardService.getById(paperInfoVo.getCardId());
                if(StringUtils.isBlank(examCard.getBlankCardPath())){
                    examCardService.createJpgImage(examCard);
                    examCardService.updateById(examCard);
                }
                FilePathVo filePathVo = JSON.parseObject(examCard.getBlankCardPath(), FilePathVo.class);
                String cardUrl = teachcloudCommonService.filePreviewByPathAndType(filePathVo.getPath(), filePathVo.getUploadType().name(), filePathVo.getType(), false);
                cardList.add(new UrlMd5Dto(cardUrl, filePathVo.getMd5()));
            }
            record.setPaper(paperList);
            record.setCard(cardList);

            // 签到表
            List<UrlMd5Dto> signs = new ArrayList<>();
            // 卷袋贴
            List<UrlMd5Dto> packages = new ArrayList<>();
            // 登记表
            List<UrlMd5Dto> checkIns = new ArrayList<>();

            List<String> examDetailIds = Arrays.asList(record.getExamDetailIds().split(","));
            List<ExamDetail> examDetails = examDetailService.listByIds(examDetailIds);
            examDetails.stream().forEach(m->{
                JSONObject jsonObject = JSONObject.parseObject(m.getAttachmentPath());
                String pathString = jsonObject.getString("path");
                List<PrintPathVo> printPathVos = JSON.parseArray(pathString, PrintPathVo.class);
                for (PrintPathVo printPathVo : printPathVos) {
                    String url = teachcloudCommonService.filePreviewByPathAndType(printPathVo.getPdfPath(), printPathVo.getUploadType().name(), printPathVo.getType(), false);
                    if(ClassifyEnum.SIGN.equals(printPathVo.getPrintType())){
                        signs.add(new UrlMd5Dto(url, printPathVo.getPdfMd5()));
                    }
                    if(ClassifyEnum.PACKAGE.equals(printPathVo.getPrintType())){
                        packages.add(new UrlMd5Dto(url, printPathVo.getPdfMd5()));
                    }
                    if(ClassifyEnum.CHECK_IN.equals(printPathVo.getPrintType())){
                        checkIns.add(new UrlMd5Dto(url, printPathVo.getPdfMd5()));
                    }
                }
            });
            record.setSigns(signs);
            record.setPackages(packages);
            record.setCheckIn(checkIns);
        }
        return clientExamTaskDtoList;
    }

    /**
     * 根据考场生成试卷map
     */
    public Map<String, Map<String, String>> mapCourseUrl(List<Map<String, Object>> mapList) {
        Map<String, Map<String, String>> map = new HashMap<>();
        for (Map<String, Object> taskDetail : mapList) {
            String courseCode = taskDetail.get("courseCode").toString();
            String paperNumber = taskDetail.get("paperNumber").toString();
            String paperAttachmentIds = taskDetail.get("paperAttachmentIds").toString();
            List<Map> attachementIds = JSONObject.parseArray(paperAttachmentIds, Map.class);
            for (Map attaMap : attachementIds) {
                String name = attaMap.get("name").toString();
                String attachmentId = attaMap.get("attachmentId").toString();
                Map<String, String> stringMap = teachcloudCommonService.filePreviewByAttachmentId(Long.valueOf(attachmentId), false);
                StringJoiner sj = new StringJoiner(SystemConstant.DELIMITER);
                String key = sj.add(courseCode).add(paperNumber).add(name).toString();
                map.put(key, stringMap);
            }
        }
        return map;
    }


    /**
     * 生成印品url公共方法
     *
     * @param otherList
     * @param pathList
     * @param contentMap
     */
    private void spliceOtherContent(List<Map> otherList, List<Map> pathList, Map contentMap) {
        Map vMap = new HashMap();
        vMap.put("type", contentMap.get("type"));
        for (Map path : pathList) {
            String printType = path.get("printType").toString();
            if (printType.equals(contentMap.get("type").toString())) {
//                vMap.put("htmlUrl", teachcloudCommonService.filePreviewByPathAndType(path.get("htmlPath").toString(), path.get("type").toString(), false));
//                vMap.put("htmlMd5", path.get("htmlMd5"));
                vMap.put("pdfUrl", teachcloudCommonService.filePreviewByPathAndType(path.get(SystemConstant.PDF_PATH).toString(), path.get(SystemConstant.UPLOAD_TYPE).toString(), path.get("type").toString(), false));
                vMap.put("pdfMd5", path.get("pdfMd5").toString().toLowerCase());
            }
        }
        if (vMap.size() > 1) {
            otherList.add(vMap);
        }
    }

    /**
     * 生成试卷url公共方法
     *
     * @param examDetailCourses
     * @param map
     */
    private List<ClientPrintDataDto> splicePaperContent(List<Map<String, Object>> examDetailCourses, Map<String, Map<String, String>> map, String studentCode, String type) {
        List<ClientPrintDataDto> clientPrintDataDtos = new ArrayList<>();
        for (Map<String, Object> examDetailCours : examDetailCourses) {
            // 取考生列表
            List<Map> studentList = examDetailService.listStudentByExamDetailCourseId(Long.valueOf(examDetailCours.get("schoolId").toString()), Long.valueOf(examDetailCours.get("examDetailCourseId").toString()), studentCode, type);
            Integer printCount = Integer.parseInt(examDetailCours.get("printCount").toString());
            if (studentList != null && studentList.size() > 0) {
                for (Map studentMap : studentList) {
                    ClientPrintDataDto printDataDto = newClientPrintDataDto(studentMap);
                    StringJoiner sj = new StringJoiner(SystemConstant.DELIMITER);
                    String key = sj.add(printDataDto.getCourseCode()).add(studentMap.get("paperNumber").toString()).add(printDataDto.getPaperType()).toString();
                    printDataDto.setMd5(map.get(key).get("md5"));
                    printDataDto.setUrl(map.get(key).get("url"));
                    clientPrintDataDtos.add(printDataDto);
                }
            } else if (printCount > 0) {
                List<String> paperTypes = Arrays.stream(examDetailCours.get("paperType").toString().split(",")).sorted(Comparator.comparing(String::valueOf)).collect(Collectors.toList());
                for (int i = 0; i < printCount; i++) {
                    int mod = i % paperTypes.size();
                    String tempPaperType = paperTypes.get(mod);
                    ClientPrintDataDto printDataDto = newClientPrintDataDto(examDetailCours);
                    StringJoiner sj = new StringJoiner(SystemConstant.DELIMITER);
                    String key = sj.add(printDataDto.getCourseCode()).add(examDetailCours.get("paperNumber").toString()).add(tempPaperType).toString();
                    printDataDto.setMd5(map.get(key).get("md5"));
                    printDataDto.setUrl(map.get(key).get("url"));
                    clientPrintDataDtos.add(printDataDto);
                }
            }
        }
        return clientPrintDataDtos;
    }

    /**
     * 生成题卡url公共方法
     *
     * @param examDetailCourses
     */
    private List<ClientPrintDataDto> spliceCardContent(List<Map<String, Object>> examDetailCourses, String studentCode, String type) {
        List<ClientPrintDataDto> clientPrintDataDtos = new ArrayList<>();
        for (Map<String, Object> examDetailCours : examDetailCourses) {
            // 取考生列表
            List<Map> studentList = examDetailService.listStudentByExamDetailCourseId(Long.valueOf(examDetailCours.get("schoolId").toString()), Long.valueOf(examDetailCours.get("examDetailCourseId").toString()), studentCode, type);
            Integer printCount = Integer.parseInt(examDetailCours.get("printCount").toString());
            if (studentList != null && studentList.size() > 0) {
                for (Map studentMap : studentList) {
                    ClientPrintDataDto printDataDto = newClientPrintDataDto(studentMap);
                    if (!studentMap.containsKey("attachmentId") || studentMap.get("attachmentId") == null) {
                        continue;
                    }
                    Map<String, String> urlMap = teachcloudCommonService.filePreviewByAttachmentId(Long.valueOf(studentMap.get("attachmentId").toString()), false);
                    printDataDto.setMd5(urlMap.get("md5"));
                    printDataDto.setUrl(urlMap.get("url"));
                    clientPrintDataDtos.add(printDataDto);
                }
            } else if (printCount != null && printCount > 0) {
                List<JSONObject> commonAttachmentIds = JSONObject.parseArray(examDetailCours.get("commonAttachmentId").toString(), JSONObject.class);
                List<String> paperTypes = Arrays.stream(examDetailCours.get("paperType").toString().split(",")).sorted(Comparator.comparing(String::valueOf)).collect(Collectors.toList());
                for (int i = 0; i < printCount; i++) {
                    int mod = i % commonAttachmentIds.size();
                    String tempPaperType = paperTypes.get(mod);
                    JSONObject jsonObject = commonAttachmentIds.stream().filter(j -> tempPaperType.equals(j.getString("name"))).findFirst().get();
                    ClientPrintDataDto printDataDto = newClientPrintDataDto(examDetailCours);
                    Map<String, String> urlMap = teachcloudCommonService.filePreviewByAttachmentId(Long.valueOf(jsonObject.get("attachmentId").toString()), false);
                    printDataDto.setMd5(urlMap.get("md5"));
                    printDataDto.setUrl(urlMap.get("url"));
                    clientPrintDataDtos.add(printDataDto);
                }
            }
        }
        return clientPrintDataDtos;
    }

    @Override
    public List<Map<String, String>> getPaperUrl(Long schoolId, Long printPlanId, Long examTaskId) {
        ExamTask examTask = examTaskService.getById(examTaskId);
        List<ExamDetailCourse> examDetailCourses = examDetailCourseService.listByPrintPlanIdAndCourseCodeAndPaperNumber(schoolId, printPlanId, examTask.getCourseCode(), examTask.getPaperNumber());
        if (CollectionUtils.isNotEmpty(examDetailCourses)) {
            Set<String> relatePaperTypes = examDetailCourses.stream().filter(m -> StringUtils.isNotBlank(m.getPaperType())).map(m -> m.getPaperType()).collect(Collectors.toSet());
            List<Map<String, String>> paperList = new ArrayList<>();
            ExamTaskDetail examTaskDetail = examTaskDetailService.getByExamTaskId(examTaskId);
            if (CollectionUtils.isEmpty(relatePaperTypes)) {
                throw ExceptionResultEnum.ERROR.exception("未找到关联的试卷卷型");
            }
            List<PaperInfoVo> paperInfoVoList = ExamTaskUtil.parsePaperAttachmentPath(examTaskDetail.getPaperAttachmentIds());
            if (CollectionUtils.isEmpty(paperInfoVoList)) {
                throw ExceptionResultEnum.ERROR.exception("未找到关联的试卷文件");
            }

            Map<String, String> paperMap = paperInfoVoList.stream().collect(Collectors.toMap(m -> m.getName(), m -> String.valueOf(m.getAttachmentId())));
            for (String relatePaperType : relatePaperTypes) {
                String[] paperTypes = relatePaperType.split(",");
                for (String paperType : paperTypes) {
                    if (!paperMap.containsKey(paperType)) {
                        continue;
                    }
                    String attachmentId = paperMap.get(paperType);
                    if (StringUtils.isNotBlank(attachmentId)) {
                        paperList.add(teachcloudCommonService.filePreviewByAttachmentId(Long.valueOf(attachmentId), false));
                    }
                }
            }
            paperList = paperList.stream().distinct().collect(Collectors.toList());
            return paperList;
        }
        return null;
    }

    /**
     * new ClientPrintDataDto
     *
     * @param m
     */
    private ClientPrintDataDto newClientPrintDataDto(Map m) {
        ClientPrintDataDto printDataDto = new ClientPrintDataDto();
        String courseCode = m.get("courseCode").toString();
        String courseName = m.get("courseName").toString();
        String studentName = m.containsKey("studentName") ? m.get("studentName").toString() : "";
        String studentCode = m.containsKey("studentCode") ? m.get("studentCode").toString() : "";
        String paperType = m.get("paperType").toString();
        printDataDto.setCourseCode(courseCode);
        printDataDto.setCourseName(courseName);
        printDataDto.setStudentName(studentName);
        printDataDto.setStudentCode(studentCode);
        printDataDto.setPaperType(paperType);
        return printDataDto;
    }
}
