package com.xhkjedu.smarking.service.paper;

import com.xhkjedu.exception.MissingParametersException;
import com.xhkjedu.smarking.mapper.exam.MsSubjectMapper;
import com.xhkjedu.smarking.mapper.paper.*;
import com.xhkjedu.smarking.mapper.papercheck.MsPaperCheckTeacherMapper;
import com.xhkjedu.smarking.mapper.stupaper.MsPaperStudentMapper;
import com.xhkjedu.smarking.mapper.stupaper.MsPaperStudentQuestionMapper;
import com.xhkjedu.smarking.mapper.system.SchoolMapper;
import com.xhkjedu.smarking.mapper.system.UserBasketMapper;
import com.xhkjedu.smarking.model.paper.*;
import com.xhkjedu.smarking.model.stupaper.MsPaperStudentQuestion;
import com.xhkjedu.smarking.utils.ConvertUtil;
import com.xhkjedu.smarking.utils.MarkingUtil;
import com.xhkjedu.smarking.vo.paper.*;
import com.xhkjedu.smarking.vo.system.SchoolCloudVo;
import com.xhkjedu.utils.N_Utils;
import com.xhkjedu.vo.ResultVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

/**
 * @Description 阅卷试卷题型表 服务实现类
 * @Author auto
 * @Date 2024-10-15
 */
@Slf4j
@Service
public class MsPaperQtypeService {
    @Resource
    private MsPaperQtypeMapper msPaperQtypeMapper;
    @Resource
    private MsPaperAnalyzeMapper msPaperAnalyzeMapper;
    @Resource
    private MsPaperMapper msPaperMapper;
    @Resource
    private MsPaperQtypeQuestionMapper msPaperQtypeQuestionMapper;
    @Resource
    private MsPaperFileMapper msPaperFileMapper;
    @Resource
    private MsPaperQtypeQuestionPointMapper msPaperQtypeQuestionPointMapper;
    @Resource
    private MsSubjectMapper msSubjectMapper;
    @Resource
    private UserBasketMapper userBasketMapper;
    @Resource
    private SchoolMapper schoolMapper;
    @Resource
    private MsPaperStudentQuestionMapper msPaperStudentQuestionMapper;
    @Resource
    private MsPaperStudentMapper msPaperStudentMapper;
    @Resource
    private MsPaperCheckTeacherMapper msPaperCheckTeacherMapper;
    @Resource
    private MsPaperAnalyzeService msPaperAnalyzeService;
    private final ConvertUtil convertUtil;

    public MsPaperQtypeService(ConvertUtil convertUtil) {
        this.convertUtil = convertUtil;
    }

    /**
     * @return void
     * @Description 新增
     * @Param [msPaperQtype]
     * @Author auto
     * @Date 2024-10-15
     **/
    @Transactional(rollbackFor = Exception.class)
    public ResultVo savePaperQtype(MsPaper paper, Integer pstate) {
        Integer mpid = paper.getMpid();

        // 根据试卷ID获取考试信息
        PExamSubjectVo exam = msPaperMapper.getExamSubjectForPaper(mpid);
        // 线下考试，发布成绩（生成报告）之前可以修改试卷结构
        if (exam.getExammode() < 3 && exam.getExamstate() > 2) {
            throw new MissingParametersException("考试已统分禁止操作");
        }

        if (exam.getExammode() == 3 && exam.getPstate() == 2) {
            throw new MissingParametersException("试卷已提交禁止操作");
        }

        // 先删除原有题型、分析
        msPaperQtypeMapper.deleteByMpId(mpid);

        // 根据考试类型（线上和线下），是否删除文件
        if (exam.getExammode() == 3 && paper.getPtype() == 2) {
            msPaperFileMapper.deleteByMpid(mpid);
        }

        List<MsPaperQtype> qtypeList = paper.getQtypes();
        int timestamp = N_Utils.getSecondTimestamp();
        paper.setCreatetime(timestamp);
        setPaperBaseDetail(paper, qtypeList);
        msPaperMapper.updatePaperInfo(paper);
        // 保存题型试题信息
        savePaperQtype(paper, qtypeList);

        List<String> imgs = new ArrayList<>();
        // 保存试卷分析
        if (paper.getPtype() == 1) {
            msPaperAnalyzeService.savePaperAnalyzeForQuestion(paper);
        } else {
            List<MsPaperFile> pfiles = paper.getPfiles();// 附件
            if (paper.getYjstate() == 1) {
                setPaperFiles(paper, pfiles, imgs);
                msPaperFileMapper.insertList(pfiles);
            }
            msPaperAnalyzeService.savePaperAnalyzeForFj(paper);
        }

        // 更改科目状态
        msSubjectMapper.updatePstateByMpid(mpid, pstate);
        if (paper.getPtype() == 1) {
            userBasketMapper.deleteByUseridAndSubjectid(paper.getCreateid(), exam.getSubjectid());
        }

        msPaperCheckTeacherMapper.deleteByMpid(mpid);// 删除批阅教师
        if (exam.getExammode() < 3) {
            // 如果是线下考试更改了试卷结构，则清空题块、试卷模板
            msPaperMapper.deleteTemplageBlockByMpid(mpid);
            msPaperStudentMapper.deletePaperStuByMpid(mpid);
            msSubjectMapper.updatePaperFollowup(mpid);
        } else {
            msSubjectMapper.updateCheckSetByMpId(mpid, 0);
        }

        if (N_Utils.isListNotEmpty(imgs) && imgs.size() > 1) {
            // 说明上传的试卷附件文件为图片，并且图片为多张，调用mq合并
            convertUtil.imgToPdf(imgs, mpid, 1);
        }

        return new ResultVo(0, "保存成功", paper.getMpid());
    }

