package com.qmth.themis.admin.api;

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.themis.business.annotation.ApiJsonObject;
import com.qmth.themis.business.annotation.ApiJsonProperty;
import com.qmth.themis.business.bean.admin.ExamRecordPdfQueryBean;
import com.qmth.themis.business.cache.bean.ExamCacheBean;
import com.qmth.themis.business.cache.bean.ExamCourseCacheBean;
import com.qmth.themis.business.cache.bean.ExamRecordDetailBean;
import com.qmth.themis.business.cache.bean.ExamRecordPaperViewBean;
import com.qmth.themis.business.constant.SystemConstant;
import com.qmth.themis.business.dto.MqDto;
import com.qmth.themis.business.dto.response.MarkResultDto;
import com.qmth.themis.business.dto.response.TEExamStudentDto;
import com.qmth.themis.business.entity.*;
import com.qmth.themis.business.enums.*;
import com.qmth.themis.business.service.*;
import com.qmth.themis.business.util.MqUtil;
import com.qmth.themis.business.util.OssUtil;
import com.qmth.themis.business.util.ServletUtil;
import com.qmth.themis.common.enums.ExceptionResultEnum;
import com.qmth.themis.common.exception.BusinessException;
import com.qmth.themis.common.util.Result;
import com.qmth.themis.common.util.ResultUtil;
import io.swagger.annotations.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import java.io.IOException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Description: 考生库 前端控制器
 * @Param:
 * @returnß:
 * @Author: wangliang
 * @Date: 2020/6/25
 */
@Api(tags = "考生库Controller")
@RestController
@RequestMapping(SystemConstant.PREFIX_URL_ADMIN + "/examStudent")
@Validated
public class TEExamStudentController {

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

    @Resource
    TEExamStudentService teExamStudentService;

    @Resource
    TBAttachmentService tbAttachmentService;

    @Resource
    TBTaskHistoryService taskHistoryService;

    @Resource
    TEExamService teExamService;

    @Resource
    TEExamActivityService teExamActivityService;

    @Resource
    TBExamInvigilateUserService tbExamInvigilateUserService;

    @Resource
    MqDtoService mqDtoService;

    @Resource
    OssUtil ossUtil;

    @Resource
    TEStudentService teStudentService;

    @Resource
    TEExamCourseService teExamCourseService;

    @Resource
    TOeExamRecordService tOeExamRecordService;

    @Resource
    MqUtil mqUtil;

    @Resource
    TSyncExamStudentScoreService tSyncExamStudentScoreService;

    @Resource
    ThemisCacheService themisCacheService;

