package com.ruoyi.web.controller.manager;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.quartz.service.ISysJobService;
import com.ruoyi.system.domain.exam.ElExam;
import com.ruoyi.system.domain.exam.dto.ExamRepoDTO;
import com.ruoyi.system.domain.exam.dto.ext.ExamRepoExtDTO;
import com.ruoyi.system.domain.exam.enums.ExamState;
import com.ruoyi.system.domain.paper.ElPaper;
import com.ruoyi.system.domain.paper.ElPaperQu;
import com.ruoyi.system.domain.paper.ElPaperQuAnswer;
import com.ruoyi.system.domain.paper.dto.PaperQuDTO;
import com.ruoyi.system.domain.paper.dto.ext.PaperQuAnswerExtDTO;
import com.ruoyi.system.domain.paper.dto.ext.PaperQuDetailDTO;
import com.ruoyi.system.domain.paper.dto.request.PaperAnswerDTO;
import com.ruoyi.system.domain.paper.dto.response.ExamDetailRespDTO;
import com.ruoyi.system.domain.paper.enums.PaperState;
import com.ruoyi.system.domain.qu.ElQu;
import com.ruoyi.system.domain.qu.ElQuAnswer;
import com.ruoyi.system.domain.qu.enums.QuType;
import com.ruoyi.system.service.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * packageName com.ruoyi.web.controller.manager
 *
 * @author wangxy
 * @version JDK 8
 * @className PaperManager
 * @date 2024/6/28
 * @description 试卷
 */
@Component
public class PaperManager {


    @Resource
    private ElPaperService paperService;

    @Resource
    private ElPaperQuService paperQuService;

    @Resource
    private ElPaperQuAnswerService paperQuAnswerService;


    @Autowired
    private ElExamService examService;


    @Autowired
    private ElExamRepoService examRepoService;

    @Resource
    private ElQuService quService;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private ElQuAnswerService quAnswerService;

    @Autowired
    private ISysJobService jobService;


    @Resource
    private UserExamManager userExamManager;

    @Resource
    private UserBookManager userBookManager;




    /**
     * 展示的选项，ABC这样
     */
    private static List<String> ABC = Arrays.asList(new String[]{
            "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K","L","M","N","O","P","Q","R","S","T","U","V","W","X"
            ,"Y","Z"
    });


    /**
     * 
     *  创建试卷
     * @param examId
     * @param userId
     * @return java.lang.String
     */
    
    @Transactional(rollbackFor = Exception.class)
    public String createPaper(String examId,Long userId) {
        // 校验是否有正在考试的试卷
        QueryWrapper<ElPaper> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(ElPaper::getUserId, userId)
                .eq(ElPaper::getState, PaperState.ING);
        long exists = paperService.count(wrapper);
        if (exists > 0) {
            throw new ServiceException("您有正在进行的考试！");
        }
        // 查找考试
        ElExam exam = examService.getById(examId);

        if(Objects.isNull(exam)){
            throw new ServiceException( "考试不存在！");
        }
        if(!ExamState.ENABLE.equals(exam.getState())){
            throw new ServiceException( "考试状态不正确！");
        }
        // 考试题目列表
        List<ElPaperQu> quList = this.generateByRepo(examId);

        if(CollectionUtils.isEmpty(quList)){
            throw new ServiceException("规则不正确，无对应的考题！");
        }
        //保存试卷内容
        ElPaper paper = this.savePaper(userId, exam, quList);
        return paper.getId();
    }