    // 设置试卷基本信息
    private void setPaperBaseDetail(MsPaper paper, List<MsPaperQtype> qtypelist) {
        if (paper.getPtype() == 2 && paper.getPfiles() != null && !paper.getPfiles().isEmpty()) {
            // 获取附件为1题干的数量
            List<MsPaperFile> pfiles = paper.getPfiles().stream().filter(p -> p.getFiletype() == 1).collect(Collectors.toList());
            if (N_Utils.isListNotEmpty(pfiles)) {
                paper.setYjstate(1);
            } else {
                paper.setYjstate(0);
            }
        } else {
            paper.setYjstate(0);
        }
        double pscore = qtypelist.stream().mapToDouble(MsPaperQtype::getMptscore).sum();
        int pnum = qtypelist.stream().mapToInt(MsPaperQtype::getMptnum).sum();
        paper.setPnum(pnum);
        paper.setPscore(pscore);
        paper.setHandletime(paper.getCreatetime());
        paper.setHandleid(paper.getCreateid());
        if (paper.getPtype() == 1) {
            paper.setAnswered(1);// 题库已设置正确答案
        } else {
            paper.setAnswered(0);
        }

        if(N_Utils.isNotEmpty(paper.getHearfile())){
            paper.setHasfile(1);//说明有听力文件
        }

        if (paper.getHearnum() == null) {
            paper.setHearnum(0);
        }
    }

    // 保存试卷题型试题信息
    private void savePaperQtype(MsPaper paper, List<MsPaperQtype> qtypelist) {
        for (MsPaperQtype qtype : qtypelist) {
            qtype.setMpid(paper.getMpid());
            qtype.setCreateid(paper.getHandleid());
            qtype.setCreatetime(paper.getHandletime());
            qtype.setMptname(N_Utils.strTrim(qtype.getMptname()));
            if(N_Utils.isEmpty(qtype.getMptqn())){
                qtype.setMptqn(MarkingUtil.getQnByOrder(qtype.getMptorder()));
            }
        }
        msPaperQtypeMapper.insertList(qtypelist);// 保存题型
        List<MsPaperQtypeQuestion> qtqs = new ArrayList<>();
        for (MsPaperQtype qtype : qtypelist) {
            List<MsPaperQtypeQuestion> questions = qtype.getQuestions();
            qtype.setMptid(qtype.getId());

            for (MsPaperQtypeQuestion q : questions) {
                q.setMpid(paper.getMpid());
                q.setMptid(qtype.getId());
                q.setPagenum(0);
                if (q.getOptionnum() == null) {
                    q.setOptionnum(0);
                }
                if (q.getLoseoption() == null) {
                    q.setLoseoption(0.0);
                }
                if (q.getScoreset() == null) {
                    q.setScoreset(0);
                }
                if (N_Utils.isObjectiveQuestion(q.getCtype())) {
                    q.setQtype(1);
                } else {
                    q.setQtype(2);
                }
                q.setQnstr(qtype.getMptqn() + "." + q.getQn());

                qtqs.add(q);
            }
        }
        msPaperQtypeQuestionMapper.insertList(qtqs);
    }



    // 设置附件
    private void setPaperFiles(MsPaper paper, List<MsPaperFile> pfiles, List<String> imgs) {
        int order = 1;
        for (MsPaperFile pf : pfiles) {
            pf.setCreateid(paper.getCreateid());
            pf.setCreatetime(paper.getHandletime());
            pf.setMpid(paper.getMpid());
            pf.setFileorder(order++);

            if (isImgFormatForsourcepath(pf.getSourcepath()) && !imgs.contains(pf.getSourcepath()) && pf.getFiletype() == 1) {
                imgs.add(pf.getSourcepath());
            }
        }
    }

    // 根据地址判断是否图片
    private boolean isImgFormatForsourcepath(String sourcepath) {
        if (sourcepath != null && !sourcepath.isEmpty()) {
            return sourcepath.contains(".jpg") || sourcepath.contains(".png") || sourcepath.contains(".jpeg");
        } else {
            return false;
        }

    }




