/**
 * @Description : 这是一个REST控制器,处理与考试、问题和考试记录相关的HTTP请求,它包括创建、更新和检索考试和问题的方法,以及处理用户提交和评分。
 */
package lsgwr.exam.controller;

import lsgwr.exam.entity.Exam;
import lsgwr.exam.entity.ExamRecord;
import lsgwr.exam.service.ExamService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lsgwr.exam.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;

@RestController
@Api(tags = "Exam APIs")
//将此控制器中的所有端点映射到/api/exam URL路径
@RequestMapping("/api/exam")
public class ExamController {
    @Autowired //注入一个ExamService实例，用于处理与考试和问题相关的业务逻辑
    private ExamService examService;

    /**
     * @Description: 使用examService.getQuestionAll()获取数据,并将其包装在ResultVO对象中,用于获取所有考试列表
     * &#064;ApiOperation注解用于描述API操作,它将显示在SwaggerUI中
     */
    @GetMapping("/question/all")
    @ApiOperation("获取所有问题的列表")
   // 获取全部问题列表。
ResultVO<List<QuestionVo>> getQuestionAll() {
        // 定义返回值。
        ResultVO<List<QuestionVo>> resultVO;
        try {
            // 调用examService获取全部问题列表。
            List<QuestionVo> questionAll = examService.getQuestionAll();
            // 返回成功结果。
            resultVO = new ResultVO<>(0, "获取全部问题列表成功", questionAll);
        } catch (Exception e) {
            // 打印异常信息。
            e.printStackTrace();
            // 返回失败结果。
            resultVO = new ResultVO<>(-1, "获取全部问题列表失败", null);
        }
        // 返回结果。
        return resultVO;
    }

    @PostMapping("/question/update")
    @ApiOperation("更新问题")
    ResultVO<QuestionVo> questionUpdate(@RequestBody QuestionVo questionVo) {
        // 完成问题的更新。
        System.out.println(questionVo);
        try {
            // 调用examService的updateQuestion方法，更新问题。
            QuestionVo questionVoResult = examService.updateQuestion(questionVo);
            // 返回更新成功的结果。
            return new ResultVO<>(0, "更新问题成功", questionVoResult);
        } catch (Exception e) {
            // 打印异常信息。
            e.printStackTrace();
            // 返回更新失败的结果。
            return new ResultVO<>(-1, "更新问题失败", null);
        }
    }

    /**
     * 创建问题
     * @Description: 从请求体中获取一个QuestionCreateSimplifyVo对象，将其属性复制到QuestionCreateVo，设置创建者的ID，并使用examService.questionCreate()创建问题。
     * @param questionCreateSimplifyVo 从请求体中获取的QuestionCreateSimplifyVo对象
     * @param request HttpServletRequest对象，用于获取当前用户的ID
     * @return ResultVO<String> 对象，包含操作结果信息
     */
    @PostMapping("/question/create")
    @ApiOperation("创建问题")
    ResultVO<String> questionCreate(@RequestBody QuestionCreateSimplifyVo questionCreateSimplifyVo, HttpServletRequest request) {
        // 创建一个QuestionCreateVo对象。
        QuestionCreateVo questionCreateVo = new QuestionCreateVo();
        // 把能拷贝过来的属性都拷贝过来。
        BeanUtils.copyProperties(questionCreateSimplifyVo, questionCreateVo);
        // 设置创建者信息。
        String userId = (String) request.getAttribute("user_id");
        questionCreateVo.setQuestionCreatorId(userId);
        System.out.println(questionCreateVo);
        try {
            // 调用examService的questionCreate方法创建问题。
            examService.questionCreate(questionCreateVo);
            // 返回问题创建成功的ResultVO。
            return new ResultVO<>(0, "问题创建成功", null);
        } catch (Exception e) {
            // 打印异常信息。
            e.printStackTrace();
            // 返回创建问题失败的ResultVO。
            return new ResultVO<>(-1, "创建问题失败", null);
        }
    }

    /**
     * @Description: 获取全部问题列表,使用examService.getSelections()获取数据，并将其包装在ResultVO对象中
     * @return ResultVO<QuestionAllVo> 对象，包含问题列表
     */
    @GetMapping("/question/selection")
    @ApiOperation("获取问题分类的相关选项")
   // 获取问题分类选项。
ResultVO<QuestionSelectionVo> getSelections() {
        // 调用examService的getSelections方法获取问题分类选项。
        QuestionSelectionVo questionSelectionVo = examService.getSelections();
        // 如果获取成功。
        if (questionSelectionVo != null) {
            // 返回成功的结果。
            return new ResultVO<>(0, "获取问题分类选项成功", questionSelectionVo);
        } else {
            // 否则返回失败的结果。
            return new ResultVO<>(-1, "获取问题分类选项失败", null);
        }
    }

