package com.qmth.themis.exam.api;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qmth.themis.business.annotation.ApiJsonObject;
import com.qmth.themis.business.annotation.ApiJsonProperty;
import com.qmth.themis.business.bean.exam.*;
import com.qmth.themis.business.cache.ExamBreakCacheUtil;
import com.qmth.themis.business.cache.ExamRecordCacheUtil;
import com.qmth.themis.business.constant.SystemConstant;
import com.qmth.themis.business.dto.MqDto;
import com.qmth.themis.business.dto.cache.TEStudentCacheDto;
import com.qmth.themis.business.dto.response.TEExamDto;
import com.qmth.themis.business.dto.response.TEExamWaitDto;
import com.qmth.themis.business.entity.SysConfig;
import com.qmth.themis.business.entity.TEExam;
import com.qmth.themis.business.entity.TOeExamRecord;
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.MqUtil;
import com.qmth.themis.business.util.RedisUtil;
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.IpUtil;
import com.qmth.themis.common.util.Result;
import com.qmth.themis.common.util.ResultUtil;
import com.qmth.themis.exam.config.ExamConstant;
import com.qmth.themis.exam.websocket.WebSocketOeServer;
import io.swagger.annotations.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Api(tags = "考试Controller")
@RestController
@RequestMapping(SystemConstant.PREFIX_URL_OE + "/exam")
public class TEExamController {

    @Resource
    TEExamService teExamService;

    @Resource
    RedisUtil redisUtil;

    @Resource
    MqDtoService mqDtoService;

    @Resource
    TOeExamRecordService tOeExamRecordService;

    @Resource
    TOeExamBreakHistoryService tOeExamBreakHistoryService;

    @Resource
    MqUtil mqUtil;

    @Resource
    ThemisCacheService themisCacheService;