    /*
     * @Description 试卷答案-客观题
     * @Date 2024/10/17 15:38:44
     * @Author WN
     * @Param [qtype]
     * @Return com.xhkjedu.vo.ResultVo
     **/
    @Transactional(rollbackFor = Exception.class)
    public ResultVo answerObjective(MsPaperQtype qtype) {
        Integer mpid = qtype.getMpid();
        List<MsPaperQtypeQuestion> questions = qtype.getQuestions();
        for (MsPaperQtypeQuestion question : questions) {
            if (!N_Utils.isTrueInteger(question.getMptqid()) || N_Utils.isEmpty(question.getQanswer())) {
                return new ResultVo(1, "请设置对应试题答案");
            }
        }

        // 获取试题答案改变的试题
        List<MsPaperQtypeQuestion> changelist = new ArrayList<>();
        // 获取试卷中原试题答案
        List<MsPaperQtypeQuestion> yqlist = msPaperQtypeQuestionMapper.listQuestionsByMpid(mpid);
        for (MsPaperQtypeQuestion tq : questions) {
            if (N_Utils.isTrueInteger(tq.getMptqid()) && N_Utils.isNotEmpty(tq.getQanswer())) {
                MsPaperQtypeQuestion yq = yqlist.stream().filter(y -> y.getMptqid().equals(tq.getMptqid())).findFirst().orElse(null);
                if(yq!=null && yq.getQtype() == 1){
                    if (!tq.getQanswer().equalsIgnoreCase(yq.getQanswer()) || !tq.getLoseoption().equals(yq.getLoseoption()) || !tq.getScoreset().equals(yq.getScoreset())) {
                        // 说明新设置的答案和原设置的答案不一致，则为变动的
                        tq.setCtype(yq.getCtype());
                        tq.setQscore(yq.getQscore());
                        changelist.add(tq);
                    }
                }
            }
        }

        // 保存试题答案
        // 更新试卷设置答案状态
        msPaperMapper.updatePaperAnswer(1, mpid);
        // 保存试卷答案
        msPaperQtypeQuestionMapper.updateBatchQuestionAnswer(changelist);

        // 判断考试状态是开始，已提交学生重新批阅，需要重新批阅
        PExamSubjectVo examSubjectVo = msPaperMapper.getSubjectStateByMpid(mpid);
        if (examSubjectVo.getMsstate() > 0 && !changelist.isEmpty()) {
            msPaperStudentQuestionMapper.updateBatchStuQuesNeeddeal(mpid, changelist);// 批量设置学生提交试题为需要批改试题

            // 说明该试卷考试已开始，处理已提交试卷中客观题答案批阅
            new Thread(() -> {
                try {
                    dealChangeQuestionStuAnswer(changelist, mpid);
                } catch (Exception e) {
                    log.error("处理学生已提交客观题重新批阅：" + e.getMessage());
                    try {
                        dealChangeQuestionStuAnswer(changelist, mpid);
                    } catch (Exception se) {
                        log.error("处理学生已提交客观题重新批阅出错：" + se.getMessage());
                    }
                }
            }).start();
        }

        return new ResultVo(0, "保存成功");
    }

    // 试卷答案-客观题-对于已经开始考试的试卷修改正确答案重新判断试题
    public void dealChangeQuestionStuAnswer(List<MsPaperQtypeQuestion> changeQs, Integer mpid) {
        int limitnum = 100;// 一次处理条数
        for (MsPaperQtypeQuestion q : changeQs) {
            int mptqid = q.getMptqid();
            boolean hasmore = true;
            while (hasmore) {
                // 获取指定试题学生作答情况,指定条数的数据
                List<MsPaperStudentQuestion> psqlist = msPaperStudentQuestionMapper.listPaperStudentQuestionsByMptqid(mpid, mptqid, limitnum);
                if (N_Utils.isListNotEmpty(psqlist)) {
                    List<MsPaperStudentQuestion> uplist = setUpdateStuQuestions(q, psqlist);
                    if (N_Utils.isListNotEmpty(uplist)) {
                        // 批量更新学生试题分值
                        msPaperStudentQuestionMapper.updateBatchStuQuestionScore(uplist);
                        // 获取需要更改的学生试卷
                        List<Integer> mpsids = psqlist.stream().map(MsPaperStudentQuestion::getMpsid).distinct().collect(Collectors.toList());
                        // 更新学生试卷分值
                        msPaperStudentMapper.updateBathStudentPaperScoreByMpsid(mpid, mpsids);
                    }
                } else {
                    hasmore = false;
                }
            }
        }
    }

    // 试卷答案-客观题-设置学生答案得分
    private List<MsPaperStudentQuestion> setUpdateStuQuestions(MsPaperQtypeQuestion q, List<MsPaperStudentQuestion> psqlist) {
        List<MsPaperStudentQuestion> uplist = new ArrayList<>();// 要更新的
        Integer timestamp = N_Utils.getSecondTimestamp();

        // 先判断试题分值设置0默认1送分题 2 0分题
        double allScore = 0.0;
        if (N_Utils.isTrueInteger(q.getScoreset())) {
            if (q.getScoreset() == 1) {
                allScore = q.getQscore();
            }

            for (MsPaperStudentQuestion psq : psqlist) {
                if (psq.getAnswered() == 1 && N_Utils.isNotEmpty(psq.getStuanswer())) {
                    psq.setStuscore(allScore);
                } else {
                    psq.setStuscore(0.0);
                }
                psq.setFirstcime(timestamp);
                uplist.add(psq);
            }

        } else {
            // 按照学生答案进行分组
            Map<String, List<MsPaperStudentQuestion>> stuansmap = psqlist.stream().collect(Collectors.groupingBy(MsPaperStudentQuestion::getStuanswer));
            // 处理学生答案
            for (Map.Entry<String, List<MsPaperStudentQuestion>> entry : stuansmap.entrySet()) {
                String stuanswer = entry.getKey();
                Double stuScore = MarkingUtil.checkObjectiveStuAnswer(stuanswer, q.getCtype(), q.getQanswer(), q.getLoseoption(), q.getQscore());

                List<MsPaperStudentQuestion> sameanswerlist = entry.getValue();// 答案对应的学生
                for (MsPaperStudentQuestion stuq : sameanswerlist) {
                    stuq.setStuscore(stuScore);
                    stuq.setFirstcime(timestamp);
                    uplist.add(stuq);
                }
            }
        }

        return uplist;
    }

