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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.qmth.boot.api.exception.ApiException;
import com.qmth.distributed.print.business.bean.dto.CardDetailDto;
import com.qmth.distributed.print.business.bean.dto.ExamDetailCourseDto;
import com.qmth.distributed.print.business.bean.dto.SyncExamStudentDto;
import com.qmth.distributed.print.business.bean.dto.SyncExamTaskDto;
import com.qmth.distributed.print.business.bean.marking.GroupInfo;
import com.qmth.distributed.print.business.bean.marking.Marker;
import com.qmth.distributed.print.business.entity.*;
import com.qmth.distributed.print.business.enums.ExamPaperStructureStatusEnum;
import com.qmth.distributed.print.business.enums.ExamTaskSyncStatusEnum;
import com.qmth.distributed.print.business.service.*;
import com.qmth.teachcloud.common.bean.dto.stmms.GroupDetailDTO;
import com.qmth.teachcloud.common.bean.dto.stmms.PicConfig;
import com.qmth.teachcloud.common.bean.dto.stmms.QuestionBaseDTO;
import com.qmth.teachcloud.common.bean.dto.stmms.QuestionDTO;
import com.qmth.teachcloud.common.config.DictionaryConfig;
import com.qmth.teachcloud.common.contant.SpringContextHolder;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.*;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.enums.SyncFileTypeEnum;
import com.qmth.teachcloud.common.enums.TaskResultEnum;
import com.qmth.teachcloud.common.enums.TaskStatusEnum;
import com.qmth.teachcloud.common.enums.userPush.SpecialPrivilegeEnum;
import com.qmth.teachcloud.common.service.*;
import com.qmth.teachcloud.common.sync.CloudMarkingTaskUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 同步服务类
 */
@Service
public class DataSyncServiceImpl implements DataSyncService {

    private final static Logger log = LoggerFactory.getLogger(DataSyncServiceImpl.class);

    @Resource
    private ExamTaskSyncService examTaskSyncService;

    @Resource
    private TSyncStmmsExamService tSyncStmmsExamService;

    @Resource
    private TBSyncTaskService tbSyncTaskService;

    @Resource
    private ExamStudentService examStudentService;

    @Resource
    private ExamDetailCourseService examDetailCourseService;

    @Resource
    private ExamCardService examCardService;

    @Resource
    private ExamPaperStructureService examPaperStructureService;

    @Resource
    private TeachcloudCommonService teachcloudCommonService;

    @Resource
    private BasicAttachmentService basicAttachmentService;

    @Resource
    private SysOrgService sysOrgService;

    @Resource
    private SysUserService sysUserService;

    @Resource
    private ExamPaperGroupService examPaperGroupService;

    @Resource
    private ExamPaperGroupMarkerService examPaperGroupMarkerService;

    @Resource
    ExamTaskService examTaskService;

    @Resource
    private ExamTaskDetailService examTaskDetailService;

    @Resource
    private CloudMarkingTaskUtils cloudMarkingTaskUtils;

    @Resource
    DictionaryConfig dictionaryConfig;