    /**
     * @Description: 使用examService.getQuestionDetail(id)获取数据,并将其包装在ResultVO对象中,用于获取全部问题列表
     * @param id 问题id
     * @return ResultVO<QuestionDetailVo> 对象，包含问题详情
     */
    @GetMapping("/question/detail/{id}")
    @ApiOperation("根据问题的id获取问题的详细信息")
    ResultVO<QuestionDetailVo> getQuestionDetail(@PathVariable String id) {
        //  根据问题id获取问题的详细信息。
        System.out.println(id);
        ResultVO<QuestionDetailVo> resultVO;
        try {
            // 调用examService的getQuestionDetail方法，根据问题id获取问题的详细信息。
            QuestionDetailVo questionDetailVo = examService.getQuestionDetail(id);
            // 如果获取成功，则返回ResultVO对象，状态码为0，提示信息为"获取问题详情成功"，数据为questionDetailVo。
            resultVO = new ResultVO<>(0, "获取问题详情成功", questionDetailVo);
        } catch (Exception e) {
            // 如果获取失败，则打印异常信息，并返回ResultVO对象，状态码为-1，提示信息为"获取问题详情失败"，数据为null。
            e.printStackTrace();
            // 创建一个表示获取失败的ResultVO对象，状态码设置为 -1，表示获取操作失败，消息设置为"获取问题详情失败"，数据部分设置为null
            resultVO = new ResultVO<>(-1, "获取问题详情失败", null);
        }
        // 返回ResultVO对象。
        return resultVO;
    }

    /**
     * @Description: 使用examService.getExamAll()获取数据,并将其包装在ResultVO对象中,用于获取全部考试列表
     * @return ResultVO<QuestionDetailVo> 对象，包含考试列表详情
     */
    @GetMapping("/all")
    @ApiOperation("获取全部考试的列表")
    ResultVO<List<ExamVo>> getExamAll() {
        // 需要拼接前端需要的考试列表对象。
        ResultVO<List<ExamVo>> resultVO;
        try {
            // 调用examService的getExamAll方法获取全部考试的列表。
            List<ExamVo> examVos = examService.getExamAll();
            // 将获取到的考试列表封装到ResultVO对象中，并返回。
            resultVO = new ResultVO<>(0, "获取全部考试的列表成功", examVos);
        } catch (Exception e) {
            // 捕获异常，并打印异常信息。
            e.printStackTrace();
            // 将异常信息封装到ResultVO对象中，并返回。
            resultVO = new ResultVO<>(-1, "获取全部考试的列表失败", null);
        }
        return resultVO;
    }

    /**
     * @Description: 使用examService.getExamQuestionTypeList()获取数据,并将其包装在ResultVO对象中,用于获取问题列表
     * @return ResultVO<ExamQuestionTypeVo> 对象，包含问题列表
     */
    @GetMapping("/question/type/list")
    @ApiOperation("获取问题列表，按照单选、多选和判断题分类返回")
    ResultVO<ExamQuestionTypeVo> getExamQuestionTypeList() {
        // 获取问题的分类列表。
        ResultVO<ExamQuestionTypeVo> resultVO;
        try {
            // 调用examService的getExamQuestionType方法获取问题分类列表。
            ExamQuestionTypeVo examQuestionTypeVo = examService.getExamQuestionType();
            // 如果获取成功，则返回成功的结果。
            resultVO = new ResultVO<>(0, "获取问题列表成功", examQuestionTypeVo);
        } catch (Exception e) {
            // 如果获取失败，则打印异常信息，并返回失败的结果。
            e.printStackTrace();
            resultVO = new ResultVO<>(-1, "获取问题列表失败", null);
        }
        // 返回结果。
        return resultVO;
    }