    /*
     * @Description 试卷答案-主观题
     * @Date 2024/10/17 15:40:47
     * @Author WN
     * @Param [qtype]
     * @Return com.xhkjedu.vo.ResultVo
     **/
    @Transactional(rollbackFor = Exception.class)
    public void answerSubjective(MsPaper paper) {
        Integer mpid = paper.getMpid();
        List<MsPaperFile> pfiles = paper.getPfiles();
        // 删除已保存主观题答案图片
        msPaperFileMapper.deleteByMpidAndType(mpid, 2);
        Integer timestamp = N_Utils.getSecondTimestamp();
        List<String> imgs = pfiles.stream().map(MsPaperFile::getFilepath).collect(Collectors.toList());
        PaperFileVo paperFileVo = null;
        if (imgs.get(0).contains("base64")) {// 说明上传的是base64图片
            // 获取试卷对应学校区域码,base64转为图片
            SchoolCloudVo schoolCloudVo = schoolMapper.getSchoolCloudcode(mpid);
            String saveFloder = schoolCloudVo.getCloudcode() + "/" + schoolCloudVo.getSchoolid() + "/marking/paper";
            paperFileVo = MarkingUtil.uploadBatchBase64ImgPdf(imgs, saveFloder);
        }

        for (int i = 0; i < pfiles.size(); i++) {
            MsPaperFile pf = pfiles.get(i);
            pf.setMpid(mpid);
            pf.setCreateid(paper.getCreateid());
            pf.setCreatetime(timestamp);
            pf.setFiletype(2);
            pf.setFileorder(i + 1);

            if (paperFileVo != null) {
                pf.setSourcepath(paperFileVo.getPdfpath());
                pf.setFilepath(paperFileVo.getImgs().get(i));
            }
        }

        msPaperFileMapper.insertList(pfiles);
    }

    /*
     * @Description 保存试题知识点和难易度
     * @Date 2024/10/17 17:07:28
     * @Author WN
     * @Param [paper]
     * @Return void
     **/
    @Transactional(rollbackFor = Exception.class)
    public void saveQuestionPoints(MsPaper paper) {
        // 先删除已存在试题知识点
        msPaperQtypeQuestionPointMapper.deleteByMpid(paper.getMpid());

        List<MsPaperQtypeQuestion> questions = paper.getQuestions();
        List<MsPaperQtypeQuestionPoint> savePoints = new ArrayList<>();
        Integer mpid = paper.getMpid();
        Integer createid = paper.getCreateid();
        Integer timestamp = N_Utils.getSecondTimestamp();
        for (MsPaperQtypeQuestion question : questions) {
            List<MsPaperQtypeQuestionPoint> points = question.getPoints();
            int i = 1;
            for (MsPaperQtypeQuestionPoint point : points) {
                point.setCreateid(createid);
                point.setCreatetime(timestamp);
                point.setMptqid(question.getMptqid());
                point.setMpid(mpid);
                point.setMporder(i++);
                savePoints.add(point);
            }
        }
        // 保存难易度
        msPaperQtypeQuestionMapper.updateBatchQuestionComplexity(questions);

        // 保存试题知识点
        msPaperQtypeQuestionPointMapper.insertList(savePoints);

        // 保存完知识点难易度后，更新试卷分析
        MsPaper apaper = msPaperMapper.selectByPrimaryKey(mpid);
        msPaperAnalyzeService.savePaperAnalyzeForFj(apaper);
    }

    /*
     * @Description 获取试卷详细信息
     * @Date 2024/10/18 9:29:37
     * @Author WN
     * @Param [msid]
     * @Return java.util.Map<java.lang.String,java.lang.Object>
     **/
    public Map<String, Object> getPaperDetail(Integer msid) {
        // 获取试卷详情
        Map<String, Object> paper = msPaperMapper.getPaperInfoByMsid(msid);
        if (N_Utils.isEmpty((paper.get("ptype"))) || paper.get("ptype").equals("0")) {
            return paper;
        }
        int ptype = Integer.parseInt(paper.get("ptype").toString());
        Integer mpid = Integer.parseInt(paper.get("mpid").toString());
        List<MsPaperQtypeVo> qtypelist;
        // 获取题型下试题
        if (ptype == 1) {
            // 题库
            qtypelist = msPaperQtypeMapper.listPaperQtypeQuestions(mpid);
            setPaperQuestionQtypeQuesitonTk(qtypelist);
            paper.put("qtypes", qtypelist);
        } else {
            // 附件
            qtypelist = msPaperQtypeMapper.listPaperQtypeQuesitonsForFj(mpid);
            List<Map<String, Object>> qtypes = new ArrayList<>();
            setPaperQuestionQtypeQuesitonFj(qtypelist, qtypes);
            paper.put("qtypes", qtypes);

            // 试卷文件
            List<MsPaperFile> pfiles = msPaperFileMapper.listFilesbyMpidAndType(mpid, null);
            paper.put("pfiles", pfiles);
        }

        // 试卷分析
        MsPaperAnalyze analyze = msPaperAnalyzeMapper.getObjByMpId(mpid);
        paper.put("analyze", analyze);

        return paper;
    }