    @Async
    @Override
    public void syncExamAndStudentAndCard(Long thirdRelateId, String thirdRelateName, String examTime, TBSyncTask tbSyncTask, SysUser sysUser) {

        // 同步初始参数
        TaskResultEnum result = null;
        TaskStatusEnum status;
        String errorMessage = null;
        Long schoolId = tbSyncTask.getSchoolId();
        Long objectId = tbSyncTask.getObjectId();
        List<SyncExamTaskDto> params = JSONObject.parseArray(tbSyncTask.getRemark(), SyncExamTaskDto.class);
        Integer thirdRelateOrgId = null;

        // 各步骤状态
        try {
            // 同步中
            status = TaskStatusEnum.RUNNING;
            tbSyncTaskService.updateStatusAndResultById(tbSyncTask.getId(), null, status, null, null);

            // 按学院code进行分组，并按学院进行循环同步
            Map<String, List<SyncExamTaskDto>> byCollegeCodeMap = params.stream().collect(Collectors.groupingBy(SyncExamTaskDto::getCollegeCode));
            for (Map.Entry<String, List<SyncExamTaskDto>> entry : byCollegeCodeMap.entrySet()) {
                // 本行为，若为按学校同步，则后续方法都传null,方便校验
                String orgCode = cloudMarkingTaskUtils.isCollegeMode(schoolId) ? entry.getKey() : null;

                if (StringUtils.isNotBlank(orgCode)) {
                    SysOrg byCode = sysOrgService.findByCode(orgCode);
                    // 同步机构
                    thirdRelateOrgId = saveSchool(schoolId, thirdRelateOrgId, orgCode, byCode.getName());
                }
                // 查询本地库中云阅卷考试Id是否存在
                TSyncStmmsExam tSyncStmmsExam = tSyncStmmsExamService.getBySchoolIdAndOrgCodeAndExamName(schoolId, orgCode, thirdRelateName);
                if (tSyncStmmsExam != null) {
                    thirdRelateId = Long.valueOf(tSyncStmmsExam.getExamId());
                }

                //按课程做同步
                for (SyncExamTaskDto param : params) {
                    // 前置方法已经校验过各课程下是否有学院代码
                    // 同步考试
                    thirdRelateId = saveExam(schoolId, objectId, orgCode, thirdRelateId, thirdRelateName, examTime);

                    Long examTaskId = Long.valueOf(param.getExamTaskId());
                    ExamTask examTask = examTaskService.getById(examTaskId);
                    ExamTaskSync examTaskSync = examTaskSyncService.getBySchoolIdAndOrgCodeAndPaperNumber(schoolId, examTask.getExamId(), orgCode, examTask.getPaperNumber());
                    if (examTaskSync != null && ExamTaskSyncStatusEnum.STARTING.equals(examTaskSync.getSyncStatus())) {
                        throw ExceptionResultEnum.ERROR.exception("其它任务中该课程正在同步中，请刷新列表查看最新状态");
                    }
                    ExamTaskSyncStatusEnum syncStatus = ExamTaskSyncStatusEnum.STARTING;

                    if (examTaskSync == null) {
                        examTaskSync = new ExamTaskSync(schoolId, examTask.getExamId(), examTask.getCourseCode(), examTask.getPaperNumber(), orgCode, Math.toIntExact(thirdRelateId), syncStatus, sysUser.getId(), System.currentTimeMillis(), null);
                    } else {
                        examTaskSync.setSyncStatus(syncStatus);
                        examTaskSync.setSyncStartTime(System.currentTimeMillis());
                        examTaskSync.setSyncUserId(sysUser.getId());
                        examTaskSync.setErrorMsg(null);
                    }
                    examTaskSyncService.saveOrUpdate(examTaskSync);

                    try {
                        List<Long> printPlanIds = Arrays.asList(param.getPrintPlanIds().split(",")).stream().map(m -> Long.parseLong(m)).collect(Collectors.toList());
                        List<ExamDetailCourseDto> examDetailCourseList = examDetailCourseService.listByPrintPlanIdAndExamTaskId(printPlanIds, examTaskId);
                        // 同步考生
                        List<SyncExamStudentDto> syncExamStudentDtoList = examStudentService.listStudentByExamDetailCourseId(examDetailCourseList);

                        long count = syncExamStudentDtoList.stream().filter(m -> StringUtils.isBlank(m.getPaperType())).count();
                        if (count > 0) {
                            throw ExceptionResultEnum.ERROR.exception("部分学生未关联试卷类型，数量[" + count + "]");
                        }
                        // 同步考生
                        saveStudent(schoolId, thirdRelateId, syncExamStudentDtoList);

                        // 同步题卡
                        for (ExamDetailCourseDto examDetailCourseDto : examDetailCourseList) {
                            // 同步题卡
                            cardUpload(schoolId, thirdRelateId, examTask, examDetailCourseDto.getPaperType());
                        }
                    } catch (Exception e) {
                        examTaskSync.setErrorMsg(e.getMessage());
                        examTaskSync.setSyncStatus(ExamTaskSyncStatusEnum.FAIL);
                    } finally {
                        examTaskSync.setSyncStatus(ExamTaskSyncStatusEnum.FINISH);
                    }
                    examTaskSyncService.saveOrUpdate(examTaskSync);
                }

            }
            // 任务结果
            result = TaskResultEnum.SUCCESS;
        } catch (Exception e) {
            result = TaskResultEnum.ERROR;
            errorMessage = e.getMessage();
        } finally {
            // 同步结束
            status = TaskStatusEnum.FINISH;
            tbSyncTaskService.updateStatusAndResultById(tbSyncTask.getId(), thirdRelateId, status, result, errorMessage);

            // 同步成功，发送短信
//            if (ExamPrintPlanSyncStatusEnum.FINISH.equals(syncStatus)) {
//                examPrintPlanService.sendNoticeUploadStructure(printPlanId, sysUser);
//            }
        }
    }