    /**
     * 题库组题方式产生题目列表
     * @param examId
     * @return
     */
    private List<ElPaperQu> generateByRepo(String examId){
        // 查找规则指定的题库
        List<ExamRepoExtDTO> list = examRepoService.listByExam(examId);
        //最终的题目列表
        List<ElPaperQu> quList = new ArrayList<>();
        //排除ID，避免题目重复
        List<String> excludes = new ArrayList<>();
        excludes.add("none");
        if (!CollectionUtils.isEmpty(list)) {
            for (ExamRepoExtDTO item : list) {
                // 单选题
                if(item.getRadioCount() > 0){
                    List<ElQu> radioList = quService.listByRandom(item.getRepoId(), QuType.RADIO, excludes, item.getRadioCount());
                    for (ElQu qu : radioList) {
                        ElPaperQu paperQu = this.processPaperQu(item, qu);
                        quList.add(paperQu);
                        excludes.add(qu.getId());
                    }
                }
                //多选题
                if(item.getMultiCount() > 0) {
                    List<ElQu> multiList = quService.listByRandom(item.getRepoId(), QuType.MULTI, excludes,
                            item.getMultiCount());
                    for (ElQu qu : multiList) {
                        ElPaperQu paperQu = this.processPaperQu(item, qu);
                        quList.add(paperQu);
                        excludes.add(qu.getId());
                    }
                }
                // 判断题
                if(item.getJudgeCount() > 0) {
                    List<ElQu> judgeList = quService.listByRandom(item.getRepoId(), QuType.JUDGE, excludes,
                            item.getJudgeCount());
                    for (ElQu qu : judgeList) {
                        ElPaperQu paperQu = this.processPaperQu(item, qu);
                        quList.add(paperQu);
                        excludes.add(qu.getId());
                    }
                }
            }
        }
        return quList;
    }


    /**
     * 填充试题题目信息
     * @param repo
     * @param qu
     * @return
     */
    private ElPaperQu processPaperQu(ExamRepoDTO repo, ElQu qu) {

        //保存试题信息
        ElPaperQu paperQu = new ElPaperQu();
        paperQu.setQuId(qu.getId());
        paperQu.setAnswered(false);
        paperQu.setIsRight(false);
        paperQu.setQuType(qu.getQuType());

        if (QuType.RADIO.equals(qu.getQuType())) {
            paperQu.setScore(repo.getRadioScore());
            paperQu.setActualScore(repo.getRadioScore());
        }

        if (QuType.MULTI.equals(qu.getQuType())) {
            paperQu.setScore(repo.getMultiScore());
            paperQu.setActualScore(repo.getMultiScore());
        }

        if (QuType.JUDGE.equals(qu.getQuType())) {
            paperQu.setScore(repo.getJudgeScore());
            paperQu.setActualScore(repo.getJudgeScore());
        }

        return paperQu;
    }


    /**
     * 保存试卷
     *
     * @param userId
     * @param exam
     * @param quList
     * @return
     */
    private ElPaper savePaper(Long userId, ElExam exam, List<ElPaperQu> quList) {
        // 查找用户
        SysUser user = sysUserService.selectUserById(userId);
        //保存试卷基本信息
        ElPaper paper = new ElPaper();
        paper.setDepartId(user.getDeptId());
        paper.setExamId(exam.getId());
        paper.setTitle(exam.getTitle());
        paper.setTotalScore(exam.getTotalScore());
        paper.setTotalTime(exam.getTotalTime());
        paper.setUserScore(0);
        paper.setUserId(userId);
        paper.setCreateTime(new Date());
        paper.setUpdateTime(new Date());
        paper.setQualifyScore(exam.getQualifyScore());
        paper.setState(PaperState.ING);
        paper.setHasSaq(false);
        // 截止时间
        Calendar cl = Calendar.getInstance();
        cl.setTimeInMillis(System.currentTimeMillis());
        cl.add(Calendar.MINUTE, exam.getTotalTime());
        paper.setLimitTime(cl.getTime());
        paperService.save(paper);
        if (CollUtil.isNotEmpty(quList)) {
            this.savePaperQu(paper.getId(), quList);
        }
        return paper;
    }