    private void setPaperQuestionQtypeQuesitonTk(List<MsPaperQtypeVo> typelist){
        for(MsPaperQtypeVo qt : typelist){
            List<MsPaperQtypeQuestionVo> qlist = qt.getQuestions();
            List<MsPaperQtypeQuestionVo> rtnqlist = new ArrayList<>();//保存处理后的试题
            String qpid = "";//母题id
            List<MsPaperQtypeQuestionVo> sonqlist;
            for(MsPaperQtypeQuestionVo q : qlist){
                //试题类型1单题2母题3子题
                if(q.getQlevel() == 3){
                    if(!q.getQuestionpid().equals(qpid)){
                        sonqlist = qlist.stream().filter(o -> q.getQlevel()==3 && q.getQuestionpid().equals(o.getQuestionpid())).collect(Collectors.toList());
                        MsPaperQtypeQuestionVo mq = new MsPaperQtypeQuestionVo();
                        mq.setQuestionid(q.getQuestionpid());
                        mq.setCtype(q.getMctype());
                        mq.setQtypeid(q.getMqtypeid());
                        mq.setQtypename(q.getMqtypename());
                        mq.setQstem(q.getMqstem());
                        mq.setComplexity(q.getMcomplexity());
                        mq.setQanalyze(q.getMqanalyze());
                        mq.setQanswer(q.getMqanswer());
                        mq.setQorder(q.getQorder());
                        mq.setQlevel(q.getMqlevel());
                        mq.setHashear(q.getMhashear());
                        mq.setHearfile(q.getMhearfile());
                        Double mscore = sonqlist.stream().mapToDouble(MsPaperQtypeQuestionVo::getQscore).sum();
                        mq.setQscore(mscore);

                        for(MsPaperQtypeQuestionVo sonQ : sonqlist){
                            if(N_Utils.isNotEmpty(sonQ.getAnswer())){
                                //如果试卷已有答案，把试卷中设置的答案返回
                                sonQ.setQanswer(sonQ.getAnswer());
                            }
                        }

                        mq.setSonques(sonqlist);
                        mq.setPoints(sonqlist.get(0).getPoints());
                        rtnqlist.add(mq);
                    }
                    qpid = q.getQuestionpid();
                }else{
                    if(N_Utils.isNotEmpty(q.getAnswer())){
                        //如果试卷已有答案，把试卷中设置的答案返回
                        q.setQanswer(q.getAnswer());
                    }
                    rtnqlist.add(q);
                }
            }
            qt.setQuestions(rtnqlist);
        }
    }

    // 试卷详情-附件-设置返回值
    private void setPaperQuestionQtypeQuesitonFj(List<MsPaperQtypeVo> qtypelist, List<Map<String, Object>> qtypes) {
        for (MsPaperQtypeVo qtypeVo : qtypelist) {
            List<MsPaperQtypeQuestionVo> questions = qtypeVo.getQuestions();
            List<Map<String, Object>> questionsList = new ArrayList<>();
            for (MsPaperQtypeQuestionVo questionVo : questions) {
                Map<String, Object> questionMap = new TreeMap<>();
                questionMap.put("mptqid", questionVo.getMptqid());
                questionMap.put("qorder", questionVo.getQorder());
                questionMap.put("qn", questionVo.getQn());
                questionMap.put("qscore", questionVo.getQscore());
                questionMap.put("ctype", questionVo.getCtype());
                questionMap.put("qtypename", questionVo.getQtypename());
                questionMap.put("qanswer", questionVo.getQanswer());
                questionMap.put("loseoption", questionVo.getLoseoption());
                questionMap.put("scoreset", questionVo.getScoreset());
                questionMap.put("complexity", questionVo.getComplexity());
                questionMap.put("optionnum", questionVo.getOptionnum());
                questionMap.put("points", questionVo.getPoints());
                questionsList.add(questionMap);
            }

            Map<String, Object> typeMap = new TreeMap<>();
            typeMap.put("mptid", qtypeVo.getMptid());
            typeMap.put("mptqn", qtypeVo.getMptqn());
            typeMap.put("mptname", qtypeVo.getMptname());
            typeMap.put("mptorder", qtypeVo.getMptorder());
            typeMap.put("mptnum", qtypeVo.getMptnum());
            typeMap.put("mptscore", qtypeVo.getMptscore());
            typeMap.put("ctype", qtypeVo.getCtype());
            typeMap.put("questions", questionsList);
            qtypes.add(typeMap);
        }
    }


    /*
     * @Description 获取试卷中所有主观题（题型-试题）
     * @Date 2024/10/21 13:50:54
     * @Author WN
     * @Param [mpid]
     * @Return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
     **/
    public List<Map<String, Object>> listPaperSubjectiveQuestions(Integer mpid,Integer qtype) {
        MsPaper paper = msPaperMapper.selectByPrimaryKey(mpid);
        List<Map<String, Object>> rtnList;
        if (paper.getPtype() == 1) {
            rtnList = msPaperQtypeMapper.listSubjectiveQuestionsTk(mpid, qtype);
        } else {
            rtnList = msPaperQtypeMapper.listSubjectiveQuestionsFj(mpid, qtype);
        }

        return rtnList;
    }

    /*
     * @Description 试卷文件-原卷或答案
     * @Date 2024/11/14 10:39:08
     * @Author WN
     * @Param [mpid, filetype]
     * @Return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
     **/
    public List<Map<String, Object>> listFileByFiletype(Integer mpid, Integer filetype) {
        return msPaperFileMapper.listFileByFiletype(mpid, filetype);
    }

