package com.ruoyi.hezhi.api.kaoshi;

import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.annotation.RateLimiter;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.hezhi.domain.*;
import com.ruoyi.hezhi.domain.dto.*;
import com.ruoyi.hezhi.mapper.TbExamSimulateInfoMapper;
import com.ruoyi.hezhi.mapper.TbExamSubjectAnswerMapper;
import com.ruoyi.hezhi.service.*;
import io.swagger.annotations.Api;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Author: LCL
 * @Date: 2024/10/08
 * @Description:通用API
 */
@Api("考试")
@RestController
@RequestMapping("/api/exam")
public class ApiExamController {

    @Resource
    private ITbExamRegistrationService examRegistrationService;
    @Resource
    private ITbSubjectWarehouseClassService subjectWarehouseClassService;
    @Resource
    private ITbExamSubjectService examSubjectService;
    @Resource
    private ITbMemberSubjectAllService memberSubjectAllService;
    @Resource
    private ITbMemberSubjectCollectService memberSubjectCollectService;
    @Resource
    private ITbExamSubjectSimulateService examSubjectSimulateService;
    @Resource
    private ITbExamSimulateInfoService examSimulateInfoService;;
    @Resource
    private ITbMemberExamSimulateAllService memberExamSimulateAllService;
    @Resource
    private ITbExamService examService;
    @Resource
    private ITbExamSubjectFormalService examSubjectFormalService;
    @Resource
    private ITbExamFileService examFileService;
    @Resource
    private TbExamSubjectAnswerMapper examSubjectAnswerMapper;
    @Resource
    private TbExamSimulateInfoMapper tbExamSimulateInfoMapper;
    @Resource
    private ITbSubjectWarehouseClassService tbSubjectWarehouseClassService;
    @Resource
    private ITbExamBatchService tbExamBatchService;


    /**
     * 题库列表
     *
     * @param params searchValue 搜索词
     * @return success
     */
    @GetMapping("/getSubjectWarehouseClassList")
    public AjaxResult getSubjectWarehouseClassList(@RequestParam Map<String, Object> params) {
        try {
            return AjaxResult.success().put("data", subjectWarehouseClassService.getSubjectWarehouseClassList(params));
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("题库列表异常");
        }
    }

    /**
     * 考试报名
     *
     * @param examRegistrationDTO
     * @return ok
     */
    @RepeatSubmit
    @RateLimiter(key = "API_examRegistration", time = 5, count = 50)
    @PostMapping("/examRegistration")
    public AjaxResult examRegistration(@RequestBody @Validated({ExamRegistrationDTO.examRegistration.class}) ExamRegistrationDTO examRegistrationDTO, BindingResult bindingResult) {
        // 参数校验
        if (bindingResult.hasErrors()) {
            return AjaxResult.allParameterErrors(bindingResult);
        }
        try {
            return examRegistrationService.examRegistration(examRegistrationDTO);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("考试报名异常");
        }
    }

    /**
     * 查询考试报名详情
     *
     * @param params memberUserId 用户ID
     *               examId 考试ID
     * @return ok
     */
    @GetMapping("/getExamRegistrationInfo")
    public AjaxResult getExamRegistrationInfo(@RequestParam Map<String, Object> params) {
        try {
            return AjaxResult.success().put("data", examRegistrationService.getExamRegistrationInfo(params));
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("查询考试报名详情异常");
        }
    }