    @Async
    @Override
    public void syncPaperStructureAndGroup(ExamPaperStructure examPaperStructure, TBSyncTask tbSyncTask) {
        // 开始同步
        ExamPaperStructureStatusEnum structureStatus = ExamPaperStructureStatusEnum.INIT;
        // 同步初始参数
        TaskResultEnum result = null;
        String mainProgress = "<b>步骤：删除分组->主观题结构->主观题分组->绑定评卷员</b><br>";
        String errorMessage = "";
        try {
            String paperTypes = examPaperStructure.getPaperType();
            if (StringUtils.isBlank(paperTypes)) {
                throw ExceptionResultEnum.ERROR.exception("没有可同步的试卷类型");
            }

            Long schoolId = examPaperStructure.getSchoolId();
            // 云阅卷考试ID
            String examId = String.valueOf(examPaperStructure.getThirdRelateId());
            // 科目代码（课程代码+卷型+课程序号）
            String subjectCode = examPaperStructure.getCourseCode().concat(examPaperStructure.getPaperType()).concat(examPaperStructure.getSequence());

            // 同步中
            tbSyncTaskService.updateStatusAndResultById(tbSyncTask.getId(), examPaperStructure.getThirdRelateId(), TaskStatusEnum.RUNNING, null, null);

            // 同步分组（检查，若存在，先删除）
            errorMessage = "[删除分组]";
            int i = 0;
            deleteGroup(schoolId, examId, subjectCode, i);

            // 同步主观题
            errorMessage = "[主观题结构]";
            String subjectiveStructure = examPaperStructure.getSubjectiveStructure();
            if (StringUtils.isNotBlank(subjectiveStructure)) {
                List<JSONObject> subjectiveJsons = JSONObject.parseArray(subjectiveStructure, JSONObject.class);
                List<QuestionDTO> syncSubjectiveStructureDatas = subjectiveJsons.stream().map(m -> {
                    QuestionDTO syncStructureData = new QuestionDTO();
                    syncStructureData.setMainNumber(m.getInteger("mainNumber"));
                    syncStructureData.setSubNumber(m.getString("subNumber"));
                    syncStructureData.setMainTitle(m.getString("mainTitle"));
                    syncStructureData.setTotalScore(m.getDouble("totalScore"));
                    return syncStructureData;
                }).collect(Collectors.toList());

                // 主观题不传试卷类型 update by 20220711
                cloudMarkingTaskUtils.syncPaperStructure(schoolId, examId, subjectCode, false, null, syncSubjectiveStructureDatas);
            }

            // 清掉云阅卷主观题答案
            String objectiveStructure = examPaperStructure.getObjectiveStructure();
            if (StringUtils.isNotBlank(objectiveStructure)) {
                List<JSONObject> objectiveJsons = JSONObject.parseArray(objectiveStructure, JSONObject.class);
                long count = objectiveJsons.stream().filter(m -> m.containsKey("answer")).count();
                if (objectiveJsons.size() == 0 || count == 0) {
                    List<QuestionDTO> syncObjectiveStructureDatas = new ArrayList<>();
                    cloudMarkingTaskUtils.syncPaperStructure(schoolId, examId, subjectCode, true, null, syncObjectiveStructureDatas);
                }
            }

            structureStatus = ExamPaperStructureStatusEnum.SUBJECTIVE_FINISH;

            errorMessage = "[主观题分组]";
            List<ExamPaperGroup> examPaperGroups = examPaperGroupService.listByExamPaperStructureId(examPaperStructure.getId());
            if (!CollectionUtils.isEmpty(examPaperGroups)) {
                List<GroupDetailDTO> groupDetailDTOS = new ArrayList<>();
                for (ExamPaperGroup examPaperGroup : examPaperGroups) {
                    GroupDetailDTO groupDetailDTO = new GroupDetailDTO();
                    groupDetailDTO.setNumber(examPaperGroup.getGroupNumber());
                    String picListString = examPaperGroup.getPictureConfig();
                    if (StringUtils.isNotBlank(picListString)) {
                        List<PicConfig> picConfigs = JSONObject.parseArray(picListString, PicConfig.class);
                        groupDetailDTO.setPicConfig(picConfigs);
                    }
                    groupDetailDTO.setDoubleRate(examPaperGroup.getDoubleRate());
                    groupDetailDTO.setArbitrateThreshold(examPaperGroup.getArbitrateThreshold());
                    groupDetailDTO.setScorePolicy(examPaperGroup.getScorePolicy().getValue());
                    String questionsString = examPaperGroup.getQuestionInfo();
                    if (StringUtils.isNotBlank(questionsString)) {
                        List<JSONObject> jsonObjects = JSONObject.parseArray(questionsString, JSONObject.class);
                        List<QuestionBaseDTO> questionBaseDTOS = jsonObjects.stream().map(m -> {
                            QuestionBaseDTO questionBaseDTO = new QuestionBaseDTO();
                            questionBaseDTO.setMainNumber(m.getInteger("mainNumber"));
                            questionBaseDTO.setSubNumber(m.getString("subNumber"));
                            return questionBaseDTO;
                        }).collect(Collectors.toList());
                        groupDetailDTO.setQuestions(questionBaseDTOS);
                    }
                    groupDetailDTOS.add(groupDetailDTO);
                }
                cloudMarkingTaskUtils.saveMarkerGroup(schoolId, examId, subjectCode, 0, groupDetailDTOS);
            }
            structureStatus = ExamPaperStructureStatusEnum.GROUP_FINISH;

            // 同步绑定评卷员
            errorMessage = "[绑定评卷员]";
            String orgCode = cloudMarkingTaskUtils.isCollegeMode(schoolId) ? sysOrgService.findCollegeByCourseCode(schoolId, examPaperStructure.getCourseCode()).getCode() : null;
            SysConfigService sysConfigService = SpringContextHolder.getBean(SysConfigService.class);
            SysConfig sysConfig = sysConfigService.getByKey("sys.user.initPassword");
            for (ExamPaperGroup examPaperGroup : examPaperGroups) {
                List<ExamPaperGroupMarker> examPaperGroupMarkers = examPaperGroupMarkerService.listByGroupId(examPaperGroup.getId());
                for (ExamPaperGroupMarker examPaperGroupMarker : examPaperGroupMarkers) {
                    // 推送用户
                    SysUser markerUser = sysUserService.getById(examPaperGroupMarker.getMarkerId());
                    cloudMarkingTaskUtils.syncUser(SpecialPrivilegeEnum.MARKER.getPrefix() + markerUser.getLoginName(), markerUser.getRealName(), sysConfig.getConfigValue(), SpecialPrivilegeEnum.MARKER.getValue(), markerUser.getEnable(), schoolId, orgCode);
                    // 绑定评卷员
                    cloudMarkingTaskUtils.saveMarker(schoolId, examId, subjectCode, examPaperGroup.getGroupNumber(), examPaperGroupMarker.getLoginName());
                }
            }
            structureStatus = ExamPaperStructureStatusEnum.FINISH;
            result = TaskResultEnum.SUCCESS;
        } catch (Exception e) {
            result = TaskResultEnum.ERROR;
            errorMessage = errorMessage + e.getMessage();
        } finally {
            examPaperStructure.setStatus(structureStatus);
            examPaperStructureService.updateById(examPaperStructure);

            tbSyncTaskService.updateStatusAndResultById(tbSyncTask.getId(), examPaperStructure.getThirdRelateId(), TaskStatusEnum.FINISH, result, mainProgress + errorMessage);
        }
    }