    /*
     * @Description 线下试卷-保存题型及试题
     * @Date 2024/12/3 16:11:09
     * @Author WN
     * @Param [paper]
     * @Return com.xhkjedu.vo.ResultVo
     **/
    @Transactional(rollbackFor = Exception.class)
    public ResultVo saveQtypeQuestionOffline(MsPaperQtype paperQtype) {
        Integer mpid = paperQtype.getMpid();

        // 根据试卷ID获取考试信息
        PExamSubjectVo exam = msPaperMapper.getExamSubjectForPaper(mpid);
        // 线下考试，发布成绩（生成报告）之前可以修改试卷结构
        if (exam.getExammode() < 3 && exam.getExamstate() > 2) {
            throw new MissingParametersException("考试已统分禁止操作");
        }

        Integer timestamp = N_Utils.getSecondTimestamp();
        paperQtype.setCreatetime(timestamp);
        // 保存题型
        msPaperQtypeMapper.insertUseGeneratedKeys(paperQtype);
        Integer mptid = paperQtype.getId();
        List<MsPaperQtypeQuestion> qtypeQuestions = paperQtype.getQuestions();
        for (MsPaperQtypeQuestion que : qtypeQuestions) {
            que.setMptid(mptid);
            que.setMpid(mpid);
            que.setPagenum(0);
            if (N_Utils.isObjectiveQuestion(que.getCtype())) {
                que.setQtype(1);
            } else {
                que.setQtype(2);
            }
            que.setQnstr(paperQtype.getMptqn() + "." + que.getQn());
            if(que.getScoreset() == null) que.setScoreset(0);
            if(que.getLoseoption() == null) que.setLoseoption(0.0);
        }
        msPaperQtypeQuestionMapper.insertList(qtypeQuestions);

        MsPaper paper = new MsPaper();
        paper.setMpid(mpid);
        paper.setPtype(2);
        paper.setHandletime(timestamp);

        // 设置试卷题目数量和分值
        setPaperNumAndScore(paper);
        msPaperMapper.updateByPrimaryKeySelective(paper);

        msPaperAnalyzeService.savePaperAnalyzeForFj(paper);

        if (exam.getPstate() != 2) {
            // 更改科目状态
            msSubjectMapper.updatePstateByMpid(mpid, 2);
        }
        deletePaperOtherInfo(mpid);

        return new ResultVo(0, "保存成功", paper.getMpid());
    }

    // 操作线下试卷-删除后续批阅教师、题块、学生试题、试卷模板
    private void deletePaperOtherInfo(Integer mpid) {
        msPaperCheckTeacherMapper.deleteByMpid(mpid);// 删除批阅教师
        // 如果是线下考试更改了试卷结构，则清空题块、试卷模板
        msPaperMapper.deleteTemplageBlockByMpid(mpid);
        msPaperStudentMapper.deletePaperStuByMpid(mpid);
        msSubjectMapper.updatePaperFollowup(mpid);
    }

    // 操作线下试卷-设置试卷试题数量和分值
    private void setPaperNumAndScore(MsPaper paper) {
        // 获取保存的所有试题
        List<MsPaperQtypeQuestion> qtypeQuestions = msPaperQtypeQuestionMapper.listQuestionsByMpid(paper.getMpid());
        paper.setPnum(qtypeQuestions.size());
        paper.setPscore(qtypeQuestions.stream().mapToDouble(MsPaperQtypeQuestion::getQscore).sum());
    }

    /*
     * @Description 线下试卷-修改题型及试题
     * @Date 2024/12/3 17:02:40
     * @Author WN
     * @Param [paperQtype]
     * @Return com.xhkjedu.vo.ResultVo
     **/
    @Transactional(rollbackFor = Exception.class)
    public ResultVo updateQtypeQuestionOffline(MsPaperQtype paperQtype) {
        Integer mpid = paperQtype.getMpid();

        // 根据试卷ID获取考试信息
        PExamSubjectVo exam = msPaperMapper.getExamSubjectForPaper(mpid);
        // 线下考试，发布成绩（生成报告）之前可以修改试卷结构
        if (exam.getExammode() < 3 && exam.getExamstate() > 2) {
            throw new MissingParametersException("考试已统分禁止操作");
        }

        Integer timestamp = N_Utils.getSecondTimestamp();
        paperQtype.setCreatetime(timestamp);
        // 保存题型
        msPaperQtypeMapper.updateByPrimaryKeySelective(paperQtype);
        // 删除题型下原有试题
        msPaperQtypeQuestionMapper.deleteByMptid(paperQtype.getMptid());

        Integer mptid = paperQtype.getMptid();
        List<MsPaperQtypeQuestion> qtypeQuestions = paperQtype.getQuestions();
        for (MsPaperQtypeQuestion que : qtypeQuestions) {
            que.setMptid(mptid);
            que.setMpid(mpid);
            que.setPagenum(0);
            if (N_Utils.isObjectiveQuestion(que.getCtype())) {
                que.setQtype(1);
            } else {
                que.setQtype(2);
            }
            if(que.getScoreset() == null) que.setScoreset(0);
            if(que.getLoseoption() == null) que.setLoseoption(0.0);
            que.setQnstr(paperQtype.getMptqn() + "." + que.getQn());
        }
        msPaperQtypeQuestionMapper.insertList(qtypeQuestions);

        MsPaper paper = new MsPaper();
        paper.setMpid(mpid);
        paper.setPtype(2);
        paper.setHandletime(timestamp);

        // 设置试卷题目数量和分值
        setPaperNumAndScore(paper);
        msPaperMapper.updateByPrimaryKeySelective(paper);

        // 试卷中小题重新排序
        chandleQuestionOrder(paper);

        msPaperAnalyzeService.savePaperAnalyzeForFj(paper);
        deletePaperOtherInfo(mpid);

        return new ResultVo(0, "保存成功", paper.getMpid());
    }