    /**
     * 练习统计
     *
     * @param params memberUserId 用户ID
     *               majorId 专业ID
     *               subjectWarehouseClassId 题库分类ID
     *               subjectType 题目类型（1-单选，2-多选，3-判断，4-论述）
     *               practiceType 练习类型（1-顺序练习，2-专项练习，3-章节练习，4-随机练习）
     * @return success
     */
    @GetMapping("/getPracticeStatistics")
    public AjaxResult getPracticeStatistics(@RequestParam Map<String, Object> params) {
        try {
            // 做对数
            String statisticsTrue = "0";
            // 做对比例
            String statisticsTrueRate = "0";
            // 做错数
            String statisticsFalse = "0";
            // 做错比例
            String statisticsFalseRate = "0";
            // 未做数
            String statisticsUn = "0";
            // 未做比例
            String statisticsUnRate = "100";

            // 正确率
            String accuracyRate = "0";

            // 做过的题目
            String doneNum = "0";

            // 查询所有题目
            List<Map<String, Object>> list = examSubjectService.queryByParam(params);
            // 题目总数
            int allNum = list.size();
            statisticsUn = String.valueOf(allNum);

            if (params.containsKey("memberUserId") && StringUtils.isNotBlank(params.get("memberUserId").toString()) && allNum > 0) {
                // 正确题数， 当前题目编号
                params.put("status", 1);
                int countTrue = memberSubjectAllService.memberSubjectAllCount(params);
                statisticsTrue = String.valueOf(countTrue);
                statisticsTrueRate = String.valueOf(new BigDecimal(countTrue).divide(new BigDecimal(allNum), 2, RoundingMode.HALF_UP).multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN));

                // 错误题数， 当前题目编号
                params.put("status", 2);
                int countFalse = memberSubjectAllService.memberSubjectAllCount(params);
                statisticsFalse = String.valueOf(countFalse);
                statisticsFalseRate = String.valueOf(new BigDecimal(countFalse).divide(new BigDecimal(allNum), 2, RoundingMode.HALF_UP).multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN));
                // 未做题目
                int unNum = allNum - countTrue - countFalse;
                // 已做题目
                doneNum = String.valueOf(countTrue + countFalse);

                if (unNum >= 0) {
                    statisticsUn = String.valueOf(unNum);
                    statisticsUnRate = String.valueOf(new BigDecimal(statisticsUn).divide(new BigDecimal(allNum), 2, RoundingMode.HALF_UP).multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN));
                }