    /**
     * 保存试卷试题列表
     * @param paperId
     * @param quList
     */
    private void savePaperQu(String paperId, List<ElPaperQu> quList){

        List<ElPaperQu> batchQuList = new ArrayList<>();
        List<ElPaperQuAnswer> batchAnswerList = new ArrayList<>();
        int sort = 0;
        for (ElPaperQu item : quList) {
            item.setPaperId(paperId);
            item.setSort(sort);
            item.setId(IdWorker.getIdStr());
            //回答列表
            QueryWrapper<ElQuAnswer> wrapper = new QueryWrapper<>();
            wrapper.lambda().eq(ElQuAnswer::getQuId, item.getQuId());
            wrapper.last(" ORDER BY RAND() ");
            List<ElQuAnswer> answerList = quAnswerService.list(wrapper);
            if (CollUtil.isNotEmpty(answerList)) {
                int ii = 0;
                for (ElQuAnswer answer : answerList) {
                    ElPaperQuAnswer paperQuAnswer = new ElPaperQuAnswer();
                    paperQuAnswer.setId(UUID.randomUUID().toString());
                    paperQuAnswer.setPaperId(paperId);
                    paperQuAnswer.setQuId(answer.getQuId());
                    paperQuAnswer.setAnswerId(answer.getId());
                    paperQuAnswer.setChecked(false);
                    paperQuAnswer.setSort(ii);
                    paperQuAnswer.setAbc(ABC.get(ii));
                    paperQuAnswer.setIsRight(answer.getIsRight());
                    ii++;
                    batchAnswerList.add(paperQuAnswer);
                }
            }
            batchQuList.add(item);
            sort++;
        }
        //添加问题
        paperQuService.saveBatch(batchQuList);
        //批量添加问题答案
        paperQuAnswerService.saveBatch(batchAnswerList);
    }

    /**
     *
     *  试卷详情
     * @param paperId
     * @return com.ruoyi.system.domain.paper.dto.response.ExamDetailRespDTO
     */

    public ExamDetailRespDTO paperDetail(String paperId) {
        // 试题基本信息
        ElPaper paper = paperService.getById(paperId);
        ExamDetailRespDTO respDTO = Convert.convert(ExamDetailRespDTO.class, paper);
        //查询条件
        QueryWrapper<ElPaperQu> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(ElPaperQu::getPaperId, paperId)
                .orderByAsc(ElPaperQu::getSort);
        List<ElPaperQu> paperQus = paperQuService.list(wrapper);
        // 查找题目列表
        List<PaperQuDTO> list = Convert.toList(PaperQuDTO.class, paperQus);
        List<PaperQuDTO> radioList = new ArrayList<>();
        List<PaperQuDTO> multiList = new ArrayList<>();
        List<PaperQuDTO> judgeList = new ArrayList<>();
        for(PaperQuDTO item: list){
            if(QuType.RADIO.equals(item.getQuType())){
                radioList.add(item);
            }
            if(QuType.MULTI.equals(item.getQuType())){
                multiList.add(item);
            }
            if(QuType.JUDGE.equals(item.getQuType())){
                judgeList.add(item);
            }
        }
        respDTO.setRadioList(radioList);
        respDTO.setMultiList(multiList);
        respDTO.setJudgeList(judgeList);
        return respDTO;
    }

    /**
     * 
     *  试题详情
     * @param paperId
     * @param quId
     * @return com.ruoyi.system.domain.paper.dto.ext.PaperQuDetailDTO
     */
    