    /**
     * @Description: 使用examService.createExam()获取数据,并将其包装在ResultVO对象中,用于获取问题列表
     * @param examCreateVo 前端传过来的参数
     * @param request 获取用户id
     * @return ResultVO<Exam> 对象，包含考试信息
     */
    @PostMapping("/create")
    @ApiOperation("创建考试")
    ResultVO<Exam> createExam(@RequestBody ExamCreateVo examCreateVo, HttpServletRequest request) {
        // 定义一个ResultVO类型的变量，用于存放最终要返回给客户端的结果对象，其泛型参数指定为Exam，表示包含新创建考试相关信息的结果封装
        ResultVO<Exam> resultVO;
        // 从HttpServletRequest对象中获取用户ID信息，通常这个用户ID是在请求处理的前置环节（比如拦截器中）设置到请求属性中的，用于标识创建这个考试的用户是谁
        String userId = (String) request.getAttribute("user_id");
        try {
            // 调用ExamService的create方法，将创建考试的视图对象（examCreateVo）和获取到的用户ID传递进去，由服务层实现将考试记录数据保存到数据库等具体的创建逻辑操作，返回创建好的Exam对象代表新创建的考试信息
            Exam exam = examService.create(examCreateVo, userId);
            // 如果创建成功，创建一个表示成功的ResultVO对象，状态码设置为0，表示创建操作成功，消息设置为"创建考试成功"，并将创建好的考试对象放入ResultVO对象中返回给客户端
            resultVO = new ResultVO<>(0, "创建考试成功", exam);
        } catch (Exception e) {
            e.printStackTrace();
            // 如果在创建过程中出现异常，创建一个表示创建失败的ResultVO对象，状态码设置为 -1，表示创建操作失败，消息设置为"创建考试失败"，数据部分设置为null
            resultVO = new ResultVO<>(-1, "创建考试失败", null);
        }
        return resultVO;
    }
    /**
     * @Description: 使用examService.updateExam()获取数据,并将其包装在ResultVO对象中,用于更新考试
     * @param examVo 前端传过来的参数
     * @param request 获取用户id
     * @return
     */
    @PostMapping("/update")
    @ApiOperation("更新考试")
    ResultVO<Exam> updateExam(@RequestBody ExamVo examVo, HttpServletRequest request) {
        // 从前端传参数过来，在这里完成考试的入库。
        ResultVO<Exam> resultVO;
        // 获取当前用户id。
        String userId = (String) request.getAttribute("user_id");
        try {
            // 调用service层更新考试。
            Exam exam = examService.update(examVo, userId);
            // 返回更新成功的resultVO。
            resultVO = new ResultVO<>(0, "更新考试成功", exam);
        } catch (Exception e) {
            // 打印异常信息。
            e.printStackTrace();
            // 返回更新失败的resultVO。
            resultVO = new ResultVO<>(-1, "更新考试失败", null);
        }
        return resultVO;
    }
    /**
     * @Description: 获取考试列表，适配前端卡片列表
     * @return ResultVO<List<ExamCardVo>> 对象，包含考试列表卡片信息
     */
    @GetMapping("/card/list")
    @ApiOperation("获取考试列表，适配前端卡片列表")
    ResultVO<List<ExamCardVo>> getExamCardList() {
        // 获取考试列表卡片。
        ResultVO<List<ExamCardVo>> resultVO;
        try {
            // 调用examService的getExamCardList方法获取考试列表卡片。
            List<ExamCardVo> examCardVoList = examService.getExamCardList();
            // 如果获取数据成功，创建一个表示成功的ResultVO对象，状态码设置为0，表示获取考试列表卡片成功，消息设置为"获取考试列表卡片成功"，并将获取到的考试卡片列表数据放入ResultVO对象中，以便返回给客户端进行展示。
            resultVO = new ResultVO<>(0, "获取考试列表卡片成功", examCardVoList);
        } catch (Exception e) {
            // 如果获取失败，则打印异常信息，并返回失败的结果。
            e.printStackTrace();
            // 创建一个表示获取失败的ResultVO对象，状态码设置为 -1，表示获取考试列表卡片失败，消息可根据业务实际情况设置为相应的提示语，数据部分设置为null，因为没有成功获取到有效的考试卡片列表数据。
            resultVO = new ResultVO<>(-1, "获取考试列表卡片失败", null);
        }
        return resultVO;
    }
    /**
     * @Description: 根据考试的id，获取考试详情
     * @param id 考试id
     * @return ResultVO<ExamDetailVo> 对象，包含考试详情信息
     */
    @GetMapping("/detail/{id}")
    @ApiOperation("根据考试的id，获取考试详情")
    ResultVO<ExamDetailVo> getExamDetail(@PathVariable String id) {
        // 根据id获取考试详情，先定义一个用于存放最终要返回给客户端的ResultVO<ExamDetailVo>类型的结果对象，后续根据查询数据的情况进行赋值操作。
        ResultVO<ExamDetailVo> resultVO;
        try {
            // 调用ExamService的getExamDetail方法，将接收到的考卷唯一标识符（id）传递进去，由服务层实现从数据库或者其他数据源根据该ID查询对应考卷详细信息的逻辑，返回一个ExamDetailVo对象代表该考卷的所有详细信息。
            ExamDetailVo examDetail = examService.getExamDetail(id);
            // 如果获取详细信息成功，创建一个表示成功的ResultVO对象，状态码设置为0，表示获取考试详情成功，消息设置为"获取考试详情成功"，并将获取到的考卷详细信息对象放入ResultVO对象中，以便返回给客户端进行展示。
            resultVO = new ResultVO<>(0, "获取考试详情成功", examDetail);
        } catch (Exception e) {
            // 如果在获取考卷详细信息的过程中出现异常，创建一个表示获取失败的ResultVO对象，状态码设置为 -1，表示获取考试详情失败，消息可根据业务实际情况设置为相应的提示语，数据部分设置为null，因为没有成功获取到有效的考卷详细信息。
            resultVO = new ResultVO<>(-1, "获取考试详情失败", null);
        }
        return resultVO;
    }
    /**
     * @Description: 使用examService.finishExam获取数据,并将其包装在ResultVO对象中,用于考试判分
     * @param examId 考试id
     * @param answersMap 用户提交的答案
     * @param request 获取用户id
     * @return
     */
    @PostMapping("/finish/{examId}")
    @ApiOperation("根据用户提交的答案对指定id的考试判分")
    ResultVO<ExamRecord> finishExam(@PathVariable String examId, @RequestBody HashMap<String, List<String>> answersMap, HttpServletRequest request) {
        // 定义一个用于存放结果的ResultVO<ExamRecord>类型的数据结构，后续根据评分操作的成功与否以及获取到的相关数据进行赋值，用于最终返回给客户端展示评分结果。
        ResultVO<ExamRecord> resultVO;
        try {
            // 拦截器里设置上的用户id，从HttpServletRequest对象中获取用户ID属性值，该用户ID用于标识当前提交答案并进行评分的用户，是后续业务逻辑处理（如记录答题记录归属、判断是否有权限答题等）的重要依据。
            String userId = (String) request.getAttribute("user_id");
            // 下面根据用户提交的信息进行判分，返回用户的得分情况，调用ExamService的judge方法，传入获取到的用户ID、考试唯一标识符（examId）以及用户提交的答案集合（answersMap），由服务层实现具体的评分逻辑，比如对比答案、计算得分等操作，并返回一个ExamRecord对象，包含了评分后的成绩记录等详细信息。
            ExamRecord examRecord = examService.judge(userId, examId, answersMap);
            // 封装成绩记录到最终结果中，创建一个表示评分成功的ResultVO对象，状态码设置为0，表示考卷提交（评分）成功，消息设置为"考卷提交成功"，并将包含成绩记录的ExamRecord对象放入ResultVO对象中，以便返回给客户端展示评分结果。
            resultVO = new ResultVO<>(0, "考卷提交成功", examRecord);// 封装成绩记录到最终结果中
        } catch (Exception e) {
            // 如果在评分过程中出现异常，打印异常堆栈信息，方便开发人员排查问题，查看是答案解析出错还是其他业务逻辑环节出现的错误导致评分失败。
            e.printStackTrace();
            // 创建一个表示评分失败的ResultVO对象，状态码设置为 -1，表示考卷提交（评分）失败，消息可根据业务实际情况设置为相应的提示语，数据部分设置为null，因为没有成功获取到有效的评分成绩记录。
            resultVO = new ResultVO<>(-1, "考卷提交失败", null);
        }
        return resultVO;
    }
    /**
     * @Description: 使用examService.getExamRecordList获取数据,并将其包装在ResultVO对象中,用于获取当前用户的考试记录
     * @param request 获取用户id
     * @return ResultVO<List<ExamRecordVo>> 返回一个包含考试记录列表的ResultVO对象，如果发生异常，则返回一个包含错误信息的ResultVO对象。
     */
    @GetMapping("/record/list")
    @ApiOperation("获取当前用户的考试记录")
    ResultVO<List<ExamRecordVo>> getExamRecordList(HttpServletRequest request) {
        // 定义一个用于存放结果的ResultVO<List<ExamRecordVo>>类型的数据结构，后续根据查询用户考试记录操作的成功与否以及获取到的相关数据进行赋值，用于最终返回给客户端展示查询结果。
        ResultVO<List<ExamRecordVo>> resultVO;
        try {
            // 拦截器里设置上的用户id，从HttpServletRequest对象中获取用户ID属性值，该用户ID用于明确要查询其考试记录的目标用户，是服务层准确获取对应数据的关键依据。
            String userId = (String) request.getAttribute("user_id");
            // 下面根据用户账号拿到他（她）所有的考试信息，注意要用VO封装下，调用ExamService的getExamRecordList方法，传入获取到的用户ID，由服务层实现从数据库或者其他数据源获取该用户所有历史考试记录数据的逻辑，并将其整理封装成List<ExamRecordVo>类型的列表返回，每个ExamRecordVo对象包含了如时间、得分等详细信息。
            List<ExamRecordVo> examRecordVoList = examService.getExamRecordList(userId);
            // 封装查询得到的信息到最终结果中，创建一个表示获取成功的ResultVO对象，状态码设置为0，表示获取考试记录成功，消息设置为"获取考试记录成功"，并将获取到的用户考试记录列表数据放入ResultVO对象中，以便返回给客户端展示历史考试记录情况。
            resultVO = new ResultVO<>(0, "获取考试记录成功", examRecordVoList);//封装查询得到的信息到最终结果中；
        } catch (Exception e) {
            // 如果在获取用户考试记录数据的过程中出现异常，打印异常堆栈信息，方便开发人员排查问题，查看是数据源查询出错还是数据封装等环节出现的错误导致获取失败。
            e.printStackTrace();
            // 创建一个表示获取失败的ResultVO对象，状态码设置为 -1，表示获取考试记录失败，消息可根据业务实际情况设置为相应的提示语，数据部分设置为null，因为没有成功获取到有效的用户考试记录数据。
            resultVO = new ResultVO<>(-1, "获取考试记录失败", null);
        }
        return resultVO;//返回封装好的 数据结构
    }
    /**
     * @Description: 使用examService.getExamRecordDetail获取数据,并将其包装在ResultVO对象中,用于获取指定id的考试记录详情
     * @param recordId 考试记录id
     * @return ResultVO<RecordDetailVo> 返回一个包含考试记录详情的ResultVO对象，如果发生异常，则返回一个包含错误信息的ResultVO对象。
     */
    @GetMapping("/record/detail/{recordId}")
    @ApiOperation("根据考试记录id获取考试记录详情")
    ResultVO<RecordDetailVo> getExamRecordDetail(@PathVariable String recordId) {
        // 定义一个用于存放结果的ResultVO<RecordDetailVo>类型的数据结构，后续根据查询测验详细情况操作的成功与否以及获取到的相关数据进行赋值，用于最终返回给客户端展示查询结果。
        ResultVO<RecordDetailVo> resultVO;
        try {
            // 调用ExamService的getRecordDetail方法，将接收到的测验记录唯一标识符（recordId）传递进去，由服务层实现从数据库或者其他数据源根据该ID查询对应测验详细信息的逻辑，返回一个RecordDetailVo对象代表该次测验的所有详细信息。
            RecordDetailVo recordDetailVo = examService.getRecordDetail(recordId);
            // 封装查询得到的信息到最终结果中，创建一个表示获取成功的ResultVO对象，状态码设置为0，表示获取考试记录详情成功，消息设置为"获取考试记录详情成功"，并将获取到的测验详细信息对象放入ResultVO对象中，以便返回给客户端展示该次测验的详细情况。
            resultVO = new ResultVO<>(0, "获取考试记录详情成功", recordDetailVo);//封装查询得到的信息到最终结果中；
        } catch (Exception e) {
            // 如果在获取测验详细信息的过程中出现异常，打印异常堆栈信息，方便开发人员排查问题，查看是数据源查询出错还是数据解析等环节出现的错误导致获取失败。
            e.printStackTrace();
            // 创建一个ResultVO对象，表示操作失败
            // 状态码设置为-1，表示获取考试记录详情失败
            // 消息设置为"获取考试记录详情失败"
            // 由于查询失败，详细信息对象设置为null
            resultVO = new ResultVO<>(-1, "获取考试记录详情失败", null);
        }
        // 返回封装好的ResultVO对象给客户端
        // 客户端可以根据状态码和消息判断操作是否成功，并根据详细信息对象获取测验的详细记录信息
        return resultVO;
    }
}