                if (params.containsKey("practiceType") && StringUtils.isNotBlank(params.get("practiceType").toString()) &&
                        params.containsKey("subjectWarehouseClassId") && StringUtils.isNotBlank(params.get("subjectWarehouseClassId").toString())
                ) {
                    TbMemberSubjectAll subjectAll = new TbMemberSubjectAll();
                    subjectAll.setPracticeType(Integer.parseInt(params.get("practiceType").toString()));
                    subjectAll.setMemberUserId(Long.parseLong(params.get("memberUserId").toString()));
                    subjectAll.setSubjectWarehouseClassId(Long.parseLong(params.get("subjectWarehouseClassId").toString()));
                    List<TbMemberSubjectAll> allList = memberSubjectAllService.selectMemberSubjectAllList(subjectAll);
                    int completeNum = allList.size();
                    if (completeNum > 0 && countTrue > 0) {
                        accuracyRate = String.valueOf(new BigDecimal(countTrue).divide(new BigDecimal(completeNum), 2, RoundingMode.HALF_UP).multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN));
                    }
                }

            }

            HashMap<Object, Object> map = new HashMap<>();
            map.put("statisticsTrue", statisticsTrue);
            map.put("statisticsTrueRate", statisticsTrueRate);
            map.put("statisticsFalse", statisticsFalse);
            map.put("statisticsFalseRate", statisticsFalseRate);
            map.put("statisticsUn", statisticsUn);
            map.put("statisticsUnRate", statisticsUnRate);
            map.put("accuracyRate", accuracyRate);
            map.put("doneNum", doneNum);
            map.put("allNum", allNum);
            return AjaxResult.success().put("data", map);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error(e.getMessage());
        }
    }

    /**
     * 题目序号列表
     *
     * @param params memberUserId 用户ID
     *               majorId 专业ID
     *               subjectWarehouseClassId 题库分类ID
     *               subjectType 题目类型（1-单选，2-多选，3-判断，4-论述）
     *               practiceType 练习类型（1-顺序练习，2-专项练习，3-章节练习，4-随机练习）
     *               searchValue 搜索词
     * @return success
     */
    @GetMapping("/getExamSubjectList")
    public AjaxResult getExamSubjectList(@RequestParam Map<String, Object> params) {
        if (!params.containsKey("memberUserId") || StringUtils.isBlank(params.get("memberUserId").toString())) {
            return AjaxResult.error("请先登录");
        }
        if (!params.containsKey("practiceType") || StringUtils.isBlank(params.get("practiceType").toString())) {
            return AjaxResult.error("缺少 practiceType 练习类型");
        }
        if (!params.containsKey("courseId") || StringUtils.isBlank(params.get("courseId").toString())) {
            return AjaxResult.error("缺少 courseId 课程");
        }
        try {
            // 查询所有题目
            List<Map<String, Object>> list = examSubjectService.queryByParam(params);
            // 题目总数
            int allNum = list.size();
            // 错误题数，正确题数， 当前题目编号
            params.put("status", 1);
            int countTrue = memberSubjectAllService.memberSubjectAllCount(params);
            params.put("status", 2);
            int countFalse = memberSubjectAllService.memberSubjectAllCount(params);

            int countNow = 1;
            params.remove("status");
            TbMemberSubjectAll memberSubjectAll = memberSubjectAllService.queryMemberSubjectAllByParam(params);

            // 做过的题目数
            int completeNum = 0;
            if (memberSubjectAll == null) {

            } else {
                // int location = memberSubjectAll.getLocation();
                //初始化数组
                List<Integer> nums = new ArrayList<Integer>();
                TbMemberSubjectAll subjectAll = new TbMemberSubjectAll();
                subjectAll.setPracticeType(Integer.parseInt(params.get("practiceType").toString()));
                subjectAll.setMemberUserId(Long.parseLong(params.get("memberUserId").toString()));
                subjectAll.setSubjectWarehouseClassId(Long.parseLong(params.get("subjectWarehouseClassId").toString()));
                List<TbMemberSubjectAll> allList = memberSubjectAllService.selectMemberSubjectAllList(subjectAll);
                completeNum = allList.size();

                for (TbMemberSubjectAll MSA : allList) {
                    nums.add(MSA.getLocation().intValue());
                }
                // 设置最大值
                int location = Collections.max(nums);
                if (location == allNum) {
                    countNow = location;
                } else {
                    countNow = location + 1;
                }

            }
            params.clear();
            params.put("allNum", allNum);
            params.put("countTrue", countTrue);
            params.put("countFalse", countFalse);
            params.put("countNow", countNow);
            if (allNum < 1 || completeNum < 1 || countTrue < 1) {
                params.put("accuracyRate", "0");
            } else {
                BigDecimal accuracyRate = new BigDecimal(countTrue).divide(new BigDecimal(completeNum), 2, RoundingMode.HALF_UP).multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN);
                params.put("accuracyRate", accuracyRate + "");
            }

            if (list.size() > 0) {
                for (Map<String, Object> objectMap : list) {
                    long examSubjectId = Long.parseLong(objectMap.get("examSubjectId").toString());
                    // 查询答案列表
                    objectMap.put("subjectAnswerList", examSubjectAnswerMapper.selectAnswerList(examSubjectId, null));
                }
            }

            params.put("list", list);
            return AjaxResult.success().put("data", params);
        } catch (Exception e) {
            return AjaxResult.error("题目序号列表异常");
        }
    }

    /**
     * 题目详情
     *
     * @param params examSubjectId 题目ID
     *               memberUserId 用户ID
     *               practiceType 练习类型（1-顺序练习，2-专项练习，3-章节练习，4-随机练习，5-模拟考试，6-考试）
     *               answerShow 是否返回答案（0-不返，1-返）
     * @return success
     */
    @GetMapping("/getExamSubjectInfo")
    public AjaxResult getExamSubjectInfo(@RequestParam Map<String, Object> params) {
        if (!params.containsKey("examSubjectId") || StringUtils.isBlank(params.get("examSubjectId").toString())) {
            return AjaxResult.error("缺少 examSubjectId 题目ID");
        }
        try {
            return AjaxResult.success().put("data", examSubjectService.getExamSubjectInfo(params));
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("题库详情异常");
        }
    }

    /**
     * 收藏或取消收藏题目
     *
     * @param memberSubjectCollectDTO
     * @return ok
     */
    @RepeatSubmit
    @RateLimiter(key = "API_subjectCollectOrCancelCollect", time = 5, count = 50)
    @PostMapping("/subjectCollectOrCancelCollect")
    public AjaxResult subjectCollectOrCancelCollect(@RequestBody @Validated({MemberSubjectCollectDTO.subjectCollectOrCancelCollect.class}) MemberSubjectCollectDTO memberSubjectCollectDTO, BindingResult bindingResult) {
        // 参数校验
        if (bindingResult.hasErrors()) {
            return AjaxResult.allParameterErrors(bindingResult);
        }
        try {
            return memberSubjectCollectService.subjectCollectOrCancelCollect(memberSubjectCollectDTO);
//            return AjaxResult.success();
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("收藏或取消收藏题目异常");
        }
    }

    /**
     * 专项练习（考试标题）
     * *
     * @param params majorId 专业ID
     * @return success
     */
    @GetMapping("/getSpecialPracticeList")
    public AjaxResult getSpecialPracticeList(@RequestParam Map<String,Object> params) {
        try {
            return AjaxResult.success().put("data", examSubjectService.getSpecialPracticeList(params));
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("专项练习（考试标题）异常");
        }
    }

    /**
     * 题目数量
     * *
     * @param params majorId 专业ID
     * @return success
     */
    @GetMapping("/getPracticeListCount")
    public AjaxResult getPracticeListCount(@RequestParam Map<String,Object> params) {
        try {
            return AjaxResult.success().put("data", examSubjectService.getPracticeListCount(params));
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("专项练习（考试标题）异常");
        }
    }

    /**
     * 章节练习（考试标题）
     *
     * @return success
     */
    @GetMapping("/getMajorPracticeList")
    public AjaxResult getMajorPracticeList() {
        try {
            return AjaxResult.success().put("data", examSubjectService.getMajorPracticeList());
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("章节练习（考试标题）异常");
        }
    }

    /**
     * 练习答题
     *
     * @param memberSubjectAllDTO
     * @return ok
     */
    @RepeatSubmit
    @RateLimiter(key = "API_subjectPracticeAnswer", time = 5, count = 50)
    @PostMapping("/subjectPracticeAnswer")
    public AjaxResult subjectPracticeAnswer(@RequestBody @Validated({MemberSubjectAllDTO.subjectPracticeAnswer.class}) MemberSubjectAllDTO memberSubjectAllDTO, BindingResult bindingResult) {
        // 参数校验
        if (bindingResult.hasErrors()) {
            return AjaxResult.allParameterErrors(bindingResult);
        }
        try {
            return memberSubjectAllService.subjectPracticeAnswer(memberSubjectAllDTO);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("练习答题异常");
        }
    }

    /**
     * 练习答题清空
     *
     * @param memberSubjectAllDTO
     * @return ok
     */
