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

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.entity.*;
import com.qmth.distributed.print.business.enums.ExamDetailStatusEnum;
import com.qmth.distributed.print.business.service.*;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.BasicAttachment;
import com.qmth.teachcloud.common.entity.SysPrivilege;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.service.BasicAttachmentService;
import com.qmth.teachcloud.common.service.SysPrivilegeService;
import com.qmth.teachcloud.common.service.TeachcloudCommonService;
import com.qmth.teachcloud.common.util.ExcelUtil;
import com.qmth.teachcloud.common.util.ServletUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

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

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

    @Resource
    ExamTaskService examTaskService;

    @Resource
    ExamTaskDetailService examTaskDetailService;

    @Resource
    ClientStatusService clientStatusService;

    @Resource
    ExamDetailService examDetailService;

    @Resource
    ExamDetailCourseService examDetailCourseService;

    @Resource
    BasicAttachmentService basicAttachmentService;

    @Resource
    ExamPrintPlanService examPrintPlanService;

    @Resource
    ExamStudentService examStudentService;

    @Resource
    TeachcloudCommonService teachcloudCommonService;

    @Resource
    SysPrivilegeService sysPrivilegeService;

    @Resource
    BasicExamService basicExamService;

    @Override
    public IPage<ClientExamTaskDto> listTryTask(String machineCode, Long orgId, Long printPlanId, String courseCode, String paperNumber, Boolean isTry, Boolean isPass, Integer pageNumber, Integer pageSize) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        return examTaskService.listTryTask(schoolId, machineCode, orgId, printPlanId, courseCode, paperNumber, isTry, isPass, pageNumber, pageSize);
    }

    @Override
    public List<Map<String, String>> getPaperUrl(Long printPlanId, Long examTaskId) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        return examTaskDetailService.getPaperUrl(schoolId, printPlanId, examTaskId);
    }

    @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());
        return examDetailService.updatePrintProgress(schoolId, examDetailId, machineCode, printProgress, isPrint);
    }

    @Override
    public IPage<ClientExamStudentDto> listStudent(Long examDetailId, String ticketNumber, String studentName, String courseCode, Integer pageNumber, Integer pageSize) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        return examDetailService.listStudent(schoolId, examDetailId, ticketNumber, studentName, courseCode, pageNumber, pageSize);
    }


    @Override
    public Map<String, Object> getReprintData(Long examDetailId, String ticketNumber, String type) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        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.listByExamDetailId(examDetailId);
        Map<String, Map<String, String>> map = mapCourseUrl(examDetailCourses);
        // 生成试卷List
        if (printContent.contains("PAPER")) {
            finalMap.put("paper", splicePaperContent(examDetailCourses, map));
        }
        if (printContent.contains("CARD")) {
            // 生成题卡List
            finalMap.put("card", spliceCardContent(examDetailCourses));
        }
        //

        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, 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);
        return examPrintPlanService.listClientPrintTask(page, schoolId, machineCode, printPlanId, status, courseCode, paperNumber, examPlace, examRoom, examStartTime, examEndTime, isDownload, validate, orgId);
    }

    @Transactional
    @Override
    public Map<String, Object> getPrintData(Long examDetailId, String machineCode, Boolean isPrint, String printUser) {
        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.getPrintUser() + "]占用");
        }

        // 课程、试卷信息
        List<Map<String, Object>> examDetailCourses = examDetailCourseService.listByExamDetailId(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 = examPrintPlan.getBackupCount();
            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("total", totalPathUrl);
                // 取试卷
                Map<String, Map<String, String>> map = mapCourseUrl(examDetailCourses);
                // 生成试卷List
                detailMap.put("paper", splicePaperContent(examDetailCourses, map));
                //试卷
                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));

                // 备用题卡
                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.listByExamDetailCourseId(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);
            }
        }
        return finalMap;
    }

    @Override
    public List<Map<String, Object>> getPrintDataBatch(String machineCode, Long orgId, 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);
        List<ClientPrintTaskDto> pirntTaskDtoList = examPrintPlanService.listClientPrintTask(schoolId, machineCode, printPlanId, status, courseCode, paperNumber, examPlace, examRoom, examStartTime, examEndTime, isDownload, validate, orgId);
        // 撤回
        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) {
            Map<String, Object> map = getPrintData(Long.valueOf(clientPrintTaskDto.getExamDetailId()), null, false, null);
            map.put("examDetailId", clientPrintTaskDto.getExamDetailId());
            finalList.add(map);
        }
        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("total", 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 = examPrintPlan.getBackupCount();
        // 有备用题卡
        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 printPlanId, String courseCode, String paperNumber, Boolean isTry, Boolean isPass) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        List<ClientExamTaskDto> clientExamTaskDtos = examTaskService.listTryTask(schoolId, machineCode, orgId, printPlanId, courseCode, paperNumber, isTry, isPass);
        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 = examTaskDetailService.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, 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());
//        Set<Long> orgIds = teachcloudCommonService.listSubOrgIds(null);
        List<ClientPrintTaskDto> printTaskDtoIList = examPrintPlanService.listClientPrintTask(schoolId, machineCode, printPlanId, status, courseCode, paperNumber, examPlace, examRoom, examStartTime, examEndTime, isDownload, validate, orgId);
        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()).getDesc());
            m.setValidateStr(m.getValidate() ? "是" : "否");
            m.setDownloadStr(m.getDownload() ? "是" : "否");
            return m;
        }).collect(Collectors.toList());
        ExcelUtil.excelExport("印刷管理", ClientPrintTaskDto.class, printTaskDtoIList, response);
    }

    @Override
    public ClientPrintTaskTotalDto taskTotalData(String printPlanId, Long orgId, String status, String courseCode, String paperNumber, String examPlace, String examRoom, Long examStartTime, Long examEndTime, Boolean isDownload, Boolean validate, String machineCode) {
        return examPrintPlanService.clientTaskTotalData(printPlanId, orgId, status, courseCode, paperNumber, examPlace, examRoom, examStartTime, examEndTime, isDownload, validate, machineCode);
    }

    @Override
    public IPage<ClientPrintStatisticsDto> listClientPrintStatistics(Long orgId, 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, printPlanId, examPlace, examStartTime, examEndTime, courseCode, paperNumber, orgId);
    }

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

    @Override
    public void checkPrivilege(Long userId) {
        List<SysPrivilege> sysPrivileges = sysPrivilegeService.getClientUrlByUserId(userId);
        long count = sysPrivileges.stream().filter(m -> "客户端".equals(m.getName()) && "client".equals(m.getUrl())).count();
        if (count == 0) {
            throw ExceptionResultEnum.ERROR.exception("用户没有权限，无法登录");
        }
    }

    /**
     * 根据考场生成试卷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("pdfPath").toString(), path.get("type").toString(), false));
                vMap.put("pdfMd5", path.get("pdfMd5"));
            }
        }
        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) {
        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()), null, null);
            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) {
        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()), null, null);
            Integer printCount = Integer.parseInt(examDetailCours.get("printCount").toString());
            if (studentList != null && studentList.size() > 0) {
                for (Map studentMap : studentList) {
                    ClientPrintDataDto printDataDto = newClientPrintDataDto(studentMap);
                    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;
    }

    /**
     * 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;
    }
}