    /*
     * @Description 线下试卷-删除题型
     * @Date 2024/12/3 17:15:42
     * @Author WN
     * @Param [paperQtype]
     * @Return void
     **/
    @Transactional(rollbackFor = Exception.class)
    public ResultVo deleteQtypeOffline(MsPaperQtype paperQtype) {
        // 根据试卷ID获取考试信息
        PExamSubjectVo exam = msPaperMapper.getExamSubjectForPaper(paperQtype.getMpid());
        // 线下考试，发布成绩（生成报告）之前可以修改试卷结构
        if (exam.getExammode() < 3 && exam.getExamstate() > 2) {
            throw new MissingParametersException("考试已统分禁止操作");
        }

        msPaperQtypeMapper.deleteByPrimaryKey(paperQtype.getMptid());
        MsPaper paper = new MsPaper();
        paper.setMpid(paperQtype.getMpid());

        // 处理试卷试题数量和分值，题型排序，试题排序
        chandlePaperNumQtypeOrder(paper);

        // 重新生成试卷分析
        msPaperAnalyzeService.savePaperAnalyzeForFj(paper);
        return new ResultVo(0, "删除成功", paper.getMpid());
    }

    // 处理试卷试题数量和分值，题型排序，试题排序
    private void chandlePaperNumQtypeOrder(MsPaper paper) {
        // 获取试卷中题型和试题重新排序
        List<MsPaperQtype> qtypes = msPaperQtypeMapper.listQtypeQuestionSimple(paper.getMpid());
        int pnum = 0;
        double pscore = 0;
        if (qtypes != null && !qtypes.isEmpty()) {
            int mptorder = 1;// 题型排序
            int qorder = 1;// 试题排序
            List<MsPaperQtypeQuestion> saveQues = new ArrayList<>();
            for (MsPaperQtype qtype : qtypes) {
                qtype.setMptorder(mptorder);
                mptorder++;
                List<MsPaperQtypeQuestion> questions = qtype.getQuestions();
                for (MsPaperQtypeQuestion question : questions) {
                    question.setQorder(qorder);
                    qorder++;
                    pnum++;
                    pscore = MarkingUtil.add(pscore, question.getQscore());
                    saveQues.add(question);
                }
            }
            // 保存试题排序
            msPaperQtypeQuestionMapper.updateBatchQuestionOrder(saveQues);
            // 保存题型排序
            msPaperQtypeMapper.updateBatchQtypeOrder(qtypes);
        }
        paper.setPnum(pnum);
        paper.setPscore(pscore);
        msPaperMapper.updateByPrimaryKeySelective(paper);
    }

    // 处理试卷中小题排序
    private void chandleQuestionOrder(MsPaper paper) {
        // 小题重新排序
        List<MsPaperQtypeQuestion> queOrders = msPaperQtypeQuestionMapper.listQuesOrderByMpid(paper.getMpid());
        int qorder = 1;
        int pnum = 0;
        double pscore = 0;
        for (MsPaperQtypeQuestion que : queOrders) {
            que.setQorder(qorder);
            qorder++;
            pnum++;
            pscore = MarkingUtil.add(pscore, que.getQscore());
        }
        paper.setPnum(pnum);
        paper.setPscore(pscore);
        msPaperQtypeQuestionMapper.updateBatchQuestionOrder(queOrders);
    }


    /*
     * @Description 线下试卷-题型上下移动
     * @Date 2024/12/4 10:30:51
     * @Author WN
     * @Param [params]
     * @Return void
     **/
    @Transactional(rollbackFor = Exception.class)
    public void updateQtypeOrderOffline(MsPaperParams params) {

        // 根据试卷ID获取考试信息
        PExamSubjectVo exam = msPaperMapper.getExamSubjectForPaper(params.getMpid());
        // 线下考试，发布成绩（生成报告）之前可以修改试卷结构
        if (exam.getExammode() < 3 && exam.getExamstate() > 2) {
            throw new MissingParametersException("考试已统分禁止操作");
        }

        MsPaperQtype moveQtype = new MsPaperQtype();// 要移动的题型
        moveQtype.setMptid(params.getMptid());

        int movevalue;// 移动试题的order变换值
        int bmovevalue;// 被移动试题的order变换值
        if (params.getMovetype() == 1) { // 上移
            movevalue = -1;// 在原来基础上减一
            bmovevalue = 1;
        } else {
            movevalue = 1;// 在原来基础上加一
            bmovevalue = -1;
        }
        params.setMovevalue(movevalue);
        moveQtype.setMptorder(movevalue);
        // 被交换位置的试题
        MsPaperQtype qtype = msPaperQtypeMapper.getQtypeForMoverOrder(params);
        if(qtype == null){
            throw new RuntimeException("请检查移动是否合理");
        }
        qtype.setMptorder(bmovevalue);

        List<MsPaperQtype> changeQuestions = new ArrayList<>();
        changeQuestions.add(moveQtype);
        changeQuestions.add(qtype);
        msPaperQtypeMapper.updateBatchMoveQtypeOrder(changeQuestions);

        MsPaper paper = new MsPaper();
        paper.setMpid(params.getMpid());
        chandleQuestionOrder(paper);// 小题重新排序

        rebuildPaperAnalyzeOffline(paper.getMpid(), paper);
    }