//    @RepeatSubmit
//    @RateLimiter(key = "API_subjectPracticeAnswerClear", time = 5, count = 50)
    @PostMapping("/subjectPracticeAnswerClear")
    public AjaxResult subjectPracticeAnswerClear(@RequestBody @Validated({MemberSubjectAllDTO.subjectPracticeAnswer.class}) MemberSubjectAllDTO memberSubjectAllDTO, BindingResult bindingResult) {
        try {
            return memberSubjectAllService.subjectPracticeAnswerClear(memberSubjectAllDTO);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("练习答题异常");
        }
    }

    /**
     * 模拟考试上次考试状态
     *
     * @param params memberUserId 用户ID
     *               subjectWarehouseClassId 题库分类ID
     * @return success
     */
    @GetMapping("/getSimulateSubjectUp")
    public AjaxResult getSimulateSubjectUp(@RequestParam Map<String, Object> params) {
        if (!params.containsKey("memberUserId") || StringUtils.isBlank(params.get("memberUserId").toString())) {
            return AjaxResult.error("请先登录");
        }
        if (!params.containsKey("subjectWarehouseClassId") || StringUtils.isBlank(params.get("subjectWarehouseClassId").toString())) {
            return AjaxResult.error("缺少 subjectWarehouseClassId 题库分类ID");
        }
        try {
            return AjaxResult.success().put("data", tbExamSimulateInfoMapper.getSimulateSubjectUp(params));
        } catch (Exception e) {
            return AjaxResult.error("模拟考试上次考试状态异常");
        }
    }

    /**
     * 模拟考试题目序号列表
     *
     * @param params memberUserId 用户ID
     *               subjectWarehouseClassId 题库分类ID
     *               searchValue 搜索词
     * @return success
     */
    @GetMapping("/getSimulateSubjectList")
    public AjaxResult getSimulateSubjectList(@RequestParam Map<String, Object> params) {
        if (!params.containsKey("memberUserId") || StringUtils.isBlank(params.get("memberUserId").toString())) {
            return AjaxResult.error("请先登录");
        }
        if (!params.containsKey("courseId") || StringUtils.isBlank(params.get("courseId").toString())) {
            return AjaxResult.error("缺少 courseId 课程ID");
        }
        try {
            long courseId = Long.parseLong(params.get("courseId").toString());
            TbSubjectWarehouseClass subjectWarehouseClass = subjectWarehouseClassService.getSubjectWarehouseClass(courseId);
            if (subjectWarehouseClass == null || subjectWarehouseClass.getSimulationStatus() == 0) {
                return AjaxResult.error("模拟考试暂未开放");
            }
            params.put("subjectWarehouseClassId", subjectWarehouseClass.getSubjectWarehouseClassId());
            // 模拟考试考生信息
            Map<String, Object> simulateInfo = examSimulateInfoService.getSimulateSubjectAllInfo(params);

            // 查询所有题目
            params.put("examSimulateInfoId", Long.parseLong(simulateInfo.get("examSimulateInfoId").toString()));
            List<Map<String, Object>> list = examSubjectSimulateService.getAllTbExamSubjectSimulate(params);
            if (list == null || list.isEmpty()) {
                return AjaxResult.error("模拟考试暂未开放");
            }
            // 题目总数
            int allNum = list.size();

            Integer examStatus = 0;
            Integer passStatus = 0;
            BigDecimal completeScore = new BigDecimal(0);

            TbExamSimulateInfo simulateInfoId = tbExamSimulateInfoMapper.selectTbExamSimulateInfoByExamSimulateInfoIdRetain(Long.parseLong(simulateInfo.get("examSimulateInfoId").toString()));
            if (simulateInfoId != null) {
                examStatus = simulateInfoId.getExamStatus();
                passStatus = simulateInfoId.getPassStatus();
                completeScore = simulateInfoId.getCompleteScore();
            }

            HashMap<String, Object> map = new HashMap<>();
            map.put("allNum", allNum);
            map.put("simulateInfo", simulateInfo);
            map.put("list", list);

            map.put("examStatus", examStatus);// 考试状态（0-未开始，1-进行中，2-已结束）
            map.put("passStatus", passStatus);// 通过状态（0-无，1-通过，2-未通过）
            map.put("completeScore", completeScore);// 得分

            return AjaxResult.success().put("data", map);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error(e.getMessage());
        }
    }

    /**
     * 模拟考试答题
     *
     * @param memberExamSimulateAllDTO
     * @return ok
     */
    @RepeatSubmit
    @RateLimiter(key = "API_subjectSimulateAnswer", time = 5, count = 50)
    @PostMapping("/subjectSimulateAnswer")
    public AjaxResult subjectSimulateAnswer(@RequestBody @Validated({MemberExamSimulateAllDTO.subjectSimulateAnswer.class}) MemberExamSimulateAllDTO memberExamSimulateAllDTO, BindingResult bindingResult) {
        // 参数校验
        if (bindingResult.hasErrors()) {
            return AjaxResult.allParameterErrors(bindingResult);
        }
        try {
            return memberExamSimulateAllService.subjectSimulateAnswer(memberExamSimulateAllDTO);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("模拟考试答题异常");
        }
    }

    /**
     * 模拟考试做题反馈列表
     *
     * @param params memberUserId 用户ID
     *               subjectWarehouseClassId 题库分类ID
     *               examSimulateInfoId 考试、模拟考试考生详情ID
     *               searchValue 搜索词
     * @return success
     */
    @GetMapping("/getSimulateSubjectFeedbackList")
    public AjaxResult getSimulateSubjectFeedbackList(@RequestParam Map<String, Object> params) {
        if (!params.containsKey("memberUserId") || StringUtils.isBlank(params.get("memberUserId").toString())) {
            return AjaxResult.error("请先登录");
        }
        if (!params.containsKey("courseId") || StringUtils.isBlank(params.get("courseId").toString())) {
            return AjaxResult.error("缺少 courseId 课程ID");
        }
        if (!params.containsKey("examSimulateInfoId") || StringUtils.isBlank(params.get("examSimulateInfoId").toString())) {
            return AjaxResult.error("缺少 examSimulateInfoId 考试、模拟考试考生详情ID");
        }
        try {
            List<Map<String, Object>> allTbExamSubjectSimulate = examSubjectSimulateService.getAllTbExamSubjectSimulate(params);
            return AjaxResult.success().put("data", allTbExamSubjectSimulate);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("模拟考试做题反馈列表异常");
        }
    }

    /**
     * 模拟考试交卷
     *
     * @param memberExamSimulateAllDTO
     * @return ok
     */
    @RepeatSubmit
    @RateLimiter(key = "API_subjectSimulateSubmit", time = 5, count = 50)
    @PostMapping("/subjectSimulateSubmit")
    public AjaxResult subjectSimulateSubmit(@RequestBody @Validated({MemberExamSimulateAllDTO.subjectSimulateSubmit.class}) MemberExamSimulateAllDTO memberExamSimulateAllDTO, BindingResult bindingResult) {
        // 参数校验
        if (bindingResult.hasErrors()) {
            return AjaxResult.allParameterErrors(bindingResult);
        }
        try {
            return examSimulateInfoService.subjectExamSubmit(memberExamSimulateAllDTO);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("模拟考试交卷异常");
        }
    }

    /**
     * 正式考试考生信息、提示信息
     *
     * @param params memberUserId 用户ID
     *               examId 考试ID
     *               searchValue 搜索词
     * @return success
     */
    @GetMapping("/getExamSubjectFormalInfo")
    public AjaxResult getExamSubjectFormalInfo(@RequestParam Map<String, Object> params) {
        if (!params.containsKey("memberUserId") || StringUtils.isBlank(params.get("memberUserId").toString())) {
            return AjaxResult.error("请先登录");
        }
        if (!params.containsKey("examId") || StringUtils.isBlank(params.get("examId").toString())) {
            return AjaxResult.error("缺少 examId 考试ID");
        }
        try {
            long memberUserId = Long.parseLong(params.get("memberUserId").toString());
            long examId = Long.parseLong(params.get("examId").toString());

            TbExamRegistration examRegistration = examRegistrationService.selectTbExamRegistrationByUserIdExamId(memberUserId, examId);
            if (examRegistration == null) {
                return AjaxResult.error("请先报名！！！");
            }
            TbExam exam = examService.selectTbExamByExamId(examId);
            if (exam == null) {
                return AjaxResult.error("考试信息异常，请联系管理员！！！");
            } else {
                TbExamBatch tbExamBatch = tbExamBatchService.getByExamIdBatchIndex(exam.getExamId(), examRegistration.getExamBatchIndex());
                Date examStartTime = tbExamBatch.getExamStartTime();
                Date examEndTime = tbExamBatch.getExamEndTime();
                // 获取当前时间
                Date currentTime = new Date();

                // 比较时间
                if (currentTime.after(examEndTime)) {
                    return AjaxResult.error("考试时间【" + DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", tbExamBatch.getExamStartTime()) + "至" + DateUtils.parseDateToStr("", tbExamBatch.getExamEndTime()) + "】，考试已结束");
                }
                if (currentTime.before(examStartTime)) {
                    return AjaxResult.error("考试时间【" + DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", tbExamBatch.getExamStartTime()) + "至" + DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", tbExamBatch.getExamEndTime()) + "】，考试未开始");
                }
            }
            // 正式考试考生及考试信息
            Map<String, Object> simulateInfo = examSimulateInfoService.getFormalSubjectAllInfo(params);

            return AjaxResult.success(simulateInfo);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("正式考试考生信息、提示信息异常");
        }
    }

    /**
     * 正式考试题目序号列表（点开始答题）
     *
     * @param params memberUserId 用户ID
     *               examId 考试ID
     *               isAgain 是否补考：0-否，1-是
     *               examSimulateInfoId 考试考生详情ID
     * @return success
     */
    @GetMapping("/getExamSubjectFormalList")
    public AjaxResult getExamSubjectFormalList(@RequestParam Map<String, Object> params) {
        if (!params.containsKey("memberUserId") || StringUtils.isBlank(params.get("memberUserId").toString())) {
            return AjaxResult.error("请先登录");
        }
        if (!params.containsKey("examId") || StringUtils.isBlank(params.get("examId").toString())) {
            return AjaxResult.error("缺少 examId 考试ID");
        }
        // if (!params.containsKey("isAgain") || StringUtils.isBlank(params.get("isAgain").toString())) {
        //     return AjaxResult.error("缺少 isAgain 是否补考");
        // }
        if (!params.containsKey("examSimulateInfoId") || StringUtils.isBlank(params.get("examSimulateInfoId").toString())) {
            return AjaxResult.error("缺少 examSimulateInfoId 考试考生详情ID");
        }
        Long memberUserId = MapUtils.getLong(params, "memberUserId");
        Long examId = MapUtils.getLong(params, "examId");
        try {
            TbExam exam = examService.selectTbExamByExamId(Long.parseLong(params.get("examId").toString()));
            if (ObjectUtils.isEmpty(exam)) {
                return AjaxResult.error("考试信息异常，请联系管理员！！！");
            }

            TbExamRegistration examRegistration = examRegistrationService.selectTbExamRegistrationByUserIdExamId(memberUserId, examId);
            TbExamBatch tbExamBatch = tbExamBatchService.getByExamIdBatchIndex(exam.getExamId(), examRegistration.getExamBatchIndex());

            Date examStartTime = tbExamBatch.getExamStartTime();
            Date examEndTime = tbExamBatch.getExamEndTime();
            // 获取当前时间
            Date currentTime = new Date();

            // 比较时间
            if (currentTime.after(examEndTime)) {
                return AjaxResult.error("考试时间【" + DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", tbExamBatch.getExamStartTime()) + "至" + DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", tbExamBatch.getExamEndTime()) + "】，考试已结束");
            }
            if (examStartTime.after(currentTime)) {
                return AjaxResult.error("考试时间【" + DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", tbExamBatch.getExamStartTime()) + "至" + DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", tbExamBatch.getExamEndTime()) + "】，考试未开始");
            }

            // 查询所有题目
            List<Map<String, Object>> list = examSubjectFormalService.getAllTbExamSubjectFormal(params);
            if (list == null || list.isEmpty()) {
                return AjaxResult.error("考试暂未开放");
            }
            // 题目总数
            int allNum = list.size();

            HashMap<String, Object> map = new HashMap<>();
            map.put("allNum", allNum);
            map.put("list", list);

            return AjaxResult.success().put("data", map);
        } catch (Exception e) {
            return AjaxResult.error("正式考试题目序号列表（点开始答题）异常");
        }
    }

    /**
     * 正式考试做题反馈列表
     *
     * @param params memberUserId 用户ID
     *               examId 考试ID
     *               isAgain 是否补考：0-否，1-是
     *               examSimulateInfoId 考试考生详情ID
     * @return success
     */
    @GetMapping("/getExamSubjectFormalFeedbackList")
    public AjaxResult getExamSubjectFormalFeedbackList(@RequestParam Map<String, Object> params) {
        if (!params.containsKey("memberUserId") || StringUtils.isBlank(params.get("memberUserId").toString())) {
            return AjaxResult.error("请先登录");
        }
        if (!params.containsKey("examId") || StringUtils.isBlank(params.get("examId").toString())) {
            return AjaxResult.error("缺少 examId 考试ID");
        }
        // if (!params.containsKey("isAgain") || StringUtils.isBlank(params.get("isAgain").toString())) {
        //     return AjaxResult.error("缺少 isAgain 是否补考");
        // }
        if (!params.containsKey("examSimulateInfoId") || StringUtils.isBlank(params.get("examSimulateInfoId").toString())) {
            return AjaxResult.error("缺少 examSimulateInfoId 考试考生详情ID");
        }
        try {
            return AjaxResult.success().put("data", examSubjectFormalService.getAllTbExamSubjectFormal(params));
        } catch (Exception e) {
            return AjaxResult.error("正式考试做题反馈列表异常");
        }
    }

    /**
     * 正式考试点击确定开始答题
     *
     * @param memberExamSimulateAllDTO
     * @return ok
     */
    @RepeatSubmit
    @RateLimiter(key = "API_subjectFormalClickOK", time = 5, count = 50)
    @PostMapping("/subjectFormalClickOK")
    public AjaxResult subjectFormalClickOK(@RequestBody @Validated({MemberExamSimulateAllDTO.subjectFormalClickOK.class}) MemberExamSimulateAllDTO memberExamSimulateAllDTO, BindingResult bindingResult) {
        // 参数校验
        if (bindingResult.hasErrors()) {
            return AjaxResult.allParameterErrors(bindingResult);
        }
        try {
            return memberExamSimulateAllService.subjectFormalClickOK(memberExamSimulateAllDTO);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("正式考试点击确定开始答题异常");
        }
    }

    /**
     * 正式考试答题
     *
     * @param memberExamSimulateAllDTO
     * @return ok
     */
    @RateLimiter(key = "API_subjectFormalAnswer", time = 5, count = 50)
    @PostMapping("/subjectFormalAnswer")
    public AjaxResult subjectFormalAnswer(@RequestBody @Validated({MemberExamSimulateAllDTO.subjectFormalAnswer.class}) MemberExamSimulateAllDTO memberExamSimulateAllDTO, BindingResult bindingResult) {
        // 参数校验
        if (bindingResult.hasErrors()) {
            return AjaxResult.allParameterErrors(bindingResult);
        }
        try {
            return memberExamSimulateAllService.subjectFormalAnswer(memberExamSimulateAllDTO);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("正式考试答题异常");
        }
    }

    /**
     * 正式考试交卷
     *
     * @param memberExamSimulateAllDTO
     * @return ok
     */
    @RepeatSubmit
    @RateLimiter(key = "API_subjectFormalSubmit", time = 5, count = 50)
    @PostMapping("/subjectFormalSubmit")
    public AjaxResult subjectFormalSubmit(@RequestBody @Validated({MemberExamSimulateAllDTO.subjectFormalSubmit.class}) MemberExamSimulateAllDTO memberExamSimulateAllDTO, BindingResult bindingResult) {
        // 参数校验
        if (bindingResult.hasErrors()) {
            return AjaxResult.allParameterErrors(bindingResult);
        }
        try {
            return examSimulateInfoService.subjectExamSubmit(memberExamSimulateAllDTO);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("正式考试交卷异常");
        }
    }

    /**
     * 正式考试补考
     *
     * @param memberExamSimulateAllDTO
     * @return ok
     */
    @RepeatSubmit
    @RateLimiter(key = "API_subjectFormalAgain", time = 5, count = 50)
    @PostMapping("/subjectFormalAgain")
    public AjaxResult subjectFormalAgain(@RequestBody @Validated({MemberExamSimulateAllDTO.subjectFormalAgain.class}) MemberExamSimulateAllDTO memberExamSimulateAllDTO, BindingResult bindingResult) {
        // 参数校验
        if (bindingResult.hasErrors()) {
            return AjaxResult.allParameterErrors(bindingResult);
        }
        try {
            return examSimulateInfoService.subjectFormalAgain(memberExamSimulateAllDTO);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("正式考试补考异常");
        }
    }

    /**
     * 正式考试拍摄
     *
     * @param examFileDTO
     * @return ok
     */
    @RepeatSubmit
    @RateLimiter(key = "API_subjectFormalPhotograph", time = 5, count = 50)
    @PostMapping("/subjectFormalPhotograph")
    public AjaxResult subjectFormalPhotograph(@RequestBody @Validated({ExamFileDTO.subjectFormalAgain.class}) ExamFileDTO examFileDTO, BindingResult bindingResult) {
        // 参数校验
        if (bindingResult.hasErrors()) {
            return AjaxResult.allParameterErrors(bindingResult);
        }
        try {
            return examFileService.subjectFormalPhotograph(examFileDTO);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("正式考试拍摄异常");
        }
    }

    /**
     * 报名考试即将开始弹窗列表
     *
     * @param params memberUserId 用户ID
     * @return success
     */
    @GetMapping("/getStartNowPopupList")
    public AjaxResult getStartNowPopupList(@RequestParam Map<String, Object> params) {
        try {
            return AjaxResult.success().put("data", examRegistrationService.getStartNowPopupList(params));
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("报名考试即将开始弹窗列表异常");
        }
    }

    /**
     * 错题本列表
     *
     * @param pageNum  页码
     * @param pageSize 每页数据量
     * @param params   type 通知类型（0-通知公告，1-专题专栏，2-政策解读，3-媒体聚焦，4-教育评论）
     *                 typeTwo 根据type二级类型（type=1：1-专题专栏1,2-专题专栏2,3-专题专栏3）
     *                 publisherType 0-总部学习中心通知，1-地方学习中心通知
     *                 searchValue 搜索词
     * @return success
     */
    // @GetMapping("/getNoticeList")
    // public AjaxResult getNoticeList(@RequestParam(value = "pageNum", defaultValue = "1", required = false) Integer pageNum,
    //                                 @RequestParam(value = "pageSize", defaultValue = "100", required = false) Integer pageSize,
    //                                 @RequestParam Map<String, Object> params) {
    //     try {
    //         PageHelper.startPage(pageNum, pageSize);
    //         List<Map<String, Object>> list = noticeService.getPCNoticeList(params);
    //         PageInfo<Map<String, Object>> pageInfo = new PageInfo(list);
    //         return AjaxResult.success().put("data", pageInfo);
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //         return AjaxResult.error("错题本列表异常");
    //     }
    // }

    /**
     * 获取考试报名表
     * @param type 1-准考证，4-证书，10-报名表，11-成绩单
     * @param memberUserId 用户ID
     * @param examRegistrationId 考试报名ID
     * @return 结果
     */
    @GetMapping("/getReportFormView")
    public AjaxResult getReportFormView(@RequestParam(required = false) Long type,
                                        @RequestParam(required = false) Long memberUserId,
                                        @RequestParam(required = false) Long examRegistrationId){
        if (null == type || null == memberUserId || null == examRegistrationId){
            throw new ServiceException("参数错误");
        }
        JSONObject reportFormView = examRegistrationService.getReportFormView(type, memberUserId, examRegistrationId);
        return AjaxResult.success(reportFormView);
    }

}