    @ApiOperation(value = "考试明细查询接口")
    @RequestMapping(value = "/exam_record_detail/query", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "考生信息", response = ExamRecordDetailBean.class)})
    public Result examRecordDetailQuery(@ApiParam(value = "考试批次id", required = true) @RequestParam Long examId,
                                        @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long activityId,
                                        @ApiParam(value = "科目编码", required = false) @RequestParam(required = false) String courseCode,
                                        @ApiParam(value = "考场编码", required = false) @RequestParam(required = false) String roomCode,
                                        @ApiParam(value = "交卷方式", required = false) @RequestParam(required = false) String finishType,
                                        @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
                                        @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
                                        @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) int pageNumber,
                                        @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) int pageSize) {
        return ResultUtil.ok(tOeExamRecordService.examRecordDetailQuery(new Page<>(pageNumber, pageSize), examId, activityId, courseCode, roomCode, finishType, name, identity));
    }

    @ApiOperation(value = "考试明细查看试卷接口")
    @RequestMapping(value = "/exam_record/paper_view", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "考生信息", response = ExamRecordPaperViewBean.class)})
    public Result examRecordPaperView(@ApiParam(value = "考试记录id", required = true) @RequestParam Long examRecordId) throws IOException {
        return ResultUtil.ok(tOeExamRecordService.examRecordPaperView(examRecordId));
    }

    @ApiOperation(value = "答卷pdf查询接口")
    @RequestMapping(value = "/exam_record/pdf/query", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "考试记录信息", response = Long.class)})
    public Result examRecordPdfQuery(@ApiParam(value = "答卷pdf", required = true) @Valid @RequestBody ExamRecordPdfQueryBean examRecordPdfQueryBean, BindingResult bindingResult) throws IOException {
        if (bindingResult.hasErrors()) {
            return ResultUtil.error(bindingResult.getAllErrors().get(0).getDefaultMessage());
        }
        if (!CollectionUtils.isEmpty(examRecordPdfQueryBean.getCourseCodeList())) {
            examRecordPdfQueryBean.setCourseCodeList(examRecordPdfQueryBean.getCourseCodeList().stream().map(s -> s.trim()).collect(Collectors.toList()));
        }
        if (!CollectionUtils.isEmpty(examRecordPdfQueryBean.getIdentityList())) {
            examRecordPdfQueryBean.setIdentityList(examRecordPdfQueryBean.getIdentityList().stream().map(s -> s.trim()).collect(Collectors.toList()));
        }
        return ResultUtil.ok(tOeExamRecordService.examRecordDetailQuery(examRecordPdfQueryBean.getExamId(), examRecordPdfQueryBean.getCourseCodeList(), examRecordPdfQueryBean.getIdentityList()));
    }

    @ApiOperation(value = "考生导出")
    @RequestMapping(value = "/export", method = RequestMethod.POST)
    public Result export(@ApiParam(value = "考试批次id", required = true) @RequestParam Long examId,
                         @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long activityId,
                         @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
                         @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
                         @ApiParam(value = "考场代码", required = false) @RequestParam(required = false) String roomCode,
                         @ApiParam(value = "科目代码", required = false) @RequestParam(required = false) String courseCode,
                         @ApiParam(value = "年级", required = false) @RequestParam(required = false) String grade,
                         @ApiParam(value = "是否启用", required = false) @RequestParam(required = false) Integer enable,
                         @ApiParam(value = "班级", required = false) @RequestParam(required = false) String classNo,
                         @ApiParam(value = "底照是否上传", required = false) @RequestParam(required = false) Integer hasPhoto)
            throws Exception {
        TBTaskHistory tbTaskHistory = null;
        Map<String, Object> transMap = new HashMap<String, Object>();
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        //往任务表里插一条数据
        tbTaskHistory = new TBTaskHistory(TaskTypeEnum.EXPORT_EXAM_STUDENT, TaskStatusEnum.INIT,
                SystemConstant.EXPORT_INIT, 0d, tbUser.getId(), tbUser.getOrgId());
        tbTaskHistory.setExamId(examId);
        taskHistoryService.save(tbTaskHistory);
        transMap.put("tbTaskHistory", tbTaskHistory);
        transMap.put(SystemConstant.ORG_ID, tbUser.getOrgId());
        transMap.put(SystemConstant.EXAM_ID, examId);
        transMap.put(SystemConstant.ACTIVITY_ID, activityId);
        transMap.put("identity", identity);
        transMap.put(SystemConstant.NAME, name);
        transMap.put(SystemConstant.ROOM_CODE, roomCode);
        transMap.put(SystemConstant.COURSE_CODE, courseCode);
        transMap.put("grade", grade);
        transMap.put("enable", enable);
        transMap.put("classNo", classNo);
        transMap.put("hasPhoto", hasPhoto);
        transMap.put(SystemConstant.CREATE_ID, tbUser.getId());

        //mq发送消息start
        MqDto mqDto = new MqDto(mqUtil.getTopic(), MqTagEnum.EXAM_STUDENT_EXPORT.name(), transMap,
                MqTagEnum.EXAM_STUDENT_EXPORT, String.valueOf(tbTaskHistory.getId()), tbUser.getName());

        mqDtoService.assembleSendAsyncMsg(mqDto);
        //mq发送消息end
        return ResultUtil.ok(Collections.singletonMap(SystemConstant.TASK_ID, tbTaskHistory.getId()));
    }

    @ApiOperation(value = "考生查询接口")
    @RequestMapping(value = "/query", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "考生信息", response = TEExamStudentDto.class)})
    public Result query(@ApiParam(value = "考试批次id", required = true) @RequestParam Long examId,
                        @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long activityId,
                        @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
                        @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
                        @ApiParam(value = "考场代码", required = false) @RequestParam(required = false) String roomCode,
                        @ApiParam(value = "科目代码", required = false) @RequestParam(required = false) String courseCode,
                        @ApiParam(value = "年级", required = false) @RequestParam(required = false) String grade,
                        @ApiParam(value = "是否启用", required = false) @RequestParam(required = false) Integer enable,
                        @ApiParam(value = "班级", required = false) @RequestParam(required = false) String classNo,
                        @ApiParam(value = "底照是否上传", required = false) @RequestParam(required = false) Integer hasPhoto,
                        @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) int pageNumber,
                        @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) int pageSize) {
        if (Objects.isNull(examId) || Objects.equals(examId, "")) {
            throw new BusinessException(ExceptionResultEnum.EXAM_ID_IS_NULL);
        }
        IPage<TEExamStudentDto> teExamStudentIPage = teExamStudentService
                .examStudentQuery(new Page<>(pageNumber, pageSize), examId, activityId, identity, name, roomCode,
                        courseCode, grade, enable, classNo, hasPhoto);
        if (teExamStudentIPage.getRecords() != null && teExamStudentIPage.getRecords().size() > 0) {
            for (TEExamStudentDto dto : teExamStudentIPage.getRecords()) {
                if (StringUtils.isNotBlank(dto.getBasePhotoUrl())) {
                    dto.setBasePhotoUrl(
                            ossUtil.getAliYunOssPublicDomain().getPublicUrl() + "/" + dto.getBasePhotoUrl());
                }
            }
        }
        return ResultUtil.ok(teExamStudentIPage);
    }

    @ApiOperation(value = "考生停用/启用接口")
    @RequestMapping(value = "/toggle", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    @Transactional
    public Result examStudentToggle(@ApiJsonObject(name = "examStudentToggle", value = {
            @ApiJsonProperty(key = "id", type = "long", example = "1", description = "考生ID"),
            @ApiJsonProperty(key = "enable", type = "int", example = "1", description = "是否启用")}) @ApiParam(value = "考生信息", required = true) @RequestBody List<Map<String, Object>> mapParameter) {
        if (Objects.isNull(mapParameter) || mapParameter.size() == 0) {
            throw new BusinessException(ExceptionResultEnum.EXAM_STUDENT_INFO_IS_NULL);
        }
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        List<TEExamStudent> teExamStudentList = new ArrayList<>();
        for (int i = 0; i < mapParameter.size(); i++) {
            Map map = mapParameter.get(i);
            TEExamStudent teExamStudent = teExamStudentService.getById(Long.parseLong(String.valueOf(map.get(SystemConstant.ID))));
            if (Objects.isNull(teExamStudent)) {
                throw new BusinessException(ExceptionResultEnum.EXAM_STUDENT_NO);
            }
            teExamStudent.setEnable(Integer.parseInt(String.valueOf(map.get("enable"))));
            teExamStudent.setUpdateId(tbUser.getId());
            teExamStudentList.add(teExamStudent);
        }
        teExamStudentService.updateBatchById(teExamStudentList);
        teExamStudentList.forEach(s -> {
            teExamStudentService.updateExamStudentCacheBean(s.getId());
        });
        return ResultUtil.ok(true);
    }

    @ApiOperation(value = "考生修改接口")
    @RequestMapping(value = "/save", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    @Transactional
    public Result save(@ApiParam(value = "考生信息", required = true) @RequestBody List<TEExamStudent> teExamStudentList) {
        if (Objects.isNull(teExamStudentList) || teExamStudentList.size() == 0) {
            throw new BusinessException(ExceptionResultEnum.EXAM_STUDENT_INFO_IS_NULL);
        }
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        TBOrg tbOrg = (TBOrg) ServletUtil.getRequestOrg();
        teExamStudentList.forEach(s -> {
            QueryWrapper<TEExamStudent> teExamStudentQueryWrapper = new QueryWrapper<>();
            teExamStudentQueryWrapper.lambda().eq(TEExamStudent::getIdentity, s.getIdentity())
                    .eq(TEExamStudent::getCourseCode, s.getCourseCode())
                    .eq(TEExamStudent::getExamId, s.getExamId())
                    .eq(TEExamStudent::getExamActivityId, s.getExamActivityId());
            TEExamStudent teExamStudent = teExamStudentService.getOne(teExamStudentQueryWrapper);

            if (Objects.isNull(s.getId()) && Objects.nonNull(teExamStudent)) {
                throw new BusinessException("此考生已存在");
            }

            QueryWrapper<TEStudent> teStudentQueryWrapper = new QueryWrapper<>();
            teStudentQueryWrapper.lambda().eq(TEStudent::getIdentity, s.getIdentity()).eq(TEStudent::getOrgId, tbOrg.getId());
            TEStudent teStudent = teStudentService.getOne(teStudentQueryWrapper);

            if (Objects.isNull(teExamStudent)) {
                if (Objects.isNull(teStudent)) {//如果学生数据为空则插入学生数据
                    //先插入学生档案数据
                    teStudent = new TEStudent(tbOrg.getId(), s.getIdentity(), s.getName(), tbUser.getId(), s.getMobileNumber());
                    teStudent.setPassword(SystemConstant.DEFAULT_PASSWORD);
                    teStudentService.save(teStudent);
                    s.setStudentId(teStudent.getId());
                    s.setCreateId(tbUser.getId());
                } else {//否则插入考生数据
                    s.setStudentId(teStudent.getId());
                    s.setCreateId(tbUser.getId());
                    if (Objects.nonNull(s.getMobileNumber()) && !Objects.equals(s.getMobileNumber().trim(), "")) {
                        teStudent.setMobileNumber(s.getMobileNumber());
                    }
                }
            } else {
                UpdateWrapper<TEStudent> teStudentUpdateWrapper = new UpdateWrapper<>();
                teStudentUpdateWrapper.lambda().set(TEStudent::getName, s.getName());
                teStudentUpdateWrapper.lambda().set(TEStudent::getMobileNumber, s.getMobileNumber());
                teStudentUpdateWrapper.lambda().eq(TEStudent::getIdentity, s.getIdentity())
                        .eq(TEStudent::getOrgId, tbOrg.getId());
                teStudentService.update(teStudentUpdateWrapper);
                s.setUpdateId(tbUser.getId());
            }
            ExamCourseCacheBean examCourseCacheBean = teExamCourseService
                    .getExamCourseCacheBean(s.getExamId(), s.getCourseCode());
            if (Objects.isNull(examCourseCacheBean)) {
                throw new BusinessException("考试科目不存在");
            }
            s.setCourseName(examCourseCacheBean.getCourseName());
//            List<RoomCodeQueryDto> roomCodeQueryDtoList = teExamStudentService.examRoomQuery(null);
//            if (Objects.nonNull(roomCodeQueryDtoList)) {
//                Map<String, RoomCodeQueryDto> roomCodeQueryDtoMap = roomCodeQueryDtoList.stream().collect(
//                        Collectors.toMap(RoomCodeQueryDto::getRoomCode, Function.identity(), (dto1, dto2) -> dto1));
//                if (Objects.nonNull(s.getRoomCode())) {
//                    String roomName = roomCodeQueryDtoMap.get(s.getRoomCode()).getRoomName();
//                    if (Objects.isNull(roomName)) {
//                        throw new BusinessException("考场不存在");
//                    }
//                    s.setRoomName(roomCodeQueryDtoMap.get(s.getRoomCode()).getRoomName());
//                }
//            }
            s.setAlreadyExamCount(Objects.isNull(s.getAlreadyExamCount()) ? 0 : s.getAlreadyExamCount());
            teExamStudentService.saveOrUpdate(s);
        });
        for (TEExamStudent es : teExamStudentList) {
            teExamStudentService.updateExamStudentCacheBean(es.getId());
            //加入更新考试列表缓存方法
            themisCacheService.updateCurrentExamListCache(es.getExamId().toString(), es.getExamActivityId());
            ExamCacheBean examCacheBean = teExamService.getExamCacheBean(es.getExamId());
            themisCacheService.updateOrgExamListCache(examCacheBean.getOrgId().toString(), es.getExamId().toString(), es.getExamActivityId());
        }
        return ResultUtil.ok(true);
    }

    @ApiOperation(value = "考生删除接口")
    @RequestMapping(value = "/delete", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    @Transactional
    public Result delete(@ApiParam(value = "考生id", required = true) @RequestBody List<Long> ids) {
        if (Objects.isNull(ids) || ids.size() == 0) {
            throw new BusinessException(ExceptionResultEnum.EXAM_STUDENT_ID_IS_NULL);
        }
        teExamStudentService.removeByIds(ids);
        ids.forEach(s -> {
            teExamStudentService.deleteExamStudentCacheBean(s);
        });
        return ResultUtil.ok(true);
    }

    @ApiOperation(value = "考生导入接口")
    @RequestMapping(value = "/import", method = RequestMethod.POST)
    @Transactional
    @ApiResponses({@ApiResponse(code = 200, message = "{\"taskId\":0}", response = Result.class)})
    public Result importData(@ApiParam(value = "上传文件", required = true) @RequestParam MultipartFile file,
                             @ApiParam(value = "考试批次id", required = true) @RequestParam Long examId) throws IOException {
        if (Objects.isNull(file) || Objects.equals(file, "")) {
            throw new BusinessException(ExceptionResultEnum.ATTACHMENT_IS_NULL);
        }
        if (Objects.isNull(examId) || Objects.equals(examId, "")) {
            throw new BusinessException(ExceptionResultEnum.EXAM_ID_IS_NULL);
        }
        Map<String, Object> mapParameter = ossUtil.getAliYunOssPrivateDomain().getMap();
        TBAttachment tbAttachment = null;
        TBTaskHistory tbTaskHistory = null;
        Map transMap = new HashMap();
        try {
            TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
            tbAttachment = tbAttachmentService
                    .saveAttachment(file, ServletUtil.getRequestMd5(), ServletUtil.getRequestPath(), mapParameter,
                            UploadFileEnum.file, tbUser.getOrgId(), tbUser.getId());
            if (Objects.isNull(tbAttachment)) {
                throw new BusinessException(ExceptionResultEnum.ATTACHMENT_ERROR);
            } else {
                // 往任务表里插一条数据
                tbTaskHistory = new TBTaskHistory(TaskTypeEnum.IMPORT_EXAM_STUDENT, examId, TaskStatusEnum.INIT,
                        SystemConstant.IMPORT_INIT, 0d, tbAttachment.getName(), tbAttachment.getRemark(),
                        tbUser.getId(), tbUser.getOrgId());
                tbTaskHistory.setExamId(examId);
                taskHistoryService.save(tbTaskHistory);
                transMap.put("tbTaskHistory", tbTaskHistory);
            }
            transMap.put(SystemConstant.EXAM_ID, examId);
            transMap.put(SystemConstant.CREATE_ID, tbUser.getId());

            // 先查询考试相关信息
            ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);
            Optional.ofNullable(examCacheBean).orElseThrow(() -> new BusinessException(ExceptionResultEnum.EXAM_NO));

            TEExam teExam = teExamService.cacheConvert(examCacheBean);
            transMap.put("mode", teExam.getMode());
            transMap.put(SystemConstant.ORG_ID, teExam.getOrgId());
            transMap.put("examCount", teExam.getExamCount());

            // 获取该批次下的所有考场，校验考场id是否存在
            QueryWrapper<TEExamActivity> teExamActivityQueryWrapper = new QueryWrapper<>();
            teExamActivityQueryWrapper.lambda().eq(TEExamActivity::getExamId, examId);
            List<TEExamActivity> teExamActivityList = teExamActivityService.list(teExamActivityQueryWrapper);
            if (Objects.isNull(teExamActivityList) || teExamActivityList.size() == 0) {
                throw new BusinessException(ExceptionResultEnum.EXAM_ACTIVITY_NO);
            }
            Map<String, TEExamActivity> teExamActivityMap = teExamActivityList.stream()
                    .collect(Collectors.toMap(TEExamActivity::getCode, Function.identity(), (dto1, dto2) -> dto1));
            transMap.put("teExamActivityMap", teExamActivityMap);

            // 获取考场代码和考场名称
            QueryWrapper<TBExamInvigilateUser> tbExamInvigilateUserQueryWrapper = new QueryWrapper<>();
            tbExamInvigilateUserQueryWrapper.lambda().eq(TBExamInvigilateUser::getOrgId, teExam.getOrgId())
                    .eq(TBExamInvigilateUser::getExamId, examId);
            List<TBExamInvigilateUser> tbExamInvigilateUserList = tbExamInvigilateUserService
                    .list(tbExamInvigilateUserQueryWrapper);
            if (Objects.nonNull(tbExamInvigilateUserList) && tbExamInvigilateUserList.size() > 0) {
                Map<String, TBExamInvigilateUser> tbExamInvigilateUserMap = tbExamInvigilateUserList.stream().collect(
                        Collectors.toMap(TBExamInvigilateUser::getRoomCode, Function.identity(), (dto1, dto2) -> dto1));
                transMap.put("tbExamInvigilateUserMap", tbExamInvigilateUserMap);
            }
            transMap.put(SystemConstant.REMARK, tbAttachment.getRemark());
            // mq发送消息start
            MqDto mqDto = new MqDto(mqUtil.getTopic(), MqTagEnum.EXAM_STUDENT_IMPORT.name(), transMap,
                    MqTagEnum.EXAM_STUDENT_IMPORT, String.valueOf(tbTaskHistory.getId()), tbUser.getName());
            mqDtoService.assembleSendAsyncMsg(mqDto);
            // mq发送消息end
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (Objects.nonNull(tbAttachment)) {
                tbAttachmentService.deleteAttachment(mapParameter, UploadFileEnum.file, tbAttachment);
            }
            if (e instanceof BusinessException) {
                throw new BusinessException(e.getMessage());
            } else {
                throw new RuntimeException(e);
            }
        }
        return ResultUtil.ok(Collections.singletonMap(SystemConstant.TASK_ID, tbTaskHistory.getId()));
    }

    @ApiOperation(value = "成绩查询接口")
    @RequestMapping(value = "/mark/result", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "考试批次信息", response = MarkResultDto.class)})
    public Result markResult(@ApiParam(value = "考试批次id", required = true) @RequestParam Long examId,
                             @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long examActivityId,
                             @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
                             @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
                             @ApiParam(value = "科目代码", required = false) @RequestParam(required = false) String courseCode,
                             @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) int pageNumber,
                             @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) int pageSize) {
        if (Objects.isNull(examId) || Objects.equals(examId, "")) {
            throw new BusinessException(ExceptionResultEnum.EXAM_ID_IS_NULL);
        }
        commonMarkResult(examId);
        IPage<MarkResultDto> markResultDtoIPage = teExamStudentService
                .markResultQuery(new Page<>(pageNumber, pageSize), examId, examActivityId, identity, name, courseCode);
        if (Objects.nonNull(markResultDtoIPage)) {
            List<MarkResultDto> markResultDtoList = markResultDtoIPage.getRecords();
            if (!CollectionUtils.isEmpty(markResultDtoList)) {
                Set<String> examRecordIdsSet = new LinkedHashSet<>(markResultDtoList.size());
                for (MarkResultDto markResultDto : markResultDtoList) {
                    if (Objects.nonNull(markResultDto.getExamId())) {
                        ExamCacheBean examCacheBean = teExamService.getExamCacheBean(markResultDto.getExamId());
                        TOeExamRecord tOeExamRecord = tOeExamRecordService
                                .findMarkResult(markResultDto, examCacheBean.getRecordSelectStrategy());
                        if (Objects.nonNull(tOeExamRecord)) {
                            examRecordIdsSet.add(String.valueOf(tOeExamRecord.getId()));
                            markResultDto.setObjectiveScore(Objects.isNull(tOeExamRecord.getObjectiveScore()) ? 0 : tOeExamRecord.getObjectiveScore());
                            markResultDto.setRecordId(tOeExamRecord.getId());
                            markResultDto.setSubjectiveScore(Objects.isNull(markResultDto.getSubjectiveScore()) ? 0 : markResultDto.getSubjectiveScore());
                            markResultDto.setSumScore(markResultDto.getObjectiveScore() + markResultDto.getSubjectiveScore());
                            if (Objects.nonNull(tOeExamRecord.getFirstStartTime())) {
                                markResultDto.setFirstStartTime(tOeExamRecord.getFirstStartTime());
                            }
                            if (Objects.nonNull(tOeExamRecord.getFinishTime())) {
                                markResultDto.setFinishTime(tOeExamRecord.getFinishTime());
                            }
                        }
                    }
                }
                if (!CollectionUtils.isEmpty(examRecordIdsSet)) {
                    Map<Long, MarkResultDto> markResultDtoMap = markResultDtoList.stream().collect(
                            Collectors.toMap(MarkResultDto::getRecordId, Function.identity(), (dto1, dto2) -> dto1));

                    //获取云阅卷同步成绩
                    List<TSyncExamStudentScore> tSyncExamStudentScoreList = tSyncExamStudentScoreService.findByExamRecordIds(examRecordIdsSet);
                    if (!CollectionUtils.isEmpty(tSyncExamStudentScoreList)) {
                        for (TSyncExamStudentScore t : tSyncExamStudentScoreList) {
                            MarkResultDto markResultDto = markResultDtoMap.get(Long.parseLong(t.getExamNumber()));
                            if (Objects.nonNull(markResultDto)) {
                                markResultDto.setSubjectiveScore(Objects.isNull(t.getSubjectiveScore()) ? 0 : t.getSubjectiveScore());
                                markResultDto.setSumScore(markResultDto.getObjectiveScore() + markResultDto.getSubjectiveScore());
                            }
                        }
                    }
                }
            }
        }
        return ResultUtil.ok(markResultDtoIPage);
    }

    @ApiOperation(value = "成绩查询简版导出接口")
    @RequestMapping(value = "/mark/result/simple/export", method = RequestMethod.POST)
    @Transactional
    @ApiResponses({@ApiResponse(code = 200, message = "{\"taskId\":0}", response = Result.class)})
    public Result markResultSimpleExport(@ApiParam(value = "考试批次id", required = true) @RequestParam Long examId,
                                         @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long examActivityId,
                                         @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
                                         @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
                                         @ApiParam(value = "科目代码", required = false) @RequestParam(required = false) String courseCode) {
        if (Objects.isNull(examId) || Objects.equals(examId, "")) {
            throw new BusinessException(ExceptionResultEnum.EXAM_ID_IS_NULL);
        }
        TBTaskHistory tbTaskHistory = null;
        try {
            commonMarkResult(examId);
            Map transMap = new HashMap();
            TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
            //往任务表里插一条数据
            tbTaskHistory = new TBTaskHistory(TaskTypeEnum.EXPORT_MARK_RESULT_SIMPLE, TaskStatusEnum.INIT,
                    SystemConstant.EXPORT_INIT, 0d, tbUser.getId(), tbUser.getOrgId());
            tbTaskHistory.setExamId(examId);
            taskHistoryService.save(tbTaskHistory);
            transMap.put("tbTaskHistory", tbTaskHistory);
            transMap.put(SystemConstant.CREATE_ID, tbUser.getId());
            transMap.put(SystemConstant.ORG_ID, tbUser.getOrgId());
            transMap.put(SystemConstant.EXAM_ID, examId);
            transMap.put(SystemConstant.ACTIVITY_ID, examActivityId);
            transMap.put("identity", identity);
            transMap.put(SystemConstant.NAME, name);
            transMap.put(SystemConstant.COURSE_CODE, courseCode);
            //mq发送消息start
            MqDto mqDto = new MqDto(mqUtil.getTopic(), MqTagEnum.MARK_RESULT_SIMPLE_EXPORT.name(),
                    transMap, MqTagEnum.MARK_RESULT_SIMPLE_EXPORT, String.valueOf(tbTaskHistory.getId()),
                    tbUser.getName());
            mqDtoService.assembleSendAsyncMsg(mqDto);
            //mq发送消息end
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (e instanceof BusinessException) {
                throw new BusinessException(e.getMessage());
            } else {
                throw new RuntimeException(e);
            }
        }
        return ResultUtil.ok(Collections.singletonMap(SystemConstant.TASK_ID, tbTaskHistory.getId()));
    }

    @ApiOperation(value = "成绩查询标准版导出接口")
    @RequestMapping(value = "/mark/result/standard/export", method = RequestMethod.POST)
    @Transactional
    @ApiResponses({@ApiResponse(code = 200, message = "{\"taskId\":0}", response = Result.class)})
    public Result markResultStandardExport(@ApiParam(value = "考试批次id", required = true) @RequestParam Long examId,
                                           @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long examActivityId,
                                           @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
                                           @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
                                           @ApiParam(value = "科目代码", required = false) @RequestParam(required = false) String courseCode) {
        if (Objects.isNull(examId) || Objects.equals(examId, "")) {
            throw new BusinessException(ExceptionResultEnum.EXAM_ID_IS_NULL);
        }
        TBTaskHistory tbTaskHistory = null;
        try {
            commonMarkResult(examId);
            Map transMap = new HashMap();
            TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
            //往任务表里插一条数据
            tbTaskHistory = new TBTaskHistory(TaskTypeEnum.EXPORT_MARK_RESULT_STANDARD, TaskStatusEnum.INIT,
                    SystemConstant.EXPORT_INIT, 0d, tbUser.getId(), tbUser.getOrgId());
            tbTaskHistory.setExamId(examId);
            taskHistoryService.save(tbTaskHistory);
            transMap.put("tbTaskHistory", tbTaskHistory);
            transMap.put(SystemConstant.CREATE_ID, tbUser.getId());
            transMap.put(SystemConstant.ORG_ID, tbUser.getOrgId());
            transMap.put(SystemConstant.EXAM_ID, examId);
            transMap.put(SystemConstant.ACTIVITY_ID, examActivityId);
            transMap.put("identity", identity);
            transMap.put(SystemConstant.NAME, name);
            transMap.put(SystemConstant.COURSE_CODE, courseCode);
            //mq发送消息start
            MqDto mqDto = new MqDto(mqUtil.getTopic(), MqTagEnum.MARK_RESULT_STANDARD_EXPORT.name(),
                    transMap, MqTagEnum.MARK_RESULT_STANDARD_EXPORT, String.valueOf(tbTaskHistory.getId()),
                    tbUser.getName());
            mqDtoService.assembleSendAsyncMsg(mqDto);
            //mq发送消息end
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (e instanceof BusinessException) {
                throw new BusinessException(e.getMessage());
            } else {
                throw new RuntimeException(e);
            }
        }
        return ResultUtil.ok(Collections.singletonMap(SystemConstant.TASK_ID, tbTaskHistory.getId()));
    }

    /**
     * 成绩查询公用
     *
     * @param examId
     */
    private void commonMarkResult(Long examId) {
        ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);
        Optional.ofNullable(examCacheBean).orElseThrow(() -> new BusinessException(ExceptionResultEnum.EXAM_NO));

        InvigilateMonitorStatusEnum invigilateMonitorStatusEnum = examCacheBean.getMonitorStatus();//监考状态
        if (Objects.nonNull(invigilateMonitorStatusEnum) && !Objects
                .equals(invigilateMonitorStatusEnum, InvigilateMonitorStatusEnum.FINISHED)) {
            throw new BusinessException("当前批次监考未结束，请在结束后操作");
        }
        ScoreStatusEnum scoreStatusEnum = examCacheBean.getScoreStatus();//算分状态
        if (Objects.nonNull(scoreStatusEnum) && (Objects.equals(scoreStatusEnum, ScoreStatusEnum.CALCULATING) || Objects
                .equals(scoreStatusEnum, ScoreStatusEnum.NEED_CALCULATE))) {
            throw new BusinessException("当前批次算分未结束，请在结束后操作");
        }
        QueryWrapper<TEExamCourse> teExamCourseQueryWrapper = new QueryWrapper<>();
        teExamCourseQueryWrapper.lambda().eq(TEExamCourse::getExamId, examId);
        List<TEExamCourse> teExamCourseList = teExamCourseService.list(teExamCourseQueryWrapper);
        Set answerList = null;
        if (Objects.nonNull(teExamCourseList) && teExamCourseList.size() > 0) {
            answerList = teExamCourseList.stream().filter(s -> {
                if (Objects.nonNull(s.getHasAnswer()) && s.getHasAnswer().intValue() == 0) {
                    return true;
                } else {
                    return false;
                }
            }).collect(Collectors.toSet());
        }
        if (Objects.nonNull(answerList) && answerList.size() > 0) {
            throw new BusinessException("当前批次标答未补齐，请补齐后操作");
        }
    }

    @ApiOperation(value = "云阅卷成绩同步")
    @ApiResponses({@ApiResponse(code = 200, message = "成绩同步信息", response = Result.class)})
    @RequestMapping(value = "/cloud_mark/score/sync", method = RequestMethod.POST)
    public Result scoreSync(@ApiParam(value = "考试ID", required = true) @RequestParam String examId) {
        TBTaskHistory tbTaskHistory = null;
        try {
            ExamCacheBean examCacheBean = teExamService.getExamCacheBean(Long.parseLong(examId));
            Optional.ofNullable(examCacheBean).orElseThrow(() -> new BusinessException(ExceptionResultEnum.EXAM_NO));
            Optional.ofNullable(examCacheBean.getThirdExamId()).orElseThrow(() -> new BusinessException("云阅卷考试id为空，请先推送数据"));

            InvigilateMonitorStatusEnum invigilateMonitorStatusEnum = examCacheBean.getMonitorStatus();//监考状态
            if (Objects.nonNull(invigilateMonitorStatusEnum) && !Objects
                    .equals(invigilateMonitorStatusEnum, InvigilateMonitorStatusEnum.FINISHED)) {
                throw new BusinessException("当前批次监考未结束，请在结束后操作");
            }
            ScoreStatusEnum scoreStatusEnum = examCacheBean.getScoreStatus();//算分状态
            if (Objects.nonNull(scoreStatusEnum) && (Objects.equals(scoreStatusEnum, ScoreStatusEnum.CALCULATING) || Objects
                    .equals(scoreStatusEnum, ScoreStatusEnum.NEED_CALCULATE))) {
                throw new BusinessException("当前批次算分未结束，请在结束后操作");
            }
            QueryWrapper<TEExamCourse> teExamCourseQueryWrapper = new QueryWrapper<>();
            teExamCourseQueryWrapper.lambda().eq(TEExamCourse::getExamId, examId);
            List<TEExamCourse> teExamCourseList = teExamCourseService.list(teExamCourseQueryWrapper);
            Set answerList = null;
            if (Objects.nonNull(teExamCourseList) && teExamCourseList.size() > 0) {
                answerList = teExamCourseList.stream().filter(s -> {
                    if (Objects.nonNull(s.getHasAnswer()) && s.getHasAnswer().intValue() == 0) {
                        return true;
                    } else {
                        return false;
                    }
                }).collect(Collectors.toSet());
            }
            if (Objects.nonNull(answerList) && answerList.size() > 0) {
                throw new BusinessException("当前批次标答未补齐，请补齐后操作");
            }

            Map transMap = new HashMap();
            TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();

            QueryWrapper<TBTaskHistory> tbTaskHistoryQueryWrapper = new QueryWrapper<>();
            tbTaskHistoryQueryWrapper.lambda().eq(TBTaskHistory::getExamId, examCacheBean.getId())
                    .eq(TBTaskHistory::getType, TaskTypeEnum.CLOUD_MARK_SCORE_SYNC)
                    .orderByDesc(TBTaskHistory::getCreateTime)
                    .last(" limit 1 ");
            tbTaskHistory = taskHistoryService.getOne(tbTaskHistoryQueryWrapper);

            if (Objects.isNull(tbTaskHistory) || tbTaskHistory.getStatus() == TaskStatusEnum.FINISH) {
                //往任务表里插一条数据
                tbTaskHistory = new TBTaskHistory(TaskTypeEnum.CLOUD_MARK_SCORE_SYNC, TaskStatusEnum.INIT,
                        SystemConstant.SCORE_PUSH_INIT, 0d, tbUser.getId(), tbUser.getOrgId());
                tbTaskHistory.setExamId(Long.parseLong(examId));
                taskHistoryService.save(tbTaskHistory);
            } else if (tbTaskHistory.getStatus() != TaskStatusEnum.FINISH) {
                throw new BusinessException("当前同步任务正在进行中，请稍后再试！");
            }

            transMap.put("tbTaskHistory", tbTaskHistory);
            transMap.put(SystemConstant.CREATE_ID, tbUser.getId());
            transMap.put(SystemConstant.ORG_ID, tbUser.getOrgId());
            transMap.put(SystemConstant.EXAM_ID, Long.parseLong(examId));
            transMap.put(SystemConstant.EXAM_CODE, examCacheBean.getCode());
            //mq发送消息start
            MqDto mqDto = new MqDto(mqUtil.getTopic(), MqTagEnum.CLOUD_MARK_SCORE_SYNC.name(),
                    transMap, MqTagEnum.CLOUD_MARK_SCORE_SYNC, String.valueOf(tbTaskHistory.getId()),
                    tbUser.getName());
            mqDtoService.assembleSendAsyncMsg(mqDto);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (e instanceof BusinessException) {
                throw new BusinessException(e.getMessage());
            } else {
                throw new RuntimeException(e);
            }
        }
        return ResultUtil.ok(Collections.singletonMap(SystemConstant.TASK_ID, tbTaskHistory.getId()));
    }
}