    @ApiOperation(value = "验证考试口令接口")
    @RequestMapping(value = "/short_code", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "考试信息", response = TEExam.class)})
    public Result shortCode(@ApiJsonObject(name = "shortCode", value = {
            @ApiJsonProperty(key = "shortCode", description = "考试口令")}) @ApiParam(value = "考试口令", required = true) @RequestBody Map<String, Object> mapParameter) {
        if (Objects.isNull(mapParameter.get("shortCode")) || Objects.equals(mapParameter.get("shortCode"), "")) {
            throw new BusinessException(ExceptionResultEnum.SHORT_CODE_IS_NULL);
        }
        String shortCode = String.valueOf(mapParameter.get("shortCode"));
        QueryWrapper<TEExam> teExamQueryWrapper = new QueryWrapper<>();
        teExamQueryWrapper.lambda().eq(TEExam::getShortCode, shortCode).eq(TEExam::getEnable, 1);
        TEExam teExam = teExamService.getOne(teExamQueryWrapper);
        Optional.ofNullable(teExam).orElseThrow(() -> new BusinessException(ExceptionResultEnum.EXAM_NO));

        Map<String, Object> map = new HashMap<>();
        map.put(SystemConstant.ID, teExam.getId());
        map.put(SystemConstant.NAME, teExam.getName());
        return ResultUtil.ok(map);
    }

    @ApiOperation(value = "获取待考列表接口")
    @RequestMapping(value = "/waiting", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "考试列表", response = TEExamDto.class)})
    public Result waiting(@ApiJsonObject(name = "examWaiting", value = {
            @ApiJsonProperty(key = "examId", type = "long", example = "1", description = "批次id")}) @ApiParam(value = "考试口令", required = true) @RequestBody Map<String, Object> mapParameter) {
        Long examId = Objects.nonNull(mapParameter.get(SystemConstant.EXAM_ID)) ?
                Long.parseLong(String.valueOf(mapParameter.get(SystemConstant.EXAM_ID))) :
                null;
        TEStudentCacheDto teStudent = (TEStudentCacheDto) ServletUtil.getRequestStudentAccount();
        List<TEExamWaitDto> list = teExamService.getWaitingExam(teStudent.getId(), examId, teStudent.getOrgId());
        return ResultUtil.ok(Collections.singletonMap("waiting", list));
    }

    @ApiOperation(value = "开始候考")
    @RequestMapping(value = "/prepare", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "候考信息", response = ExamPrepareBean.class)})
    public Result prepare(@RequestBody PrepareParamBean param) {
        TEStudentCacheDto teStudent = (TEStudentCacheDto) ServletUtil.getRequestStudentAccount();
        String lockKey = SystemConstant.REDIS_LOCK_STUDENT_PREFIX + teStudent.getId();
        if (!redisUtil.lock(lockKey, SystemConstant.REDIS_CACHE_TIME_OUT)) {
            throw new BusinessException(ExceptionResultEnum.REQUEST_AWAIT);
        }
        try {
            if (param.getExamStudentId() == null) {
                throw new BusinessException(ExceptionResultEnum.EXAM_STUDENT_ID_IS_NULL);
            }
            ExamPrepareBean examPrepareBean = teExamService.prepare(teStudent.getId(), param.getExamStudentId());
            ExamRecordCacheUtil.setClientCurrentIp(examPrepareBean.getRecordId(), IpUtil.getRemoteIp(ServletUtil.getRequest()));
            return ResultUtil.ok(examPrepareBean);
        } finally {
            redisUtil.releaseLock(lockKey);
        }
    }

    @ApiOperation(value = "候考/答题状态退出")
    @RequestMapping(value = "/exit", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
    public Result exit(@ApiJsonObject(name = "saveInvigilateUser", value = {
            @ApiJsonProperty(key = "recordId", type = "long", example = "1", description = "考试记录id", required = true)}) @ApiParam(value = "考试记录id", required = true) @RequestBody Map<String, Object> mapParameter)
            throws NoSuchAlgorithmException, IOException {
        if (Objects.isNull(mapParameter.get(SystemConstant.RECORD_ID)) || Objects
                .equals(mapParameter.get(SystemConstant.RECORD_ID), "")) {
            throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
        }
        Long recordId = Long.parseLong((String) mapParameter.get(SystemConstant.RECORD_ID));
        ExamRecordStatusEnum examStatus = ExamRecordCacheUtil.getStatus(recordId);
        if (Objects.nonNull(examStatus) && Objects.equals(ExamRecordStatusEnum.ANSWERING, examStatus)) {//答题状态，强制断点
            ExamConstant.sendExamStopMsg(recordId, true, false);
            tOeExamRecordService.examBreakLogic(recordId, true);
        } else if (Objects.nonNull(examStatus) && Objects.equals(ExamRecordStatusEnum.FIRST_PREPARE, examStatus)) {
            ExamConstant.sendExamStopMsg(recordId, false, true);
        } else {
            if (Objects.nonNull(examStatus) && (ExamRecordStatusEnum.FINISHED == examStatus || ExamRecordStatusEnum.PERSISTED == examStatus || ExamRecordStatusEnum.JUNK == examStatus)) {
                throw new BusinessException(ExceptionResultEnum.EXAM_FINISH);
            } else {
                throw new BusinessException(ExceptionResultEnum.EXAM_STATUS_ERROR);
            }
        }

        MonitorVideoSourceEnum source = MonitorVideoSourceEnum.CLIENT_CAMERA;
        SysConfig sysConfig = themisCacheService.addSysConfigCache(SystemConstant.MONITOR_CONFIG_PREFIX);
        Optional.ofNullable(sysConfig).orElseThrow(() -> new BusinessException("未配置监控前缀"));

        MonitorCallStatusSourceEnum callStatus = Objects.nonNull(ExamRecordCacheUtil.getMonitorCallStatus(recordId, source)) ? ExamRecordCacheUtil.getMonitorCallStatus(recordId, source) : null;
        if (Objects.nonNull(callStatus) && (callStatus == MonitorCallStatusSourceEnum.START
                || callStatus == MonitorCallStatusSourceEnum.CALLING)) {
            Long timestamp = System.currentTimeMillis();
            MonitorCallStatusSourceEnum updateCallStatus = MonitorCallStatusSourceEnum.STOP;
            if (callStatus == MonitorCallStatusSourceEnum.START) {
                updateCallStatus = MonitorCallStatusSourceEnum.CANCEL;
            }
            ExamRecordCacheUtil.setMonitorCallStatus(recordId, source, updateCallStatus, timestamp);
            tOeExamRecordService.sendExamRecordDataSaveMq(recordId, timestamp);
        }

        ConcurrentHashMap<String, WebSocketOeServer> webSocketMap = WebSocketOeServer.getWebSocketMap();
        String clientWebsocketId = ExamRecordCacheUtil.getClientWebsocketId(recordId);
        if (Objects.nonNull(clientWebsocketId)) {
            WebSocketOeServer webSocketOeServer = webSocketMap.get(clientWebsocketId);
            WebSocketOeServer.close(webSocketOeServer);
        }
        ExamRecordCacheUtil.setClientCurrentIp(recordId, IpUtil.getRemoteIp(ServletUtil.getRequest()));
        return ResultUtil.ok(true);
    }

    @ApiOperation(value = "开始考试")
    @RequestMapping(value = "/start", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "试卷信息")})
    public Result start(@RequestBody ExamStartParamBean param) {
        TEStudentCacheDto teStudent = (TEStudentCacheDto) ServletUtil.getRequestStudentAccount();
        String lockKey = SystemConstant.REDIS_LOCK_STUDENT_PREFIX + teStudent.getId();
        if (!redisUtil.lock(lockKey, SystemConstant.REDIS_CACHE_TIME_OUT)) {
            throw new BusinessException(ExceptionResultEnum.REQUEST_AWAIT);
        }
        try {
            if (Objects.isNull(param.getRecordId()) || Objects.equals(param.getRecordId(), "")) {
                throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
            }
            ExamStartBean examStartBean = teExamService.start(teStudent.getId(), param.getRecordId());
            if (Objects.nonNull(param.getReason())) {
                Long breakId = ExamRecordCacheUtil.getLastBreakId(param.getRecordId());
                if (Objects.nonNull(breakId)) {
                    JSONObject jsonObject = JSONObject.parseObject(param.getReason());
//                    ExceptionEnum exceptionEnum = ExceptionEnum
//                            .valueOf(ExceptionEnum.convertToName(String.valueOf(jsonObject.get(SystemConstant.TYPE))));
                    String reason = String.valueOf(jsonObject.get("reason"));
                    ExamBreakCacheUtil.setBreakReason(breakId, ExceptionEnum.EXAM_BREAK);
                    ExamBreakCacheUtil.setResumeReason(breakId, reason);
                    tOeExamBreakHistoryService.sendExamRecordBreakHistoryDataMq(breakId);
                    //考试断点异常原因 发送mq start
                    MqDto mqDto = new MqDto(mqUtil.getTopic(), MqTagEnum.EXCEPTION_LOG.name(),
                            JacksonUtil.parseJson(param), MqTagEnum.EXCEPTION_LOG, String.valueOf(param.getRecordId()),
                            param.getReason());
                    mqDtoService.assembleSendAsyncMsg(mqDto);
                    //考试断点异常原因 发送mq end
                }
            } else {
                //mq发送消息start
                MqDto mqDto = new MqDto(mqUtil.getTopic(), MqTagEnum.STUDENT.name(),
                        SystemOperationEnum.ANSWERING, MqTagEnum.STUDENT, String.valueOf(teStudent.getId()),
                        IpUtil.getRemoteIp(ServletUtil.getRequest()));
                teExamService.sendOeLogMessage(SystemOperationEnum.ANSWERING,
                        ExamRecordCacheUtil.getExamStudentId(param.getRecordId()), param.getRecordId(), mqDto);
                //mq发送消息end
            }
            ExamConstant.sendExamStartMsg(param.getRecordId());
            ExamRecordCacheUtil.setClientCurrentIp(param.getRecordId(), IpUtil.getRemoteIp(ServletUtil.getRequest()));
            return ResultUtil.ok(examStartBean);
        } finally {
            redisUtil.releaseLock(lockKey);
        }
    }

    @ApiOperation(value = "上传个人试卷结构")
    @RequestMapping(value = "/student_paper_struct/upload", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "试卷信息")})
    public Result studentPaperStruct(@RequestBody StudentPaperStructParamBean param) {
        TEStudentCacheDto teStudent = (TEStudentCacheDto) ServletUtil.getRequestStudentAccount();
        if (Objects.isNull(param.getRecordId()) || Objects.equals(param.getRecordId(), "")) {
            throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
        }
        if (param.getContent() == null) {
            throw new BusinessException("试卷结构json字符串不能为空");
        }
        ExamRecordCacheUtil.setClientCurrentIp(param.getRecordId(), IpUtil.getRemoteIp(ServletUtil.getRequest()));
        return ResultUtil
                .ok(teExamService.studentPaperStruct(teStudent.getId(), param.getRecordId(), param.getContent()));
    }

    @ApiOperation(value = "提交作答结果")
    @RequestMapping(value = "/answer/submit", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "试卷信息")})
    public Result answerSubmit(@RequestBody AnswerSubmitParamBean param) throws IOException {
        TEStudentCacheDto teStudent = (TEStudentCacheDto) ServletUtil.getRequestStudentAccount();
        if (Objects.isNull(param.getRecordId()) || Objects.equals(param.getRecordId(), "")) {
            throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
        }
        if (param.getMainNumber() == null) {
            throw new BusinessException("大题号不能为空");
        }
        if (param.getSubNumber() == null) {
            throw new BusinessException("小题号不能为空");
        }
        if (param.getAnswer() == null) {
            throw new BusinessException("答案json字符串不能为空");
        }
        if (param.getVersion() == null) {
            throw new BusinessException("时间戳不能为空");
        }

        //        Map mqMap = new HashMap<>();
        //        mqMap.put(SystemConstant.RECORD_ID, param.getRecordId());
        //        mqMap.put("source", MonitorVideoSourceEnum.MOBILE_FIRST.name());
        //        //监控结束
        //        MqDto mqDtoStop = new MqDto(mqUtil.getTopic(), MqTagEnum.MONITOR_STOP.name(), param.getRecordId(), MqTagEnum.MONITOR_STOP, String.valueOf(param.getRecordId()), mqMap, String.valueOf(param.getRecordId()));
        //        mqDtoService.assembleSendOneOrderMsg(mqDtoStop);

        //        ExamRecordCacheUtil.setStatus(param.getRecordId(), ExamRecordStatusEnum.FINISHED, System.currentTimeMillis());
        //        ConcurrentHashMap<String, WebSocketOeServer> webSocketMap = WebSocketOeServer.getWebSocketMap();
        //        String clientWebsocketId = ExamRecordCacheUtil.getClientWebsocketId(param.getRecordId());
        //        if (Objects.nonNull(clientWebsocketId)) {
        //            WebSocketOeServer webSocketOeServer = webSocketMap.get(clientWebsocketId);
        //            WebSocketOeServer.close(webSocketOeServer);
        //        }

        AnswerSubmitBean ret = teExamService
                .answerSubmit(teStudent.getId(), param.getRecordId(), param.getMainNumber(), param.getSubNumber(),
                        param.getSubIndex(), param.getAnswer(), param.getVersion(), param.getDurationSeconds());
        ExamRecordCacheUtil.setClientCurrentIp(param.getRecordId(), IpUtil.getRemoteIp(ServletUtil.getRequest()));
        return ResultUtil.ok(ret);
        //        return ResultUtil.ok(true);
    }

    @ApiOperation(value = "更新音频剩余播放次数")
    @RequestMapping(value = "/audio_left_play_count/submit", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "试卷信息")})
    public Result audioLeftPlayCountSubmit(@RequestBody AudioLeftPlayCountSubmitParamBean param) {
        TEStudentCacheDto teStudent = (TEStudentCacheDto) ServletUtil.getRequestStudentAccount();
        if (Objects.isNull(param.getRecordId()) || Objects.equals(param.getRecordId(), "")) {
            throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
        }
        if (param.getKey() == null) {
            throw new BusinessException("音频标识不能为空");
        }
        if (param.getCount() == null) {
            throw new BusinessException("剩余播放次数不能为空");
        }
        ExamRecordCacheUtil.setClientCurrentIp(param.getRecordId(), IpUtil.getRemoteIp(ServletUtil.getRequest()));
        return ResultUtil.ok(teExamService
                .audioLeftPlayCountSubmit(teStudent.getId(), param.getRecordId(), param.getKey(), param.getCount()));
    }

    @ApiOperation(value = "文件上传")
    @RequestMapping(value = "/file/upload", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "试卷信息")})
    public Result fileUpload(@ApiParam(value = "考试记录ID", required = true) @RequestParam Long recordId,
                             @ApiParam(value = "上传文件", required = true) @RequestParam MultipartFile file,
                             @ApiParam(value = "后缀名", required = true) @RequestParam String suffix,
                             @ApiParam(value = "md5", required = true) @RequestParam String md5) {
        TEStudentCacheDto teStudent = (TEStudentCacheDto) ServletUtil.getRequestStudentAccount();
        ExamRecordCacheUtil.setClientCurrentIp(recordId, IpUtil.getRemoteIp(ServletUtil.getRequest()));
        return ResultUtil.ok(teExamService.fileUpload(teStudent.getId(), recordId, file, suffix, md5));
    }

    @ApiOperation(value = "断点恢复")
    @RequestMapping(value = "/resume", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "试卷信息")})
    public Result resume(@RequestBody ResumeParamBean param) {
        TEStudentCacheDto teStudent = (TEStudentCacheDto) ServletUtil.getRequestStudentAccount();
        String lockKey = SystemConstant.REDIS_LOCK_STUDENT_PREFIX + teStudent.getId();
        Boolean lock = redisUtil.lock(lockKey, SystemConstant.REDIS_CACHE_TIME_OUT);
        if (!lock) {
            throw new BusinessException(ExceptionResultEnum.REQUEST_AWAIT);
        }
        try {
            if (Objects.isNull(param.getRecordId()) || Objects.equals(param.getRecordId(), "")) {
                throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
            }
            ExamRecordCacheUtil.setClientCurrentIp(param.getRecordId(), IpUtil.getRemoteIp(ServletUtil.getRequest()));
            return ResultUtil.ok(teExamService.resume(teStudent.getId(), param.getRecordId()));
        } finally {
            redisUtil.releaseLock(lockKey);
        }
    }

    @ApiOperation(value = "结束考试")
    @RequestMapping(value = "/finish", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "试卷信息")})
    public Result finish(@RequestBody FinishParamBean param) {
        TEStudentCacheDto teStudent = (TEStudentCacheDto) ServletUtil.getRequestStudentAccount();
        String lockKey = SystemConstant.REDIS_LOCK_STUDENT_PREFIX + teStudent.getId();
        Boolean lock = redisUtil.lock(lockKey, SystemConstant.REDIS_CACHE_TIME_OUT);
        if (!lock) {
            throw new BusinessException(ExceptionResultEnum.REQUEST_AWAIT);
        }
        try {
            if (Objects.isNull(param.getRecordId()) || Objects.equals(param.getRecordId(), "")) {
                throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
            }
            if (param.getType() == null) {
                throw new BusinessException(ExceptionResultEnum.FINISH_TYPE_IS_NULL);
            }
            if (param.getDurationSeconds() == null) {
                throw new BusinessException("总用时秒数不能为空");
            }
            ExamRecordCacheUtil.setClientCurrentIp(param.getRecordId(), IpUtil.getRemoteIp(ServletUtil.getRequest()));
            return ResultUtil.ok(teExamService
                    .finish(teStudent.getId(), param.getRecordId(), param.getType(), param.getDurationSeconds()));
        } finally {
            redisUtil.releaseLock(lockKey);
        }
    }

    @ApiOperation(value = "查询交卷结果")
    @RequestMapping(value = "/result", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "试卷信息")})
    public Result result(@RequestBody ResultParamBean param) {
        if (Objects.isNull(param.getRecordId()) || Objects.equals(param.getRecordId(), "")) {
            throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
        }
        ExamRecordStatusEnum examRecordStatusEnum = ExamRecordCacheUtil.getStatus(param.getRecordId());
        if (Objects.isNull(examRecordStatusEnum)) {
            TOeExamRecord tOeExamRecord = tOeExamRecordService.getById(param.getRecordId());
            examRecordStatusEnum = tOeExamRecord.getStatus();
        }

        if (Objects.nonNull(examRecordStatusEnum) && (ExamRecordStatusEnum.FINISHED == examRecordStatusEnum ||
                ExamRecordStatusEnum.PERSISTED == examRecordStatusEnum || ExamRecordStatusEnum.JUNK == examRecordStatusEnum)) {
            throw new BusinessException(ExceptionResultEnum.EXAM_FINISH);
        }
        if (Objects.nonNull(examRecordStatusEnum) && (
                !Objects.equals(ExamRecordStatusEnum.FIRST_PREPARE, examRecordStatusEnum) && !Objects
                        .equals(ExamRecordStatusEnum.RESUME_PREPARE, examRecordStatusEnum))) {
            throw new BusinessException(ExceptionResultEnum.EXAM_STATUS_ERROR);
        }
        ExamRecordCacheUtil.setClientCurrentIp(param.getRecordId(), IpUtil.getRemoteIp(ServletUtil.getRequest()));
        return ResultUtil.ok(teExamService.result(param.getRecordId()));
    }

    @ApiOperation(value = "获取试卷下载信息")
    @RequestMapping(value = "/paper/download", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "试卷信息")})
    public Result paperDownload(@RequestBody ResultParamBean param) throws IOException {
        if (Objects.isNull(param.getRecordId()) || Objects.equals(param.getRecordId(), "")) {
            throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
        }
        ExamRecordStatusEnum examRecordStatusEnum = ExamRecordCacheUtil.getStatus(param.getRecordId());
        if (Objects.nonNull(examRecordStatusEnum) && (ExamRecordStatusEnum.FINISHED == examRecordStatusEnum ||
                ExamRecordStatusEnum.PERSISTED == examRecordStatusEnum || ExamRecordStatusEnum.JUNK == examRecordStatusEnum)) {
            throw new BusinessException(ExceptionResultEnum.EXAM_FINISH);
        }

        if (Objects.nonNull(examRecordStatusEnum) && (
                !Objects.equals(ExamRecordStatusEnum.FIRST_PREPARE, examRecordStatusEnum) && !Objects
                        .equals(ExamRecordStatusEnum.RESUME_PREPARE, examRecordStatusEnum))) {
            throw new BusinessException(ExceptionResultEnum.EXAM_STATUS_ERROR);
        }
        ExamRecordCacheUtil.setClientCurrentIp(param.getRecordId(), IpUtil.getRemoteIp(ServletUtil.getRequest()));
        return ResultUtil.ok(teExamService.paperDownload(param.getRecordId()));
    }

    @ApiOperation(value = "试卷下载成功通知")
    @RequestMapping(value = "/paper/downloaded", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "试卷信息")})
    public Result paperDownloaded(@RequestBody ResultParamBean param) {
        if (Objects.isNull(param.getRecordId()) || Objects.equals(param.getRecordId(), "")) {
            throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
        }
        ExamRecordStatusEnum examRecordStatusEnum = ExamRecordCacheUtil.getStatus(param.getRecordId());
        if (Objects.nonNull(examRecordStatusEnum) && (ExamRecordStatusEnum.FINISHED == examRecordStatusEnum ||
                ExamRecordStatusEnum.PERSISTED == examRecordStatusEnum || ExamRecordStatusEnum.JUNK == examRecordStatusEnum)) {
            throw new BusinessException(ExceptionResultEnum.EXAM_FINISH);
        }

        if (Objects.nonNull(examRecordStatusEnum) && (
                !Objects.equals(ExamRecordStatusEnum.FIRST_PREPARE, examRecordStatusEnum) && !Objects
                        .equals(ExamRecordStatusEnum.RESUME_PREPARE, examRecordStatusEnum))) {
            throw new BusinessException(ExceptionResultEnum.EXAM_STATUS_ERROR);
        }
        Integer paperDownload = Objects.isNull(ExamRecordCacheUtil.getPaperDownload(param.getRecordId())) ?
                1 :
                ExamRecordCacheUtil.getPaperDownload(param.getRecordId());
        if (paperDownload.intValue() == 1) {
            ExamRecordCacheUtil.setPaperDownload(param.getRecordId(), 0);
            tOeExamRecordService.sendExamRecordDataSaveMq(param.getRecordId(), System.currentTimeMillis());
        }
        ExamRecordCacheUtil.setClientCurrentIp(param.getRecordId(), IpUtil.getRemoteIp(ServletUtil.getRequest()));
        return ResultUtil.ok(Collections.singletonMap(SystemConstant.UPDATE_TIME, System.currentTimeMillis()));
    }

    @ApiOperation(value = "查询考试状态")
    @RequestMapping(value = "/status", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "试卷信息")})
    public Result status(@RequestBody ResultParamBean param) {
        if (Objects.isNull(param)) {
            throw new BusinessException(ExceptionResultEnum.PARAMS_ILLEGALITY);
        }
        if (Objects.isNull(param.getRecordId())) {
            throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
        }
        ExamRecordStatusEnum examRecordStatusEnum = ExamRecordCacheUtil.getStatus(param.getRecordId());
        if (Objects.isNull(examRecordStatusEnum)) {
            examRecordStatusEnum = Objects.isNull(examRecordStatusEnum) ? SystemConstant.getExamStatus(param.getRecordId()) : examRecordStatusEnum;
        }
        ExamRecordCacheUtil.setClientCurrentIp(param.getRecordId(), IpUtil.getRemoteIp(ServletUtil.getRequest()));
        return ResultUtil.ok(Collections.singletonMap(SystemConstant.STATUS, examRecordStatusEnum));
    }
}