package com.qmth.themis.backend.api;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.cache.ExamRecordCacheUtil;
import com.qmth.themis.business.cache.RedisKeyHelper;
import com.qmth.themis.business.cache.bean.ExamActivityRecordCacheBean;
import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
import com.qmth.themis.business.constant.SystemConstant;
import com.qmth.themis.business.dto.AuthDto;
import com.qmth.themis.business.dto.ExamPropCountDto;
import com.qmth.themis.business.dto.MqDto;
import com.qmth.themis.business.dto.request.TEExamDto;
import com.qmth.themis.business.entity.*;
import com.qmth.themis.business.enums.*;
import com.qmth.themis.business.service.*;
import com.qmth.themis.business.util.JacksonUtil;
import com.qmth.themis.business.util.RedisUtil;
import com.qmth.themis.business.util.ServletUtil;
import com.qmth.themis.common.contanst.Constants;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @Description: 考试批次 前端控制器
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2020/6/25
 */
@Api(tags = "考试批次Controller")
@RestController
@RequestMapping("/${prefix.url.admin}/exam")
public class TEExamController {
    private final static Logger log = LoggerFactory.getLogger(TEExamController.class);

    @Resource
    TEExamService teExamService;

    @Resource
    TEExamActivityService teExamActivityService;

    @Resource
    MqDtoService mqDtoService;

    @Resource
    TBExamInvigilateUserService tbExamInvigilateUserService;

    @Resource
    TEExamStudentService teExamStudentService;

    @Resource
    RedisUtil redisUtil;

    @Resource
    TBTaskHistoryService taskHistoryService;