    /*
     * @Description 线下试卷-修改试题
     * @Date 2024/12/3 17:54:04
     * @Author WN
     * @Param [question]
     * @Return void
     **/
    @Transactional(rollbackFor = Exception.class)
    public void updateQuestionOffline(MsPaperQtypeQuestion question) {

        // 根据试卷ID获取考试信息
        PExamSubjectVo exam = msPaperMapper.getExamSubjectForPaper(question.getMpid());
        // 线下考试，发布成绩（生成报告）之前可以修改试卷结构
        if (exam.getExammode() < 3 && exam.getExamstate() > 2) {
            throw new MissingParametersException("考试已统分禁止操作");
        }

        // 获取原小题信息
        MsPaperQtypeQuestion oldQuestion = msPaperQtypeQuestionMapper.selectByPrimaryKey(question.getMptqid());
        // 修改小题信息
        msPaperQtypeQuestionMapper.updateByPrimaryKeySelective(question);
        if (!oldQuestion.getQscore().equals(question.getQscore())) {
            // 说明修改题型和试卷分值
            msPaperQtypeMapper.updateQtypeScore(question.getMptid(), question.getMpid());

            // 重新生成试卷分析
            rebuildPaperAnalyzeOffline(question.getMpid(), null);
        }
    }

    /*
     * @Description 线下试卷-删除试题
     * @Date 2024/12/3 17:59:21
     * @Author WN
     * @Param [question]
     * @Return void
     **/
    @Transactional(rollbackFor = Exception.class)
    public void deleteQuestionOffline(MsPaperQtypeQuestion question) {
        // 根据试卷ID获取考试信息
        PExamSubjectVo exam = msPaperMapper.getExamSubjectForPaper(question.getMpid());
        // 线下考试，发布成绩（生成报告）之前可以修改试卷结构
        if (exam.getExammode() < 3 && exam.getExamstate() > 2) {
            throw new MissingParametersException("考试已统分禁止操作");
        }
        Integer mptid = question.getMptid();
        msPaperQtypeQuestionMapper.deleteByPrimaryKey(question.getMptqid());
        // 获取题型下试题数量
        int qnum = msPaperQtypeQuestionMapper.getQuesnumByMptid(mptid);
        MsPaper paper = new MsPaper();
        paper.setMpid(question.getMpid());

        if (qnum == 0) {
            // 删除题型
            msPaperQtypeMapper.deleteByPrimaryKey(mptid);
            // 处理试卷试题数量和分值，题型排序，试题排序
            chandlePaperNumQtypeOrder(paper);
        } else {
            // 修改题型和试卷分值
            msPaperQtypeMapper.updateQtypeScoreAndNum(mptid, question.getMpid());
            // 小题重新排序
            chandleQuestionOrder(paper);
        }

        // 重新生成试卷分析
        rebuildPaperAnalyzeOffline(question.getMpid(), paper);
        deletePaperOtherInfo(question.getMpid());
    }

    /*
     * @Description 线下试卷-试题上下移动
     * @Date 2024/12/4 10:13:29
     * @Author WN
     * @Param [params]
     * @Return void
     **/
    @Transactional(rollbackFor = Exception.class)
    public void updateQuestionOrderOffline(MsPaperParams params) {
        // 根据试卷ID获取考试信息
        PExamSubjectVo exam = msPaperMapper.getExamSubjectForPaper(params.getMpid());
        // 线下考试，发布成绩（生成报告）之前可以修改试卷结构
        if (exam.getExammode() < 3 && exam.getExamstate() > 2) {
            throw new MissingParametersException("考试已统分禁止操作");
        }
        MsPaperQtypeQuestion moveQuestion = new MsPaperQtypeQuestion();// 要移动的试题
        moveQuestion.setMptqid(params.getMptqid());

        int movevalue;// 移动试题的order变换值
        int bmovevalue;// 被移动试题的order变换值
        if (params.getMovetype() == 1) { // 上移
            movevalue = -1;// 在原来基础上减一
            bmovevalue = 1;
        } else {
            movevalue = 1;// 在原来基础上加一
            bmovevalue = -1;
        }
        params.setMovevalue(movevalue);
        moveQuestion.setQorder(movevalue);
        // 被交换位置的试题
        MsPaperQtypeQuestion question = msPaperQtypeQuestionMapper.getQuestionForMoverOrder(params);
        if(question == null){
            throw new RuntimeException("请检查移动是否合理");
        }
        question.setQorder(bmovevalue);

        List<MsPaperQtypeQuestion> changeQuestions = new ArrayList<>();
        changeQuestions.add(moveQuestion);
        changeQuestions.add(question);
        msPaperQtypeQuestionMapper.updateBatchMoveQuestionOrder(changeQuestions);

        // 重新生成报告
        rebuildPaperAnalyzeOffline(params.getMpid(), null);
    }

    // 重新生产线下试卷分析
    private void rebuildPaperAnalyzeOffline(Integer mpid, MsPaper paper) {
        if (paper == null || !N_Utils.isTrueInteger(paper.getPnum())) {
            paper = msPaperMapper.selectByPrimaryKey(mpid);
        }
        msPaperAnalyzeService.savePaperAnalyzeForFj(paper);
    }
}