    public PaperQuDetailDTO findQuDetail(String paperId, String quId) {
        // 问题
        ElQu qu = quService.getById(quId);
        // 基本信息
        QueryWrapper<ElPaperQu> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(ElPaperQu::getPaperId, paperId)
                .eq(ElPaperQu::getQuId, quId);
        ElPaperQu paperQu = paperQuService.getOne(wrapper);
        PaperQuDetailDTO respDTO = Convert.convert(PaperQuDetailDTO.class, paperQu);
        respDTO.setContent(qu.getContent());
        respDTO.setImage(qu.getImage());
        // 答案列表
        List<PaperQuAnswerExtDTO> list = paperQuAnswerService.list(paperId, quId);
        respDTO.setAnswerList(list);
        return respDTO;
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean fillAnswer(PaperAnswerDTO reqDTO) {
        // 未作答
        if(CollectionUtils.isEmpty(reqDTO.getAnswers())
                && StringUtils.isBlank(reqDTO.getAnswer())){
            return null;
        }
        //查找答案列表
        QueryWrapper<ElPaperQuAnswer> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(ElPaperQuAnswer::getPaperId, reqDTO.getPaperId())
                .eq(ElPaperQuAnswer::getQuId,  reqDTO.getQuId());
        List<ElPaperQuAnswer> list = paperQuAnswerService.list(wrapper);
        //是否正确
        boolean right = true;
        //更新正确答案
        for (ElPaperQuAnswer item : list) {

            if (reqDTO.getAnswers().contains(item.getId())) {
                item.setChecked(true);
            } else {
                item.setChecked(false);
            }
            //有一个对不上就是错的
            if (item.getIsRight()!=null && !item.getIsRight().equals(item.getChecked())) {
                right = false;
            }
            paperQuAnswerService.updateById(item);
        }
        //修改为已回答
        ElPaperQu qu = new ElPaperQu();
        qu.setQuId(reqDTO.getQuId());
        qu.setPaperId(reqDTO.getPaperId());
        qu.setIsRight(right);
        qu.setAnswer(reqDTO.getAnswer());
        qu.setAnswered(true);
        QueryWrapper<ElPaperQu> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ElPaperQu::getPaperId, qu.getPaperId())
                .eq(ElPaperQu::getQuId, qu.getQuId());
        paperQuService.update(qu,queryWrapper);
        return true;
    }

    /**
     * 
     *  交卷
     * @param paperId
     * @return boolean
     */
    
    @Transactional(rollbackFor = Exception.class)
    public boolean submitExam(String paperId) {
        //获取试卷信息
        ElPaper paper = paperService.getById(paperId);
        //如果不是正常的，抛出异常
        if(!PaperState.ING.equals(paper.getState())){
            throw new ServiceException("试卷状态不正确！");
        }
        // 客观分
        int objScore = paperQuService.sumObjective(paperId);
        paper.setObjScore(objScore);
        paper.setUserScore(objScore);
        // 主观分，因为要阅卷，所以给0
        paper.setSubjScore(0);
        // 待阅卷
        if(Boolean.TRUE.equals(paper.getHasSaq())) {
            paper.setState(PaperState.WAIT_OPT);
        }else {
            // 同步保存考试成绩
            userExamManager.joinResult(paper.getUserId(), paper.getExamId(), objScore, objScore>=paper.getQualifyScore());
            paper.setState(PaperState.FINISHED);
        }
        paper.setUpdateTime(new Date());
        //计算考试时长
        Calendar cl = Calendar.getInstance();
        cl.setTimeInMillis(System.currentTimeMillis());
        int userTime = (int)((System.currentTimeMillis() - paper.getCreateTime().getTime()) / 1000 / 60);
        if(userTime == 0){
            userTime = 1;
        }
        paper.setUserTime(userTime);
        //更新试卷
        paperService.updateById(paper);
        List<ElPaperQu> paperQus = paperQuService.lambdaQuery()
                .eq(ElPaperQu::getPaperId, paperId)
                .orderByAsc(ElPaperQu::getSort).list();
        List<PaperQuDTO> list = Convert.toList(PaperQuDTO.class, paperQus);
        for(PaperQuDTO qu: list){
            // 主观题和对的都不加入错题库
            if(Boolean.TRUE.equals(qu.getIsRight())){
                continue;
            }
            //加入错题本
            new Thread(() -> userBookManager.addBook(paper.getExamId(), qu.getQuId())).run();
        }
        return true;
    }



}