    @ApiOperation(value = "考试批次修改/新增接口")
    @RequestMapping(value = "/save", method = RequestMethod.POST)
    @Transactional
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    public Result save(@ApiParam(value = "考试批次信息", required = true) @RequestBody TEExamDto teExamDto) {
        if (Objects.isNull(teExamDto) || Objects.equals(teExamDto, "")) {
            throw new BusinessException(ExceptionResultEnum.EXAM_INFO_IS_NULL);
        }
        if (Objects.isNull(teExamDto.getMode()) || Objects.equals(teExamDto.getMode(), "")) {
            throw new BusinessException("考试模式不能为空");
        }
        if (Objects.isNull(teExamDto.getName()) || Objects.equals(teExamDto.getName(), "")) {
            throw new BusinessException("批次名称不能为空");
        }
        if (Objects.isNull(teExamDto.getCode()) || Objects.equals(teExamDto.getCode(), "")) {
            throw new BusinessException("批次编码不能为空");
        }
        TEExam teExam = null;
        Long oldId = null;
        String activityCode = null;
        try {
            TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
            TBOrg tbOrg = (TBOrg) ServletUtil.getRequestOrg();
            if (Objects.nonNull(tbOrg)) {
                if (Objects.isNull(tbOrg.getId())) {
                    throw new BusinessException("考试的机构id不允许为空");
                }
                teExamDto.setOrgId(tbOrg.getId());
            }
            oldId = teExamDto.getId();
            TEExam oldTeExam = null;
            if (Objects.nonNull(oldId)) {
                teExamDto.setUpdateId(tbUser.getId());
                oldTeExam = teExamService.getById(oldId);
            } else {
                teExamDto.setId(Constants.idGen.next());
                teExamDto.setCreateId(tbUser.getId());
            }
            teExam = new TEExam(teExamDto);
            if (oldTeExam != null) {
                teExam.setMonitorStatus(oldTeExam.getMonitorStatus());
            } else {
                teExam.setMonitorStatus(InvigilateMonitorStatusEnum.NOT_START);
            }
            teExamService.saveOrUpdate(teExam);
            if (Objects.nonNull(oldTeExam) && !Objects.equals(oldTeExam.getMode().name(), teExamDto.getMode().name())) {//如果模式改变，则删除之前模式的全部quartz
                QueryWrapper<TEExamActivity> teExamActivityQueryWrapper = new QueryWrapper<>();
                teExamActivityQueryWrapper.lambda().eq(TEExamActivity::getExamId, oldId);
                List<TEExamActivity> teExamActivityList = teExamActivityService.list(teExamActivityQueryWrapper);
                if (Objects.nonNull(teExamActivityList) && teExamActivityList.size() > 0) {
                    //删除quartz任务,发送mq消息start
                    Map<String, Object> prop = new HashMap<>();
                    prop.put("oper", "delete");
                    if (Objects.nonNull(teExamActivityList.get(0)) && teExamActivityList.get(0).getEnable() == 1) {
                        MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_ACTIVITY.name(), JacksonUtil.parseJson(teExamActivityList), MqTagEnum.EXAM_ACTIVITY, String.valueOf(teExam.getId()), prop, tbUser.getName());
                        mqDtoService.assembleSendOneWayMsg(mqDto);
                    }
                    //删除quartz任务,发送mq消息end
                    //删除数据
                    teExamActivityService.remove(teExamActivityQueryWrapper);
                }
            }
            //如果是随到随考，则默认插入一条场次信息
            if (Objects.equals(teExam.getMode().name(), ExamModeEnum.ANYTIME.name())) {//随到随考模式
                QueryWrapper<TEExamActivity> teExamActivityQueryWrapper = new QueryWrapper<>();
                teExamActivityQueryWrapper.lambda().eq(TEExamActivity::getExamId, oldId);
                List<TEExamActivity> teExamActivityList = teExamActivityService.list(teExamActivityQueryWrapper);
                if (Objects.nonNull(teExamActivityList) && teExamActivityList.size() > 0) {
                    //修改数据
                    TEExam finalTeExam = teExam;
                    teExamActivityList.forEach(s -> {
                        s.setPrepareSeconds(finalTeExam.getPrepareSeconds());
                        s.setMaxDurationSeconds(finalTeExam.getMaxDurationSeconds());
                        s.setOpeningSeconds((int) ((finalTeExam.getEndTime() - finalTeExam.getStartTime()) / 1000));
                        s.setStartTime(finalTeExam.getStartTime());
                        s.setFinishTime(finalTeExam.getEndTime());
                        s.setUpdateId(tbUser.getId());
                        teExamActivityService.saveOrUpdate(s);
                    });
                    for (TEExamActivity ac : teExamActivityList) {
                        teExamActivityService.updateExamActivityCacheBean(ac.getId());
                    }
                    if (Objects.nonNull(teExam.getForceFinish()) && teExam.getForceFinish().intValue() == 1) {
                        //新增quartz任务,发送mq消息start
                        Map<String, Object> prop = new HashMap<>();
                        prop.put("oper", "insert");
                        prop.put("exam", teExam);
                        MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_ACTIVITY.name(), JacksonUtil.parseJson(teExamActivityList), MqTagEnum.EXAM_ACTIVITY, String.valueOf(teExam.getId()), prop, tbUser.getName());
                        mqDtoService.assembleSendOneWayMsg(mqDto);
                        //新增quartz任务,发送mq消息end
                    }
                } else {
                    TEExamActivity teExamActivity = new TEExamActivity(teExam.getId(), teExam.getPrepareSeconds(), teExam.getMaxDurationSeconds(), (int) ((teExam.getEndTime() - teExam.getStartTime()) / 1000), teExam.getStartTime(), teExam.getEndTime(), tbUser.getId());
                    teExamActivity.setCode(String.valueOf(redisUtil.getRedisActivityCodeSequence(teExam.getId())));
                    activityCode = teExamActivity.getCode();
                    teExamActivity.setEnable(1);
                    teExamActivityService.saveOrUpdate(teExamActivity);
                    teExamActivityService.updateExamActivityCacheBean(teExamActivity.getId());
                    if (Objects.nonNull(teExam.getForceFinish()) && teExam.getForceFinish().intValue() == 1 && Objects.nonNull(teExamActivity) && teExamActivity.getEnable().intValue() == 1) {
                        //新增quartz任务,发送mq消息start
                        Map<String, Object> prop = new HashMap<>();
                        prop.put("oper", "insert");
                        prop.put("exam", teExam);
                        MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_ACTIVITY.name(), JacksonUtil.parseJson(Arrays.asList(teExamActivity)), MqTagEnum.EXAM_ACTIVITY, String.valueOf(teExam.getId()), prop, tbUser.getName());
                        mqDtoService.assembleSendOneWayMsg(mqDto);
                    }
                }
            }
        } catch (Exception e) {
            log.error("请求出错", e);
            if (Objects.nonNull(teExam) && Objects.nonNull(teExam.getId()) && Objects.nonNull(activityCode)) {
                redisUtil.setRedisActivityCodeSequence(teExam.getId(), Integer.parseInt(activityCode) - 1);
            }
            if (e instanceof DuplicateKeyException) {
                String errorColumn = e.getCause().toString();
                String columnStr = errorColumn.substring(errorColumn.lastIndexOf("key") + 3, errorColumn.length()).replaceAll("'", "");
                throw new BusinessException("机构id[" + teExam.getOrgId() + "]下的" + FieldUniqueEnum.convertToCode(columnStr) + "数据不允许重复插入");
            } else if (e instanceof BusinessException) {
                throw new BusinessException(e.getMessage());
            } else {
                throw new RuntimeException(e);
            }
        }
        teExamService.updateExamCacheBean(teExam.getId());
        return ResultUtil.ok(Collections.singletonMap("success", true));
    }

    @ApiOperation(value = "考试批次统计接口")
    @RequestMapping(value = "/count", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"count\":1}", response = Result.class)})
    public Result count(@ApiParam(value = "考试批次编码", required = false) @RequestParam(required = false) String code, @ApiParam(value = "考试批次名称", required = false) @RequestParam(required = false) String name, @ApiParam(value = "考试批次模式", required = false) @RequestParam(required = false) Integer mode) {
        QueryWrapper<TEExam> teExamQueryWrapper = new QueryWrapper<>();
        if (Objects.nonNull(code)) {
            teExamQueryWrapper.lambda().eq(TEExam::getCode, code);
        }
        if (Objects.nonNull(name)) {
            teExamQueryWrapper.lambda().eq(TEExam::getName, name);
        }
        if (Objects.nonNull(mode)) {
            teExamQueryWrapper.lambda().eq(TEExam::getMode, mode);
        }
        int count = teExamService.count(teExamQueryWrapper);
        return ResultUtil.ok(Collections.singletonMap(SystemConstant.COUNT, count));
    }

    @ApiOperation(value = "考试批次查询接口")
    @RequestMapping(value = "/query", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "考试批次信息", response = TEExam.class)})
    public Result query(@ApiParam(value = "用户id", required = false) @RequestParam(required = false) Long userId, @ApiParam(value = "考试批次id", required = false) @RequestParam(required = false) Long id, @ApiParam(value = "考试批次编码", required = false) @RequestParam(required = false) String code, @ApiParam(value = "考试批次名称", required = false) @RequestParam(required = false) String name, @ApiParam(value = "考试批次模式", required = false) @RequestParam(required = false) String mode, @ApiParam(value = "是否启用", required = false) @RequestParam(required = false) Integer enable, @ApiParam(value = "分页页码", required = true) @RequestParam int pageNumber, @ApiParam(value = "分页数", required = true) @RequestParam int pageSize) {
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        return ResultUtil.ok(teExamService.examQuery(new Page<>(pageNumber, pageSize), userId, id, code, name, mode, enable, tbUser.getOrgId()));
    }

    @ApiOperation(value = "考试批次停用/启用接口")
    @RequestMapping(value = "/toggle", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    @Transactional
    public Result examToggle(@ApiJsonObject(name = "examToggle", value = {
            @ApiJsonProperty(key = "id", type = "long", example = "1", description = "考试批次ID"),
            @ApiJsonProperty(key = "enable", type = "int", example = "1", description = "是否启用")
    }) @ApiParam(value = "考试批次信息", required = true) @RequestBody Map<String, Object> mapParameter) {
        if (Objects.isNull(mapParameter.get("id")) || Objects.equals(mapParameter.get("id"), "")) {
            throw new BusinessException(ExceptionResultEnum.EXAM_ID_IS_NULL);
        }
        Long examId = Long.parseLong(String.valueOf(mapParameter.get("id")));
        if (Objects.isNull(mapParameter.get("enable")) || Objects.equals(mapParameter.get("enable"), "")) {
            throw new BusinessException(ExceptionResultEnum.ENABLE_IS_NULL);
        }
        Integer enable = Integer.parseInt(String.valueOf(mapParameter.get("enable")));
        TEExam teExam = teExamService.getById(examId);
        if (Objects.isNull(teExam)) {
            throw new BusinessException(ExceptionResultEnum.EXAM_NO);
        }
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        teExam.setEnable(enable);
        teExam.setUpdateId(tbUser.getId());
        teExamService.updateById(teExam);
        teExamService.updateExamCacheBean(teExam.getId());
        return ResultUtil.ok(Collections.singletonMap("success", true));
    }

    @ApiOperation(value = "考试批次详情接口")
    @RequestMapping(value = "/detail", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "考试批次信息", response = TEExam.class)})
    public Result detail(@ApiParam(value = "考试批次id", required = true) @RequestParam Long id) {
        if (Objects.isNull(id) || Objects.equals(id, "")) {
            throw new BusinessException(ExceptionResultEnum.EXAM_ID_IS_NULL);
        }
        TEExam teExam = teExamService.getById(id);
        if (Objects.isNull(teExam)) {
            throw new BusinessException(ExceptionResultEnum.EXAM_NO);
        }
        return ResultUtil.ok(new TEExamDto(teExam));
    }

    @ApiOperation(value = "考试批次复制接口")
    @RequestMapping(value = "/copy", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    @Transactional
    public Result copy(@ApiJsonObject(name = "examCopy", value = {
            @ApiJsonProperty(key = "sourceId", type = "long", example = "1", description = "来源批次ID"),
            @ApiJsonProperty(key = "code", description = "代码"),
            @ApiJsonProperty(key = "name", description = "名称")
    }) @ApiParam(value = "考试批次信息", required = true) @RequestBody Map<String, Object> mapParameter) {
        if (Objects.isNull(mapParameter.get("sourceId")) || Objects.equals(mapParameter.get("sourceId"), "")) {
            throw new BusinessException(ExceptionResultEnum.EXAM_ID_IS_NULL);
        }
        Long examId = Long.parseLong(String.valueOf(mapParameter.get("sourceId")));
        if (Objects.isNull(mapParameter.get("code")) || Objects.equals(mapParameter.get("code"), "")) {
            throw new BusinessException(ExceptionResultEnum.EXAM_CODE_IS_NULL);
        }
        String code = String.valueOf(mapParameter.get("code"));
        if (Objects.isNull(mapParameter.get("name")) || Objects.equals(mapParameter.get("name"), "")) {
            throw new BusinessException(ExceptionResultEnum.EXAM_NAME_IS_NULL);
        }
        String name = String.valueOf(mapParameter.get("name"));
        TEExam teExam = teExamService.getById(examId);
        if (Objects.isNull(teExam)) {
            throw new BusinessException(ExceptionResultEnum.EXAM_NO);
        }
        List<TEExamActivity> teExamActivityList = null;
        try {
            teExam.setId(null);
            teExam.setUpdateId(null);
            teExam.setUpdateTime(null);
            TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
            teExam.setCreateId(tbUser.getId());
            teExam.setCode(code);
            teExam.setName(name);
            teExamService.save(teExam);

            QueryWrapper<TEExamActivity> teExamActivityQueryWrapper = new QueryWrapper<>();
            teExamActivityQueryWrapper.lambda().eq(TEExamActivity::getExamId, examId);
            teExamActivityList = teExamActivityService.list(teExamActivityQueryWrapper);
            if (Objects.nonNull(teExamActivityList)) {
                teExamActivityList.forEach(s -> {
                    s.setId(null);
                    s.setExamId(teExam.getId());
                    s.setCreateId(teExam.getCreateId());
                    s.setUpdateId(null);
                    s.setUpdateTime(null);
                    s.setCode(String.valueOf(redisUtil.getRedisActivityCodeSequence(teExam.getId())));
                });
                for (TEExamActivity ac : teExamActivityList) {
                    teExamActivityService.saveOrUpdate(ac);
                }
            }
        } catch (Exception e) {
            log.error("请求出错", e);
            if (Objects.nonNull(examId) && Objects.nonNull(teExam.getId()) && (Objects.nonNull(teExamActivityList) && teExamActivityList.size() > 0 && Objects.nonNull(teExamActivityList.get(0)))) {
                redisUtil.setRedisActivityCodeSequence(examId, Integer.parseInt(teExamActivityList.get(0).getCode()) - 1);
            }
            if (e instanceof DuplicateKeyException) {
                String errorColumn = e.getCause().toString();
                String columnStr = errorColumn.substring(errorColumn.lastIndexOf("key") + 3, errorColumn.length()).replaceAll("'", "");
                throw new BusinessException("机构id[" + teExam.getOrgId() + "]下的" + FieldUniqueEnum.convertToCode(columnStr) + "数据不允许重复插入");
            } else if (e instanceof BusinessException) {
                throw new BusinessException(e.getMessage());
            } else {
                throw new RuntimeException(e);
            }
        }
        return ResultUtil.ok(Collections.singletonMap("success", true));
    }

    @ApiOperation(value = "监考端获取考试批次提醒接口")
    @RequestMapping(value = "/list/count", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "考试批次信息", response = Result.class)})
    public Result listCount(@ApiParam(value = "用户id", required = false) @RequestParam(required = false) Long userId) {
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        return ResultUtil.ok(teExamService.examList(userId, tbUser.getOrgId()));
    }

    @ApiOperation(value = "考试属性统计接口")
    @RequestMapping(value = "/prop/count", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "考试属性信息", response = ExamPropCountDto.class)})
    public Result propCount(@ApiParam(value = "考试id", required = true) @RequestParam Long examId) {
        if (Objects.isNull(examId) || Objects.equals(examId, "")) {
            throw new BusinessException(ExceptionResultEnum.EXAM_ID_IS_NULL);
        }
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        TBSession tbSession = (TBSession) ServletUtil.getRequestSession();
        if (Objects.isNull(tbSession)) {
            throw new BusinessException(ExceptionResultEnum.LOGIN_NO);
        }
        //首先查询当前用户所要监控的roomCode
        QueryWrapper<TBExamInvigilateUser> examInvigilateUserQueryWrapper = new QueryWrapper<>();
        AuthDto authDto = (AuthDto) redisUtil.get(SystemConstant.userOauth + "::" + tbUser.getId());
        //如果有监考员角色，只能查看自己所监考的考场，巡考员和管理员则可以查看全部考场
        examInvigilateUserQueryWrapper.lambda().eq(TBExamInvigilateUser::getOrgId, tbUser.getOrgId())
                .eq(TBExamInvigilateUser::getExamId, examId);
        if (authDto.getRoleCodes().toString().contains(RoleEnum.INVIGILATE.name())) {
            examInvigilateUserQueryWrapper.lambda().eq(TBExamInvigilateUser::getUserId, tbUser.getId());
        }
        List<TBExamInvigilateUser> tbExamInvigilateUserList = tbExamInvigilateUserService.list(examInvigilateUserQueryWrapper);
        Set<String> roomCodeSet = null;
        if (Objects.nonNull(tbExamInvigilateUserList) && tbExamInvigilateUserList.size() > 0) {
            roomCodeSet = tbExamInvigilateUserList.stream().map(s -> s.getRoomCode()).collect(Collectors.toSet());
        }
        if (authDto.getRoleCodes().toString().contains(RoleEnum.INVIGILATE.name()) && (Objects.isNull(roomCodeSet) || roomCodeSet.size() == 0)) {
            throw new BusinessException("当前监考老师未设置任何监考考场");
        }
        ExamPropCountDto examPropCountDto = null;
        if (Objects.nonNull(roomCodeSet) && roomCodeSet.size() > 0) {
            //根据roomCode获取当前老师所要监考的全部应考学生数
            QueryWrapper<TEExamStudent> teExamStudentQueryWrapper = new QueryWrapper<>();
            teExamStudentQueryWrapper.lambda().eq(TEExamStudent::getExamId, examId)
                    .in(TEExamStudent::getRoomCode, roomCodeSet).eq(TEExamStudent::getEnable, 1);
            List<TEExamStudent> teExamStudentList = teExamStudentService.list(teExamStudentQueryWrapper);
            Set<String> studentSet = null;
            Set<Long> examActivityIdSet = null;
            Integer allCount = 0;
            AtomicReference<Integer> prepareCount = new AtomicReference<>(0);
            AtomicReference<Integer> examCount = new AtomicReference<>(0);
            AtomicReference<Integer> clientWebsocketStatusCount = new AtomicReference<>(0);
            AtomicReference<Integer> monitorStatusSourceCount = new AtomicReference<>(0);
            Integer notComplete = 0;
            if (Objects.nonNull(teExamStudentList) && teExamStudentList.size() > 0) {
                studentSet = new HashSet<>();
                examActivityIdSet = new HashSet<>();
                Set<Long> finalExamActivityIdSet = examActivityIdSet;
                Set<String> finalStudentSet = studentSet;
                teExamStudentList.forEach(s -> {
                    finalStudentSet.add(SystemConstant.STUDENT + s.getStudentId());
                    finalExamActivityIdSet.add(s.getExamActivityId());
                });
                allCount = studentSet.size();
            }

            Set<Long> alreadyComplete = null;
            if (Objects.nonNull(examActivityIdSet)) {
                alreadyComplete = new HashSet<>();
                //获取已待考、考试中、已完成学生
                Set<Long> finalAlreadyComplete = alreadyComplete;
                examActivityIdSet.forEach(s -> {
                    Map<String, Object> objectMap = redisUtil.getHashEntries(RedisKeyHelper.examActivityRecordCacheKey(s));
                    if (Objects.nonNull(objectMap) && objectMap.size() > 0) {
                        objectMap.forEach((k, v) -> {
                            Long recordId = Long.parseLong(k);
                            ExamActivityRecordCacheBean examActivityRecordCacheBean = (ExamActivityRecordCacheBean) v;
                            ExamRecordStatusEnum examRecordStatusEnum = examActivityRecordCacheBean.getStatus();
                            ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examActivityRecordCacheBean.getExamStudentId());
                            if (Objects.nonNull(examStudentCacheBean) && examStudentCacheBean.getEnable().intValue() == 1 && Objects.nonNull(examRecordStatusEnum) && !Objects.equals(examRecordStatusEnum, ExamRecordStatusEnum.PERSISTED) && !Objects.equals(examRecordStatusEnum, ExamRecordStatusEnum.FINISHED)) {
                                //客户端通讯状态
                                WebsocketStatusEnum clientStatus = Objects.isNull(ExamRecordCacheUtil.getClientWebsocketStatus(recordId)) ? null : ExamRecordCacheUtil.getClientWebsocketStatus(recordId);
                                if (Objects.nonNull(clientStatus) && Objects.equals(clientStatus, WebsocketStatusEnum.OFF_LINE)) {
                                    clientWebsocketStatusCount.getAndSet(clientWebsocketStatusCount.get() + 1);
                                }
                                //监控端通讯状态
                                MonitorVideoSourceEnum source = null;
                                if (Objects.nonNull(ExamRecordCacheUtil.getMonitorLiveUrlClientCamera(recordId))) {
                                    source = MonitorVideoSourceEnum.CLIENT_CAMERA;
                                } else if (Objects.nonNull(ExamRecordCacheUtil.getMonitorLiveUrlClientScreen(recordId))) {
                                    source = MonitorVideoSourceEnum.CLIENT_SCREEN;
                                } else if (Objects.nonNull(ExamRecordCacheUtil.getMonitorLiveUrlMobileFirst(recordId))) {
                                    source = MonitorVideoSourceEnum.MOBILE_FIRST;
                                } else if (Objects.nonNull(ExamRecordCacheUtil.getMonitorLiveUrlMobileSecond(recordId))) {
                                    source = MonitorVideoSourceEnum.MOBILE_SECOND;
                                }
                                MonitorStatusSourceEnum status = Objects.isNull(source) ? null : ExamRecordCacheUtil.getMonitorStatus(recordId, source.name());
                                if (Objects.nonNull(status) && Objects.equals(status, MonitorStatusSourceEnum.STOP)) {
                                    monitorStatusSourceCount.getAndSet(monitorStatusSourceCount.get() + 1);
                                }
                            }
                            //已待考
                            if (Objects.equals(examRecordStatusEnum, ExamRecordStatusEnum.FIRST_PREPARE)) {
                                prepareCount.getAndSet(prepareCount.get() + 1);
                            }
                            //考试中
                            else if (Objects.equals(examRecordStatusEnum, ExamRecordStatusEnum.ANSWERING) || Objects.equals(examRecordStatusEnum, ExamRecordStatusEnum.RESUME_PREPARE)) {
                                examCount.getAndSet(examCount.get() + 1);
                            }
                            //已完成
                            else if (Objects.equals(examRecordStatusEnum, ExamRecordStatusEnum.FINISHED) || Objects.equals(examRecordStatusEnum, ExamRecordStatusEnum.PERSISTED)) {
                                finalAlreadyComplete.add(examActivityRecordCacheBean.getExamStudentId());
                            }
                        });
                    }
                });
            }
            notComplete = allCount - alreadyComplete.size();
            BigDecimal completionRate = new BigDecimal(alreadyComplete.size()).divide(new BigDecimal(allCount), 2, BigDecimal.ROUND_HALF_UP).setScale(2, BigDecimal.ROUND_HALF_UP);
            examPropCountDto = new ExamPropCountDto(examId, allCount, prepareCount.get(), examCount.get(), clientWebsocketStatusCount.get(), monitorStatusSourceCount.get(), alreadyComplete.size(), notComplete, completionRate);
        } else {
            examPropCountDto = new ExamPropCountDto(examId, 0, 0, 0, 0, 0, 0, 0, new BigDecimal(0));
        }
        return ResultUtil.ok(examPropCountDto);
    }

    @ApiOperation(value = "考试重新算分")
    @RequestMapping(value = "/score/calculate", method = RequestMethod.POST)
    @Transactional
    @ApiResponses({@ApiResponse(code = 200, message = "{\"taskId\":0}", response = Result.class)})
    public Result scoreCalculate(@ApiParam(value = "批次ID", required = true) @RequestParam Long id) {
        //先查询考试相关信息
        TEExam teExam = teExamService.getById(id);
        if (Objects.isNull(teExam)) {
            throw new BusinessException(ExceptionResultEnum.EXAM_NO);
        }
        TBTaskHistory tbTaskHistory = null;
        Map<String, Object> transMap = new HashMap<String, Object>();
        try {
            TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
            //往任务表里插一条数据
            tbTaskHistory = new TBTaskHistory(TaskTypeEnum.CALCULATE_EXAM_SCORE, TaskStatusEnum.INIT, "重新算分", 0d, tbUser.getId());
            tbTaskHistory.setEntityId(id);
            taskHistoryService.save(tbTaskHistory);
            transMap.put("examId", id);
            transMap.put(SystemConstant.TASK_ID, tbTaskHistory.getId());
            //mq发送消息start
            MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_SCORE_CALCULATE.name(), transMap, MqTagEnum.EXAM_SCORE_CALCULATE, String.valueOf(tbTaskHistory.getId()), tbUser.getName());
            mqDtoService.assembleSendOneWayMsg(mqDto);
            //mq发送消息end
        } catch (Exception e) {
            if (e instanceof BusinessException) {
                throw new BusinessException(e.getMessage());
            } else {
                throw new RuntimeException(e);
            }
        }
        Map<String, Long> map = new HashMap<String, Long>();
        map.put(SystemConstant.TASK_ID, tbTaskHistory.getId());
        return ResultUtil.ok(map);
    }
}