    /**
     * 云阅卷分组删除是异步任务
     *
     * @param schoolId    学校ID
     * @param examId      考试ID
     * @param subjectCode 科目代码
     */
    private boolean deleteGroup(Long schoolId, String examId, String subjectCode, int i) {
        if (i >= 5) {
            throw ExceptionResultEnum.ERROR.exception("云阅卷分组未删除");
        }
        // 同步分组
        int countGroup = cloudMarkingTaskUtils.countGroup(schoolId, examId, subjectCode);
        // 如果存在分组，先删掉
        boolean deleteGroup = false;
        if (countGroup > 0) {
            // 第一次进行调用删除
            if (i == 0) {
                deleteGroup = cloudMarkingTaskUtils.deleteGroup(schoolId, examId, subjectCode);
            }
        } else {
            return true;
        }
        // 调用成功，再查询判断是否还有分组
        if (deleteGroup) {
            countGroup = cloudMarkingTaskUtils.countGroup(schoolId, examId, subjectCode);
            if (countGroup > 0) {
                // 等待3秒
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException ignored) {
                }
                i++;
                deleteGroup(schoolId, examId, subjectCode, i);
            }
        } else {
            throw ExceptionResultEnum.ERROR.exception("云阅卷分组删除异常");
        }
        return false;
    }

    @Async
    @Override
    public void syncPaperAndAnswer(ExamPaperStructure examPaperStructure, TBSyncTask tbSyncTask) {
        // 同步初始参数
        TaskResultEnum result = null;
        String errorMessage = null;
        File paperFile = null;
        File answerFile = null;
        try {
            Long schoolId = examPaperStructure.getSchoolId();
            // 云阅卷考试ID
            String examId = String.valueOf(examPaperStructure.getThirdRelateId());
            // 科目代码（课程代码+卷型+课程序号）
            String subjectCode = examPaperStructure.getCourseCode().concat(examPaperStructure.getPaperType()).concat(examPaperStructure.getSequence());

            // 同步中
            tbSyncTaskService.updateStatusAndResultById(tbSyncTask.getId(), examPaperStructure.getThirdRelateId(), TaskStatusEnum.RUNNING, null, null);

            String paperAnswer = examPaperStructure.getPaperAnswer();
            if (StringUtils.isNotBlank(paperAnswer)) {
                List<JSONObject> paperAnswerJsons = JSONObject.parseArray(paperAnswer, JSONObject.class);
                for (JSONObject paperAnswerJson : paperAnswerJsons) {
                    if (paperAnswerJson.containsKey("paperType") && paperAnswerJson.containsKey("paper")) {
                        String paperType = paperAnswerJson.getString("paperType");
                        // 同步试卷
                        String paper = paperAnswerJson.getString("paper");
                        if (StringUtils.isAnyBlank(paperType, paper)) {
                            continue;
                        }
                        // 同步试卷文件
                        paperFile = downFileFromFss(paper, paperType, SyncFileTypeEnum.PAPER);
                        String syncPaperFileUrl = cloudMarkingTaskUtils.syncFile(schoolId, examId, subjectCode, SyncFileTypeEnum.PAPER, paperFile);
                        // 试卷文件保存url
                        paperAnswerJson.put("paperUrl", syncPaperFileUrl);

                        // 同步标答
                        String answer = paperAnswerJson.getString("answer");
                        if (StringUtils.isAnyBlank(paperType, answer)) {
                            continue;
                        }
                        // 同步标答文件
                        answerFile = downFileFromFss(answer, paperType, SyncFileTypeEnum.ANSWER);
                        String syncAnswerFileUrl = cloudMarkingTaskUtils.syncFile(schoolId, examId, subjectCode, SyncFileTypeEnum.ANSWER, answerFile);
                        // 标答文件保存url
                        paperAnswerJson.put("answerUrl", syncAnswerFileUrl);
                    }
                }
                String paperAnswerUrl = JSONObject.toJSONString(paperAnswerJsons);

                // 更新url
                UpdateWrapper<ExamPaperStructure> updateWrapper = new UpdateWrapper<>();
                updateWrapper.lambda().set(ExamPaperStructure::getPaperAnswer, paperAnswerUrl).eq(ExamPaperStructure::getId, examPaperStructure.getId());
                examPaperStructureService.update(updateWrapper);
            }

            result = TaskResultEnum.SUCCESS;
        } catch (ApiException e) {
            result = TaskResultEnum.ERROR;
            errorMessage = e.getMessage();
        } finally {
            tbSyncTaskService.updateStatusAndResultById(tbSyncTask.getId(), examPaperStructure.getThirdRelateId(), TaskStatusEnum.FINISH, result, errorMessage);
            if (paperFile != null) {
                paperFile.delete();
            }
            if (answerFile != null) {
                answerFile.delete();
            }
        }
    }

    @Async
    @Override
    public void syncObjectiveStructure(ExamPaperStructure examPaperStructure, TBSyncTask tbSyncTask) {
        // 同步初始参数
        TaskResultEnum result = null;
        String errorMessage = null;
        try {
            Long schoolId = examPaperStructure.getSchoolId();
            // 云阅卷考试ID
            String examId = String.valueOf(examPaperStructure.getThirdRelateId());
            // 科目代码（课程代码+卷型+课程序号）
            String subjectCode = examPaperStructure.getCourseCode().concat(examPaperStructure.getPaperType()).concat(examPaperStructure.getSequence());
            // 同步客观题
            String objectiveStructure = examPaperStructure.getObjectiveStructure();
            if (StringUtils.isNotBlank(objectiveStructure)) {
                List<JSONObject> objectiveJsons = JSONObject.parseArray(objectiveStructure, JSONObject.class);
                List<QuestionDTO> syncObjectiveStructureDatas = objectiveJsons.stream().map(m -> {
                    QuestionDTO syncStructureData = new QuestionDTO();
                    syncStructureData.setMainNumber(m.getInteger("mainNumber"));
                    syncStructureData.setSubNumber(m.getString("subNumber"));
                    syncStructureData.setMainTitle(m.getString("mainTitle"));
                    syncStructureData.setTotalScore(m.getDouble("totalScore"));
                    syncStructureData.setAnswer(m.getString("answer"));
                    return syncStructureData;
                }).collect(Collectors.toList());
//                cloudMarkingTaskUtils.syncPaperStructure(schoolId, examId, subjectCode, true, examPaperStructure.getPaperType(), syncObjectiveStructureDatas);
                cloudMarkingTaskUtils.syncPaperStructure(schoolId, examId, subjectCode, true, null, syncObjectiveStructureDatas);
            }

            String cloudInfoJson = cloudMarkingTaskUtils.queryPaperStructure(schoolId, examId, subjectCode, null);
            UpdateWrapper<ExamPaperStructure> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().set(ExamPaperStructure::getCloudInfoJson, cloudInfoJson).set(ExamPaperStructure::getStructureChange, false).eq(ExamPaperStructure::getId, examPaperStructure.getId());
            examPaperStructureService.update(updateWrapper);

            result = TaskResultEnum.SUCCESS;
        } catch (ApiException e) {
            result = TaskResultEnum.ERROR;
            errorMessage = e.getMessage();
        } finally {
            tbSyncTaskService.updateStatusAndResultById(tbSyncTask.getId(), examPaperStructure.getThirdRelateId(), TaskStatusEnum.FINISH, result, errorMessage);
        }
    }

    @Async
    @Override
    public void syncMarkLeader(ExamPaperStructure examPaperStructure, TBSyncTask tbSyncTask) {
        // 同步初始参数
        TaskResultEnum result = null;
        String errorMessage = null;
        try {
            Long schoolId = examPaperStructure.getSchoolId();
            // 科目代码（课程代码+卷型+课程序号）
            String subjectCode = examPaperStructure.getCourseCode().concat(examPaperStructure.getPaperType()).concat(examPaperStructure.getSequence());
            // 同步客观题
            String markLeader = examPaperStructure.getMarkLeader();
            if (StringUtils.isNotBlank(markLeader)) {
                List<JSONObject> objectiveJsons = JSONObject.parseArray(markLeader, JSONObject.class);
                for (JSONObject object : objectiveJsons) {
                    // 推送用户
                    String orgCode = cloudMarkingTaskUtils.isCollegeMode(schoolId) ? sysOrgService.findCollegeByCourseCode(schoolId, examPaperStructure.getCourseCode()).getCode() : null;
                    SysUser markerUser = sysUserService.getById(object.getLong("id"));
                    SysConfigService sysConfigService = SpringContextHolder.getBean(SysConfigService.class);
                    SysConfig sysConfig = sysConfigService.getByKey("sys.user.initPassword");
                    cloudMarkingTaskUtils.syncUser(SpecialPrivilegeEnum.SUBJECT_HEADER.getPrefix() + markerUser.getLoginName(), markerUser.getRealName(), sysConfig.getConfigValue(), SpecialPrivilegeEnum.SUBJECT_HEADER.getValue(), markerUser.getEnable(), schoolId, orgCode);

                    cloudMarkingTaskUtils.saveMarkLeader(schoolId, subjectCode, object.getString("loginName"), orgCode);
                }
            }
            result = TaskResultEnum.SUCCESS;
        } catch (Exception e) {
            result = TaskResultEnum.ERROR;
            errorMessage = e.getMessage();
        } finally {
            tbSyncTaskService.updateStatusAndResultById(tbSyncTask.getId(), examPaperStructure.getThirdRelateId(), TaskStatusEnum.FINISH, result, errorMessage);
        }
    }

    @Async
    @Override
    public void syncMarker(ExamPaperStructure examPaperStructure, TBSyncTask tbSyncTask) {
        // 同步初始参数
        TaskResultEnum result = null;
        String errorMessage = null;
        try {
            Long schoolId = examPaperStructure.getSchoolId();
            // 科目代码（课程代码+卷型+课程序号）
            String subjectCode = examPaperStructure.getCourseCode().concat(examPaperStructure.getPaperType()).concat(examPaperStructure.getSequence());
            // 同步客观题
            GroupInfo groupInfo = JSON.parseObject(tbSyncTask.getRemark(), GroupInfo.class);
            List<Marker> markerList = groupInfo.getMarkerList();

            String orgCode = cloudMarkingTaskUtils.isCollegeMode(schoolId) ? sysOrgService.findCollegeByCourseCode(schoolId, examPaperStructure.getCourseCode()).getCode() : null;
            SysConfigService sysConfigService = SpringContextHolder.getBean(SysConfigService.class);
            SysConfig sysConfig = sysConfigService.getByKey("sys.user.initPassword");
            for (Marker marker : markerList) {
                // 推送用户
                cloudMarkingTaskUtils.syncUser(SpecialPrivilegeEnum.MARKER.getPrefix() + marker.getLoginName(), marker.getName(), sysConfig.getConfigValue(), SpecialPrivilegeEnum.MARKER.getValue(), true, schoolId, orgCode);
                // 绑定评卷员
                cloudMarkingTaskUtils.saveMarker(schoolId, String.valueOf(examPaperStructure.getThirdRelateId()), subjectCode, groupInfo.getGroupNumber(), marker.getLoginName());
            }
            result = TaskResultEnum.SUCCESS;
        } catch (Exception e) {
            result = TaskResultEnum.ERROR;
            errorMessage = e.getMessage();
        } finally {
            tbSyncTaskService.updateStatusAndResultById(tbSyncTask.getId(), examPaperStructure.getThirdRelateId(), TaskStatusEnum.FINISH, result, errorMessage);
        }
    }

    /**
     * 创建考试
     *
     * @param schoolId         学校ID
     * @param thirdRelateOrgId 学院ID
     * @param orgCode          学院代码
     * @param orgName          学院名称
     */
    @Override
    public Integer saveSchool(Long schoolId, Integer thirdRelateOrgId, String orgCode, String orgName) {
        if (StringUtils.isBlank(orgCode)) {
            return null;
        }
        try {
            if (Objects.isNull(thirdRelateOrgId)) {
                thirdRelateOrgId = cloudMarkingTaskUtils.syncSchool(schoolId, orgCode, orgName);
            }
        } catch (Exception e) {
            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
        }
        try {
            UpdateWrapper<SysOrg> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().set(SysOrg::getThirdRelateId, thirdRelateOrgId)
                    .eq(SysOrg::getSchoolId, schoolId)
                    .eq(SysOrg::getCode, orgCode)
                    .isNull(SysOrg::getThirdRelateId);
        } catch (Exception e) {
            log.error("保存云阅卷机构数据失败。");
        }
        return thirdRelateOrgId;
    }

    /**
     * 创建考试
     *
     * @param schoolId        学校ID
     * @param objectId        计划ID
     * @param orgCode         学院代码
     * @param thirdRelateId   云阅卷考试ID
     * @param thirdRelateName 云阅卷考试名称
     * @param examTime        考试时间
     */
    public Long saveExam(Long schoolId, Long objectId, String orgCode, Long thirdRelateId, String thirdRelateName, String examTime) {
        try {
            if (Objects.isNull(thirdRelateId)) {
                String code = String.valueOf(objectId);
                thirdRelateId = cloudMarkingTaskUtils.syncExam(schoolId, code, thirdRelateName, examTime, orgCode);
            }

        } catch (Exception e) {
            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
        }
        try {
            TSyncStmmsExam tSyncStmmsExam = tSyncStmmsExamService.getBySchoolIdAndExamId(schoolId, orgCode, thirdRelateId);
            if (tSyncStmmsExam == null) {
                tSyncStmmsExam = new TSyncStmmsExam();
                tSyncStmmsExam.setId(SystemConstant.getDbUuid());
                tSyncStmmsExam.setSchoolId(schoolId);
                if (StringUtils.isNotBlank(orgCode)) {
                    tSyncStmmsExam.setOrgCode(orgCode);
                }
                tSyncStmmsExam.setExamId(thirdRelateId.intValue());
                tSyncStmmsExam.setExamName(thirdRelateName);
                tSyncStmmsExamService.save(tSyncStmmsExam);
            }
        } catch (Exception e) {
            log.error("保存云阅卷考试数据失败。页面上可刷新从云阅卷系统获取考试列表。");
        }
        return thirdRelateId;
    }

    /**
     * 新增考生
     *
     * @param schoolId      学校ID
     * @param thirdRelateId 云阅卷考试ID
     */
    public void saveStudent(Long schoolId, Long thirdRelateId, List<SyncExamStudentDto> syncExamStudentDtoList) {
        for (SyncExamStudentDto examStudent : syncExamStudentDtoList) {
            try {
                //参数
                String examId = String.valueOf(thirdRelateId);
                String examNumber = examStudent.getTicketNumber();
                String studentCode = examStudent.getStudentCode();
                String name = examStudent.getStudentName();
                BasicCollege basicCollege = examStudentService.getBasicCollegeByBelongOrgId(studentCode, schoolId);
                String college = Objects.nonNull(basicCollege) && StringUtils.isNotBlank(basicCollege.getCollegeName()) ? basicCollege.getCollegeName() : "无";
                String className = StringUtils.isBlank(examStudent.getClazzName()) ? getClassName(examStudent.getExtendFields()) : examStudent.getClazzName();
                String teacher = "无";
                String subjectCode = examStudent.getCourseCode() + examStudent.getPaperType() + examStudent.getSequence(); // 取试卷编号
                String subjectName = examStudent.getCourseName();
                String packageCode = examStudent.getPackageCode();
                // 试卷类型和客观题试卷类型一致  update by 20220713
//                String paperType = examStudent.getPaperType();
                String paperType = null;
                boolean syncStudent = cloudMarkingTaskUtils.syncStudent(schoolId, examId, examNumber, studentCode, name, college, className, teacher, subjectCode, subjectName, packageCode, paperType, null, null);

                if (syncStudent) {
                    UpdateWrapper<ExamStudent> updateWrapper = new UpdateWrapper<>();
                    updateWrapper.lambda().set(ExamStudent::getSyncStatus, true).eq(ExamStudent::getId, examStudent.getId());
                    examStudentService.update(updateWrapper);
                }
            } catch (Exception e) {
                throw ExceptionResultEnum.ERROR.exception(e.getMessage());
            }
        }
    }

    /**
     * 同步题卡
     *
     * @param schoolId      学校ID
     * @param thirdRelateId 云阅卷考试ID
     */
    public void cardUpload(Long schoolId, Long thirdRelateId, ExamTask examTask, String paperType) {
        ExamTaskDetail examTaskDetail = examTaskDetailService.getByExamTaskId(examTask.getId());
        List<JSONObject> paperAttachmentIds = JSON.parseArray(examTaskDetail.getPaperAttachmentIds(), JSONObject.class);
        if (paperAttachmentIds.isEmpty()) {
            throw ExceptionResultEnum.ERROR.exception(String.format("[上传题卡格式]数据异常，试卷编号[%s]未查询到题卡信息", examTask.getPaperNumber()));
        }

        if (StringUtils.isBlank(paperType)) {
            throw ExceptionResultEnum.ERROR.exception("[上传题卡格式]数据异常，考场科目信息中绑定卷型为空");
        }
        for (String s : paperType.split(",")) {
            Optional<JSONObject> optional = paperAttachmentIds.stream().filter(m -> m.getString("name").equals(s)).findFirst();
            if (!optional.isPresent()) {
                throw ExceptionResultEnum.ERROR.exception(String.format("[上传题卡格式]数据异常，未找到卷型[%s]绑定题卡ID", s));
            }
            Long cardId = optional.get().getLong("cardId");
            CardDetailDto cardDetail = examCardService.getCardDetail(cardId);
            if (cardDetail == null || StringUtils.isBlank(cardDetail.getContent())) {
//                throw ExceptionResultEnum.ERROR.exception(String.format("[上传题卡格式]数据异常，通过题卡ID[%s]，未查到题卡格式信息", cardId));
                continue;
            }

            //生成json文件
            File file = null;
            try {
                // 文件临时目录
                String dirName = dictionaryConfig.fssPrivateDomain().getConfig() + File.separator + "upload-temp" + File.separator + SyncFileTypeEnum.CARD.name().toLowerCase() + File.separator + System.currentTimeMillis();
                file = new File(dirName, SystemConstant.getNanoId() + ".json");
                file = createJsonFile(file.getPath(), cardDetail.getContent());
                if (file.exists()) {
                    String uploadCardUrl = cloudMarkingTaskUtils.syncFile(schoolId, String.valueOf(thirdRelateId), examTask.getCourseCode() + s + examTask.getSequence(), SyncFileTypeEnum.CARD, file);
                    if (StringUtils.isNotBlank(uploadCardUrl)) {
                        UpdateWrapper<ExamCard> updateWrapper = new UpdateWrapper<>();
                        updateWrapper.lambda().set(ExamCard::getSyncStatus, true).eq(ExamCard::getId, cardId);
                        examCardService.update(updateWrapper);
                    }
                }
            } catch (Exception e) {
                throw ExceptionResultEnum.ERROR.exception(e.getMessage());
            } finally {
                if (file != null && file.exists()) {
                    file.delete();
                }
            }
        }
    }

    /**
     * 通过扩展字段，获取班级名称
     *
     * @param extendColumn 扩展字段
     */
    private String getClassName(String extendColumn) {
        List<Map> mapList = JSONObject.parseArray(extendColumn, Map.class);
        for (Map map : mapList) {
            if (Objects.equals("className", map.get("code").toString())
                    || Objects.equals("clazzName", map.get("code").toString())) {
                return map.get("value").toString();
            }
        }
        return "无";
    }

    /**
     * 生成文件
     *
     * @param url     文件路径+文件名称
     * @param content 要生成的文件内容
     */
    public static File createJsonFile(String url, String content) {
        File file = new File(url);
        try {
            if (!file.exists()) {
                file.getParentFile().mkdirs();
                file.createNewFile();
            }
            IOUtils.write(content.getBytes(StandardCharsets.UTF_8), new FileOutputStream(file));
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
        }
        return file;
    }

    /**
     * 下载附件临时文件
     *
     * @param attachmentId 附件ID
     * @param name         文件名称
     * @param type         文件类型
     */
    private File downFileFromFss(String attachmentId, String name, SyncFileTypeEnum type) {
        try {
            if (Objects.nonNull(attachmentId)) {
                BasicAttachment attachment = basicAttachmentService.getById(attachmentId);
                if (attachment == null) {
                    throw ExceptionResultEnum.ERROR.exception("附件数据异常");
                }
                String fileName = attachment.getName() + SystemConstant.HYPHEN + name + attachment.getType();
                String dirName = dictionaryConfig.fssPrivateDomain().getConfig() + File.separator + "upload-temp" + File.separator + type.name().toLowerCase() + File.separator + System.currentTimeMillis();
//                File file = SystemConstant.getFileTempDirVar(dirName, SystemConstant.getNanoId() + attachment.getType());
                return teachcloudCommonService.copyFile(dirName, fileName, attachment);
            }
        } catch (Exception e) {
            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
        }
        return null;
    }
}
