package com.xhkjedu.sexam.service.paper;

import com.alibaba.fastjson.JSON;
import com.xhkjedu.exception.MissingParametersException;
import com.xhkjedu.sexam.mapper.exam.ESubjectMapper;
import com.xhkjedu.sexam.mapper.paper.*;
import com.xhkjedu.sexam.mapper.paperstudent.EPaperStudentMapper;
import com.xhkjedu.sexam.mapper.paperstudent.EPaperStudentQuestionMapper;
import com.xhkjedu.sexam.mapper.system.UserBasketMapper;
import com.xhkjedu.sexam.model.paper.*;
import com.xhkjedu.sexam.model.paperstudent.EPaperStudentQuestion;
import com.xhkjedu.sexam.utils.ConvertUtil;
import com.xhkjedu.sexam.utils.ExamUtil;
import com.xhkjedu.sexam.vo.paper.*;
import com.xhkjedu.utils.N_Utils;
import com.xhkjedu.vo.ResultVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description 题库题型
 * @Author WN
 * Date 2022/7/19 9:07
 **/
@Service
@Slf4j
public class EPaperQtypeService {
    @Resource
    private EPaperQtypeMapper ePaperQtypeMapper;
    @Resource
    private EPaperQtypeQuestionMapper ePaperQtypeQuestionMapper;
    @Resource
    private EPaperMapper ePaperMapper;
    @Resource
    private EPaperAnalyzeMapper ePaperAnalyzeMapper;
    @Resource
    private ESubjectMapper eSubjectMapper;
    @Resource
    private EPaperFileMapper ePaperFileMapper;
    @Resource
    private UserBasketMapper userBasketMapper;
    @Resource
    private EPaperStudentQuestionMapper ePaperStudentQuestionMapper;
    @Resource
    private EPaperStudentMapper ePaperStudentMapper;
    @Autowired
    private ConvertUtil convertUtil;


    /**
     * @Description 保存题库试卷
     * @Param [paper]
     * @Return void
     * @Author wn
     * @Date 2022/7/19 9:10
     **/
    @Transactional(rollbackFor = Exception.class)
    public ResultVo saveQtPaper(EPaper paper) {
        Integer examstate = ePaperMapper.getExamStateByEpId(paper.getEpid());
        if (2 <= examstate) throw new MissingParametersException("考试已结束禁止操作");
        //获取考试科目信息
        EExamSubjectPaperVo espVo = ePaperMapper.getPaperParamsByEpid(paper.getEpid());
        if (espVo.getExamstate() > 0) {
            return new ResultVo(1, "不能进行操作");
        }

        List<EPaperQtype> qtypelist = paper.getQtypelist();
        /*if (paper.getPtype() == 2) {
            List<EPaperQtypeQuestion> questions = new ArrayList<>();
            qtypelist.forEach(t -> {
                questions.addAll(t.getQuestions());
            });
            long count = questions.stream().map(q -> q.getQn()).distinct().count();
            if (count < questions.size()) return new ResultVo(1, "题号不能重复");
        }*/

        //说明已经有改考试对应的试卷，删除试卷中试题，试卷分析
        ePaperQtypeMapper.deleteByEpid(espVo.getEpid());
        ePaperAnalyzeMapper.deleteByEpid(espVo.getEpid());
        ePaperFileMapper.deleteByEpid(espVo.getEpid());

        List<EPaperQtypeQuestion> queslist = new ArrayList<>();//存放试题
        paper.setEpid(espVo.getEpid());
        setEPaperBaseDetail(paper,qtypelist);
        Integer correcttype = espVo.getCorrecttype();
        if(correcttype.equals(2)) {//按题设置要重新设置批阅方式
            paper.setCorrecttype(0);
        }else {
            paper.setCorrecttype(correcttype);
        }
        //保存试卷信息
        ePaperMapper.updatePaperInfo(paper);
        //保存题型试题信息
        savePaperQtype(paper,qtypelist,queslist);
        List<String> imgs = new ArrayList<>();

        //保存试卷分析
        if(paper.getPtype() == 1){
            savePaperAnalyzeForQuestion(paper);
        }else{
            List<EPaperFile> pfiles = paper.getPfiles();//附件
            if(paper.getHasfile() == 1){
                setPaperFiles(paper,pfiles,imgs);
                ePaperFileMapper.insertList(pfiles);
            }
            savePaperAnalyzeForFj(paper,qtypelist,queslist);
        }

        //更加试卷状态是否需要生成分析和更改科目状态
        if(espVo.getExammode() == 1 && paper.getPstate()!=null && paper.getPstate() == 1){
            //如果提交试卷，更改科目状态
            eSubjectMapper.updateExamSubjectState(1,espVo.getEsid());
        }
        //保存后清除试题栏中试题
        userBasketMapper.deleteByUseridAndSubjectid(paper.getCreateid(),espVo.getSubjectid());

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

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

    //设置试卷基本信息
    private void setEPaperBaseDetail(EPaper paper,List<EPaperQtype> qtypelist){
        if(paper.getPtype() == 2 && paper.getPfiles()!=null && paper.getPfiles().size()>0){
            paper.setHasfile(1);
        }else {
            paper.setHasfile(0);
        }
        int timestamp = N_Utils.getSecondTimestamp();
        double pscore = qtypelist.stream().collect(Collectors.summingDouble(EPaperQtype:: getEptscore));
        int pnum = qtypelist.stream().collect(Collectors.summingInt(EPaperQtype:: getEptnum));
        paper.setPnum(pnum);
        paper.setPscore(pscore);
        paper.setCreatetime(timestamp);
        paper.setHandletime(timestamp);
        paper.setHandleid(paper.getCreateid());
        if(paper.getPtype() == 1){
            paper.setAnswered(1);//题库已设置正确答案
        }else{
            paper.setAnswered(0);
        }

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

    //保存试卷题型试题信息
    private void savePaperQtype(EPaper epaper,List<EPaperQtype> qtypelist,List<EPaperQtypeQuestion> qtqs){
        for(EPaperQtype qtype : qtypelist){
            qtype.setEpid(epaper.getEpid());
            qtype.setCreateid(epaper.getHandleid());
            qtype.setCreatetime(epaper.getHandletime());
            qtype.setEptname(N_Utils.strTrim(qtype.getEptname()));
        }
        ePaperQtypeMapper.insertList(qtypelist);//保存题型
        for(EPaperQtype qtype : qtypelist){
            List<EPaperQtypeQuestion> questions = qtype.getQuestions();
            qtype.setEptid(qtype.getId());

            for (int i = 0; i < questions.size(); i++) {
                EPaperQtypeQuestion q=questions.get(i);
                q.setEpid(epaper.getEpid());
                q.setEptid(qtype.getId());
                if(q.getOptionnum()==null){
                    q.setOptionnum(0);
                }

                if(q.getCtype() == 14){
                    q.setGnum(900);//语文作文格数
                }else if(q.getCtype() == 15){
                    q.setGnum(10);//英语作文行数
                }

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

    //设置附件
    private void setPaperFiles(EPaper paper,List<EPaperFile> pfiles,List<String> imgs) {
        if(paper.getHasfile() == 1){
            int order= 1;
            for(EPaperFile pf :pfiles){
                pf.setCreateid(paper.getCreateid());
                pf.setCreatetime(paper.getHandletime());
                pf.setEpid(paper.getEpid());
                pf.setFileorder(order);
                order ++;

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

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

    }

    //保存试卷分析--题库
    public void savePaperAnalyzeForQuestion(EPaper ePaper){
        //保存之前先清除之前的试卷分析
        ePaperAnalyzeMapper.deleteByEpid(ePaper.getEpid());
        //总体分析（主观题、客观题）
        List<EPaperQtypeVo> qtypelist = ePaperQtypeMapper.listPaperQtypeQuestions(ePaper.getEpid());//试卷题型试题信息
        List<EPaperQtypeQuestion> uplist = new ArrayList<>();//改试卷中客观题选项数量
        List<QuestionOrderVo> pointqlist = new ArrayList<>();//用于存放知识点，以及知识点下得分
        List<EPaperQtypeQuestionVo> mquestions = new ArrayList<>();//存放单题和母题
        List<QuestionOrderVo> complexitylist = new ArrayList<>();//试题难易度存放试题
        List<QuestionPointVo> quesplist = new ArrayList<>();//单题、母题对应知识点

        //处理出试卷中所有试题、知识点
        List<Map> typelist = new ArrayList<>();//题型分析
        for(EPaperQtypeVo qt : qtypelist){
            List<Integer> qorderlist = new ArrayList<>();
            List<QuestionOrderVo> qtypeqlist = new ArrayList<>();
            List<EPaperQtypeQuestionVo> tqlist = qt.getQuestions();
            int hasmt = 0;
            for(EPaperQtypeQuestionVo q : tqlist){
                int ctype = q.getCtype();
                //单题的pid设置为默认值，方便后续进行单题和母题处理
                if(q.getQlevel()==1){
                    q.setQuestionpid("000");
                    //判断试题是否是客观题
                    if(N_Utils.isObjectiveQuestion(ctype)){
                        //判断试题是否是客观题,暂时用mctype进行标识
                        q.setMctype(111);
                    }else{
                        q.setMctype(112);
                    }
                    //设置知识点
                    mquestions.add(q);
                    //获取试题知识点
                    List<Map> qpoints = q.getPoints();
                    //处理试题知识点占分
                    setPaperQuestionPointScore(pointqlist,quesplist,qpoints,q,null,null);
                    setPaperQuestionQtypeScore(qtypeqlist,q,null,null);//处理试题题型
                    setPaperQuestionComplexityScore(complexitylist,q,null,null);//处理试题难易度
                }
                if(q.getQlevel() == 3){
                    hasmt ++;
                }
                if(!qorderlist.contains(q.getQorder())){
                    qorderlist.add(q.getQorder());
                }
                //为了处理客观题中选项数量
                if(ctype == 1 || ctype ==2 || ctype==4 || ctype ==5 || ctype==6){
                    List<String> strlst = JSON.parseArray(q.getQoption(),String.class);
                    EPaperQtypeQuestion eqq = new EPaperQtypeQuestion();
                    eqq.setEptqid(q.getEptqid());
                    eqq.setOptionnum(strlst.size());
                    uplist.add(eqq);
                }
            }

            if(hasmt > 0){
                //说明该题型下有复合题,复合体进行知识点、题型下试题题号及id进行操作
                LinkedHashMap<String,List<EPaperQtypeQuestionVo>> quesMap = tqlist.stream().collect(Collectors.groupingBy(EPaperQtypeQuestionVo:: getQuestionpid,LinkedHashMap::new, Collectors.toList()));
                for(Map.Entry<String, List<EPaperQtypeQuestionVo>> entry : quesMap.entrySet()){
                    if(!entry.getKey().equals("000")){
                        //说明该题为母题，
                        EPaperQtypeQuestionVo mq = new EPaperQtypeQuestionVo();
                        List<EPaperQtypeQuestionVo> sonques = entry.getValue();
                        int k = 0;//如果k大于1说明有小题是主观题，则母题为主观题
                        double score = 0;
                        for(EPaperQtypeQuestionVo sq : sonques){
                            if(!N_Utils.isObjectiveQuestion(sq.getCtype())){
                                k++;
                            }
                            score = N_Utils.getDoubleSum(score,sq.getScore());
                        }

                        EPaperQtypeQuestionVo qobj = sonques.get(0);
                        mq.setQuestionid(qobj.getQuestionpid());
                        mq.setComplexity(qobj.getMcomplexity());
                        mq.setQorder(qobj.getQorder());
                        mq.setScore(score);
                        mq.setQtypename(qobj.getMqtypename());
                        if(k == 0){
                            mq.setMctype(111);
                        }else{
                            mq.setMctype(112);
                        }
                        mq.setQlevel(qobj.getMqlevel());
                        mq.setSonques(sonques);
                        //获取所有子题的试题题号
                        List<String> qns = sonques.stream().map(EPaperQtypeQuestionVo::getQn).collect(Collectors.toList());
                        String[] qnstr = qns.stream().toArray(String[]::new);
                        //所有子题的试题eptqid
                        List<Integer> eptqids = sonques.stream().map(EPaperQtypeQuestionVo::getEptqid).collect(Collectors.toList());
                        Integer[] eptqidstr = eptqids.stream().toArray(Integer[]::new);

                        //获取知识点
                        List<Map> qpoints = sonques.get(0).getPoints();
                        mq.setPoints(qpoints);
                        mquestions.add(mq);
                        setPaperQuestionPointScore(pointqlist,quesplist,qpoints,mq,qnstr,eptqids);
                        setPaperQuestionQtypeScore(qtypeqlist,mq,qnstr,eptqidstr);//处理试题题型
                        setPaperQuestionComplexityScore(complexitylist,mq,qnstr,eptqidstr);//处理试题难易度
                    }
                }
            }

            //试题题型分析数据
            double storerate = N_Utils.getDoubleDivideAndMulitiply(qt.getEptscore(), ePaper.getPscore());
            Map tmap = new TreeMap();
            tmap.put("qtid",qt.getEptid());
            tmap.put("qtname",qt.getEptname());
            tmap.put("num",qt.getEptnum());
            tmap.put("score",qt.getEptscore());
            tmap.put("srate",storerate);
            qtypeqlist = qtypeqlist.stream().sorted(Comparator.comparing(QuestionOrderVo::getOrder)).collect(Collectors.toList());
            tmap.put("ques",qtypeqlist);
            typelist.add(tmap);
        }

        //进行客观题选项处理
        if(N_Utils.isListNotEmpty(uplist)){
            ePaperQtypeQuestionMapper.updateBatchQuestionOptionnum(uplist);
        }

        //试题总体分布进行分析
        //客观题集合
        List<EPaperQtypeQuestionVo> ktlst = mquestions.stream().filter(q->q.getMctype() == 111).collect(Collectors.toList());
        int ktnum = ktlst.size();
        double ktscore = ktlst.stream().collect(Collectors.summingDouble(EPaperQtypeQuestionVo:: getScore));
        double ktnrate = N_Utils.getIntegerDivideAndMulitiply(ktnum, ePaper.getPnum());
        double ktsrate = N_Utils.getDoubleDivideAndMulitiply(ktscore, ePaper.getPscore());
        List<EPaperQsVo> ranglist = new ArrayList<>();
        ranglist.add(new EPaperQsVo("客观题",ktscore,ktnum,ktsrate,ktnrate));
        EPaperQsVo zgq = new EPaperQsVo();
        zgq.setQtname("主观题");
        zgq.setNum(ePaper.getPnum() - ktnum);
        zgq.setNrate(N_Utils.getDoubleReduce(100.0,ktnrate));
        zgq.setScore(N_Utils.getDoubleReduce(ePaper.getPscore(),ktscore));
        zgq.setSrate(N_Utils.getDoubleReduce(100.0,ktsrate));
        ranglist.add(zgq);
        Map ztmap = new TreeMap<>();
        ztmap.put("pnum", ePaper.getPnum());
        ztmap.put("pscore",ePaper.getPscore());
        ztmap.put("ranglist",ranglist);

        //难易度
        List<Map> clist = new ArrayList<>();
        if(N_Utils.isListNotEmpty(complexitylist)){
            Map<String,List<QuestionOrderVo>> complxmap =  complexitylist.stream().collect(Collectors.groupingBy(QuestionOrderVo:: getId, Collectors.toList()));
            for(Map.Entry<String, List<QuestionOrderVo>> entry : complxmap.entrySet()){
                List<QuestionOrderVo> pgblist = entry.getValue();
                Double score = pgblist.stream().mapToDouble(s -> s.getScore()).sum();
                score = N_Utils.formatDouble(score,1);
                Double srate = N_Utils.getDoubleDivideAndMulitiply(score,ePaper.getPscore());
                Map prate = new TreeMap();
                prate.put("level",Integer.parseInt(entry.getKey()));
                prate.put("score",score);
                prate.put("srate",srate);
                prate.put("ques",pgblist.stream().sorted(Comparator.comparing(QuestionOrderVo::getOrder)).collect(Collectors.toList()));
                clist.add(prate);
            }
        }

        //知识点分析
        List<Map> pointlist = new ArrayList<>();
        if(N_Utils.isListNotEmpty(pointqlist)){
            LinkedHashMap<String,List<QuestionOrderVo>> pointmap = pointqlist.stream().collect(Collectors.groupingBy(QuestionOrderVo::getId,LinkedHashMap::new,Collectors.toList()));
            //根据指示进行分组，
            for(Map.Entry<String, List<QuestionOrderVo>> entry : pointmap.entrySet()){
                List<QuestionOrderVo> pgblist = entry.getValue();
                //获取知识点的总分
                Double score = pgblist.stream().mapToDouble(s -> s.getScore()).sum();
                score = N_Utils.formatDouble(score,1);
                Double srate = N_Utils.getDoubleDivideAndMulitiply(score,ePaper.getPscore());
                Map prate = new LinkedHashMap();
                prate.put("pointid",entry.getKey());
                prate.put("pointname",pgblist.get(0).getName());
                prate.put("score",score);
                prate.put("srate",srate);
                prate.put("ques",pgblist.stream().sorted(Comparator.comparing(QuestionOrderVo::getOrder)).collect(Collectors.toList()));
                pointlist.add(prate);
            }
        }

        EPaperAnalyze epa = new EPaperAnalyze();
        epa.setEpid(ePaper.getEpid());
        epa.setAlljson(JSON.toJSONString(ztmap));//总体分析
        epa.setQnumjson(JSON.toJSONString(typelist));//试题栏题型分析
        epa.setComplexityjson(JSON.toJSONString(clist));//难易度分析
        epa.setPointjson(JSON.toJSONString(pointlist));//知识点分析
        epa.setQuespointjson(JSON.toJSONString(quesplist));
        ePaperAnalyzeMapper.insertUseGeneratedKeys(epa);
    }

    //设置知识点
    private void setPaperQuestionPointScore(List<QuestionOrderVo> pointqlist,List<QuestionPointVo> quesplist,List<Map> qpoints,EPaperQtypeQuestionVo dq,String[] qnstr,List<Integer> eptqids){
        if(N_Utils.isListNotEmpty(qpoints)){
            if(qpoints.size() == 1){
                //试题只有一个知识点
                Map pointmap = qpoints.get(0);
                QuestionOrderVo qpoint = new QuestionOrderVo();
                qpoint.setId(pointmap.get("pointid").toString());
                qpoint.setName(pointmap.get("pointname").toString());
                qpoint.setOrder(dq.getQorder());
                qpoint.setScore(dq.getScore());
                qpoint.setQlevel(dq.getQlevel());
                qpoint.setQuestionid(dq.getQuestionid());
                if(qnstr == null){
                    qpoint.setQns(new String[]{dq.getQn()});
                }else{
                    qpoint.setQns(qnstr);
                }

                if(N_Utils.isListEmpty(eptqids)){
                    qpoint.setEptqids(new Integer[]{dq.getEptqid()});
                }else{
                    Integer[] eptqidstr = eptqids.stream().toArray(Integer[]::new);
                    qpoint.setEptqids(eptqidstr);
                }
                pointqlist.add(qpoint);

                //试题对应知识点
                QuestionPointVo questionPointVo = new QuestionPointVo();
                questionPointVo.setOrder(dq.getQorder());
                questionPointVo.setScore(dq.getScore());
                questionPointVo.setQlevel(dq.getQlevel());
                questionPointVo.setQuestionid(dq.getQuestionid());
                List<Map> pointids = new ArrayList<>();
                Map map = new HashMap();
                map.put("pointid",pointmap.get("pointid").toString());
                map.put("score",dq.getScore());
                pointids.add(map);
                questionPointVo.setPointids(pointids);

                if(N_Utils.isListEmpty(eptqids)){
                    List<Integer> saveids = new ArrayList<>();
                    saveids.add(dq.getEptqid());
                    questionPointVo.setEptqids(saveids);
                    questionPointVo.setEptqid(dq.getEptqid());
                }else{
                    questionPointVo.setEptqids(eptqids);
                    questionPointVo.setEptqid(0);
                }
                quesplist.add(questionPointVo);
            }else{

                //试题有多个知识点
                //计算每个知识点所占分值（平均分配）
                Double[] avgps = N_Utils.getPointAvgScore(qpoints.size(),dq.getScore());
                List<Map> pointids = new ArrayList<>();
                for(int m = 0; m<qpoints.size();m++){
                    Map pointmap = qpoints.get(m);
                    QuestionOrderVo qpoint = new QuestionOrderVo();
                    qpoint.setId(pointmap.get("pointid").toString());
                    qpoint.setName(pointmap.get("pointname").toString());
                    qpoint.setOrder(dq.getQorder());
                    qpoint.setQlevel(dq.getQlevel());
                    qpoint.setQuestionid(dq.getQuestionid());


                    Map quesmap = new HashMap();//试题对应知识点
                    quesmap.put("pointid",pointmap.get("pointid").toString());

                    if(avgps.length == 2 && (m+1) == qpoints.size()){
                        //不能整除分，并且是最后一个知识点
                        qpoint.setScore(avgps[1]);
                        quesmap.put("score",avgps[1]);
                    }else{
                        qpoint.setScore(avgps[0]);
                        quesmap.put("score",avgps[0]);
                    }
                    pointids.add(quesmap);

                    //题号集合
                    if(qnstr == null){
                        qpoint.setQns(new String[]{dq.getQn()});
                    }else{
                        qpoint.setQns(qnstr);
                    }
                    //试卷中试题id集合
                    if(N_Utils.isListEmpty(eptqids)){
                        qpoint.setEptqids(new Integer[]{dq.getEptqid()});
                    }else{
                        Integer[] eptqidstr = eptqids.stream().toArray(Integer[]::new);
                        qpoint.setEptqids(eptqidstr);
                    }
                    pointqlist.add(qpoint);
                }

                //试题对应知识点
                QuestionPointVo questionPointVo = new QuestionPointVo();
                questionPointVo.setOrder(dq.getQorder());
                questionPointVo.setScore(dq.getScore());
                questionPointVo.setQlevel(dq.getQlevel());
                questionPointVo.setQuestionid(dq.getQuestionid());
                questionPointVo.setPointids(pointids);
                if(N_Utils.isListEmpty(eptqids)){
                    List<Integer> saveids = new ArrayList<>();
                    saveids.add(dq.getEptqid());
                    questionPointVo.setEptqids(saveids);
                    questionPointVo.setEptqid(dq.getEptqid());

                }else{
                    questionPointVo.setEptqids(eptqids);
                    questionPointVo.setEptqid(0);
                }
                quesplist.add(questionPointVo);

            }
        } else{
            QuestionPointVo questionPointVo = new QuestionPointVo();
            questionPointVo.setOrder(dq.getQorder());
            questionPointVo.setScore(dq.getScore());
            questionPointVo.setQlevel(dq.getQlevel());
            questionPointVo.setQuestionid(dq.getQuestionid());
            questionPointVo.setPointids(null);
            if(N_Utils.isListEmpty(eptqids)){
                List<Integer> saveids = new ArrayList<>();
                saveids.add(dq.getEptqid());
                questionPointVo.setEptqids(saveids);
                questionPointVo.setEptqid(dq.getEptqid());
            }else{
                questionPointVo.setEptqids(eptqids);
                questionPointVo.setEptqid(0);
            }

            quesplist.add(questionPointVo);
        }
    }

    //设置题型下试题题号及分值
    private void setPaperQuestionQtypeScore(List<QuestionOrderVo> qtypelist,EPaperQtypeQuestionVo dq,String[] qnstr,Integer[] eptqidstr){
        QuestionOrderVo qtype = new QuestionOrderVo();
        qtype.setId(dq.getQtypeid());
        qtype.setName(dq.getQtypename());
        qtype.setComplexity(dq.getComplexity());
        qtype.setOrder(dq.getQorder());
        qtype.setScore(dq.getScore());
        qtype.setQlevel(dq.getQlevel());
        qtype.setQuestionid(dq.getQuestionid());
        if(qnstr == null){
            qtype.setQns(new String[]{dq.getQn()});
        }else{
            qtype.setQns(qnstr);
        }
        if(eptqidstr == null){
            qtype.setEptqids(new Integer[]{dq.getEptqid()});
        }else{
            qtype.setEptqids(eptqidstr);
        }

        qtypelist.add(qtype);
    }

    //设置试题难易度
    private void setPaperQuestionComplexityScore(List<QuestionOrderVo> complexityList,EPaperQtypeQuestionVo dq,String[] qnstr,Integer[] eptqidstr){
        QuestionOrderVo qtype = new QuestionOrderVo();
        qtype.setId(dq.getComplexity().toString());//存放试题难易度
        qtype.setOrder(dq.getQorder());
        qtype.setScore(dq.getScore());
        qtype.setQlevel(dq.getQlevel());
        qtype.setQuestionid(dq.getQuestionid());
        if(qnstr == null){
            qtype.setQns(new String[]{dq.getQn()});
        }else{
            qtype.setQns(qnstr);
        }
        if(eptqidstr == null){
            qtype.setEptqids(new Integer[]{dq.getEptqid()});
        }else{
            qtype.setEptqids(eptqidstr);
        }

        complexityList.add(qtype);
    }
    //保存试卷分析--附件
    private void savePaperAnalyzeForFj(EPaper ePaper,List<EPaperQtype> fjtypelist,List<EPaperQtypeQuestion> queslist){
        //保存之前先清除之前的试卷分析
        ePaperAnalyzeMapper.deleteByEpid(ePaper.getEpid());
        //总体分析（主观题、客观题）
        //处理题型1单选题2多选题3主观题4判断对错5判断√×6判断TF11综合题12听力13填空题
        int znum = 0;
        double zscore = 0;
        int knum = 0;
        double kscore = 0;
        for(EPaperQtypeQuestion q : queslist){
            if(N_Utils.isObjectiveQuestion(q.getCtype())){
                knum ++;
                kscore = kscore + q.getScore();
            }else{
                znum ++;
                zscore = zscore + q.getScore();
            }
        }

        double znumrate = N_Utils.getIntegerDivideAndMulitiply(znum, ePaper.getPnum());
        double knumrate = N_Utils.getDoubleReduce(100.0, znumrate);

        double zscorerate = N_Utils.getDoubleDivideAndMulitiply(zscore, ePaper.getPscore());
        double kscorerate = N_Utils.getDoubleReduce(100.0,zscorerate);

        List<Map> ranglist = new ArrayList<>();
        Map zgmap = new TreeMap();
        zgmap.put("qtname","主观题");
        zgmap.put("score",zscore);
        zgmap.put("num",znum);
        zgmap.put("srate",zscorerate);
        zgmap.put("nrate",znumrate);
        ranglist.add(zgmap);
        Map kgmap = new TreeMap();
        kgmap.put("qtname","客观题");
        kgmap.put("score",kscore);
        kgmap.put("num",knum);
        kgmap.put("srate",kscorerate);
        kgmap.put("nrate",knumrate);
        ranglist.add(kgmap);

        Map ztmap = new TreeMap<>();
        ztmap.put("pnum", ePaper.getPnum());
        ztmap.put("pscore",ePaper.getPscore());
        ztmap.put("ranglist",ranglist);

        //题型分布(按照名称进行分组)
        fjtypelist.stream().sorted(Comparator.comparing(EPaperQtype::getEptorder)).collect(Collectors.toList());
        Map<String,List<EPaperQtype>> qtypemap =  fjtypelist.stream().collect(Collectors.groupingBy(EPaperQtype:: getEptname, Collectors.toList()));
        List<Map> qtlist = new ArrayList<>();
        for(Map.Entry<String, List<EPaperQtype>> entry : qtypemap.entrySet()){
            List<EPaperQtype> aq = entry.getValue();
            int num = aq.stream().mapToInt(EPaperQtype::getEptnum).sum();
            double tscore = aq.stream().collect(Collectors.summingDouble(EPaperQtype:: getEptscore));
            tscore = N_Utils.formatDouble(tscore,1);
            double storerate = N_Utils.getDoubleDivideAndMulitiply(tscore, ePaper.getPscore());
            //获取小题题号

            List<Integer> orderlist = new ArrayList<>();
            List<Integer> eptqidlist = new ArrayList<>();
            List<String> qnlist = new ArrayList<>();
            List<Double> scorelist = new ArrayList<>();
            List<String> qnamelist = new ArrayList<>();
            for(EPaperQtype t : aq){
                List<EPaperQtypeQuestion> qlist = t.getQuestions();
                for(EPaperQtypeQuestion q : qlist){
                    orderlist.add(q.getQorder());
                    eptqidlist.add(q.getId());
                    qnlist.add(q.getQn());
                    scorelist.add(q.getScore());
                    qnamelist.add(q.getQtypename());
                }
            }

            Map anmap = new TreeMap();//题型对应试题的id和基础信息
            anmap.put("orders",orderlist);
            anmap.put("eptqids",eptqidlist);
            anmap.put("qns",qnlist);
            anmap.put("scores",scorelist);
            anmap.put("qtypenames",qnamelist);

            Map tmap = new TreeMap();
            tmap.put("qtname",entry.getKey());
            tmap.put("qtid",aq.get(0).getEptid());
            tmap.put("num",num);
            tmap.put("score",tscore);
            tmap.put("srate",storerate);
            tmap.put("ques",anmap);
            qtlist.add(tmap);
        }

        EPaperAnalyze epa = new EPaperAnalyze();
        epa.setEpid(ePaper.getEpid());
        epa.setAlljson(JSON.toJSONString(ztmap));
        epa.setQnumjson(JSON.toJSONString(qtlist));
        ePaperAnalyzeMapper.insertUseGeneratedKeys(epa);
    }

    /**
     * @Description  试卷详情
     * @Param [epid]
     * @Return java.util.Map
     * @Author wn
     * @Date 2022/7/19 9:10
     **/
    public Map getPaperQtDetail(Integer esid) {
        Map map = ePaperMapper.getExamPaperDetailByEsid(esid);//试卷信息
        List<EPaperQtypeVo> fjtypelist = new ArrayList<>();
        List<Map> files = new ArrayList<>();
        if(map.get("epid") != null){
            Integer epid = Integer.parseInt(map.get("epid").toString()) ;
            Integer ptype = Integer.parseInt(map.get("ptype").toString()) ;//试卷类型1题库2附件
            if(ptype == 1){
                fjtypelist = ePaperQtypeMapper.listPaperQtypeQuestions(epid);//试卷题型试题信息（题库）
                setEPaperQtypeForQues(fjtypelist);

            }else{
                fjtypelist = ePaperQtypeMapper.listPaperQtypeQuesitonsForFj(epid);//试卷题型试题信息（附件）
                files = ePaperFileMapper.listPaperFiles(epid);

            }
        }
        map.put("qtypes",fjtypelist);
        map.put("pfiles",files);
        return map;
    }

    private void setEPaperQtypeForQues(List<EPaperQtypeVo> fjtypelist){
        for(EPaperQtypeVo qt : fjtypelist){
            List<EPaperQtypeQuestionVo> qlist = qt.getQuestions();
            List<EPaperQtypeQuestionVo> rtnqlist = new ArrayList<>();//保存处理后的试题
            String qpid = "";//母题id
            List<EPaperQtypeQuestionVo> sonqlist = new ArrayList<>();
            for(EPaperQtypeQuestionVo 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());
                       EPaperQtypeQuestionVo mq = new EPaperQtypeQuestionVo();
                       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().collect(Collectors.summingDouble(EPaperQtypeQuestionVo:: getScore));
                       mq.setScore(mscore);
                       mq.setSonques(sonqlist);
                       mq.setPoints(sonqlist.get(0).getPoints());
                       rtnqlist.add(mq);
                   }
                    qpid = q.getQuestionpid();
                }else{
                    /*EPaperQtypeQuestionVo mq = new EPaperQtypeQuestionVo();
                    BeanUtils.copyProperties(q,mq);
                    mq.setCtype(mq.getCtype());*/
                    rtnqlist.add(q);
                }
            }
            qt.setQuestions(rtnqlist);
        }

    }

    private boolean isExistEPaperPoints(List<Map> allpoint,Map p){
        String ppointid = p.get("pointid").toString();
        for(Map pvo : allpoint){
            String pvopointid = pvo.get("pointid").toString();
            if(ppointid.equals(pvopointid)){
                return true;
            }
        }
        return false;
    }

    /**
     * @Description 设置试卷正确答案
     * @Param [ePaper]
     * @Return void
     * @Author wn
     * @Date 2022/7/25 15:12
     **/
    public void saveQuestionAnswerAndUpdateStuAnswer(EPaper ePaper) {
        Integer epid = ePaper.getEpid();
        Integer examstate = ePaperMapper.getExamStateByEpId(epid);
        List<EPaperQtypeQuestion> questions = ePaper.getQuestions();

        if (N_Utils.isListNotEmpty(questions)) {
            //获取试题答案改变的试题
            List<EPaperQtypeQuestion> changelist = listChangeQuestionAnswer(questions,epid);
            //批量保存试题答案
            saveQuestionAnswer(ePaper,questions,changelist,examstate);
            if(N_Utils.isListNotEmpty(changelist) && examstate > 0){

                //如果考试已经发布，更改学生提交指定试题为需要批改状态
                new Thread(()->{
                    try {
                        dealChangeQuestionStuAnswer(changelist,epid);
                    }catch (Exception e){
                        log.error("处理学生已提交试题重试：" + e.getMessage());
                        try {
                            dealChangeQuestionStuAnswer(changelist,epid);
                        }catch (Exception se){
                            log.error("处理学生已提交试题重批改出错：" + se.getMessage());
                        }
                    }
                }).start();
            }
        }
    }

    //保存试卷中试题答案
    @Transactional(rollbackFor = Exception.class)
    public void saveQuestionAnswer(EPaper ePaper,List<EPaperQtypeQuestion> questions,List<EPaperQtypeQuestion> changelist,Integer examstate){
        try {
            int epid = ePaper.getEpid();
            ePaper.setAnswered(1);
            ePaperMapper.updateEPaperAnswered(ePaper);
            //保存试题答案
            ePaperQtypeQuestionMapper.updateBatchQuestionAnswer(questions);
            if(N_Utils.isListNotEmpty(changelist) && examstate > 0){
                //考试已经发布，更改学生提交指定试题为需要批改状态
                List<Integer> eptqids = changelist.stream().map(EPaperQtypeQuestion::getEptqid).collect(Collectors.toList());
                ePaperStudentQuestionMapper.updateBatchStuQuesNeeddeal(epid,eptqids);//批量设置学生提交试题为需要批改试题
            }

            //判断答案中是否包含附件
            List<EPaperFile> pfiles = ePaper.getPfiles();
            if(N_Utils.isListNotEmpty(pfiles)){
                //说明上传答案附件,先清空
                ePaperFileMapper.delAnswerFile(epid);
                Integer timestamp = N_Utils.getSecondTimestamp();
                for(int i=0;i<pfiles.size(); i++){
                    EPaperFile pfile = pfiles.get(i);
                    pfile.setEpid(epid);
                    pfile.setFileorder(i+1);
                    pfile.setFileclass(2);
                    pfile.setCreateid(ePaper.getHandleid());
                    pfile.setCreatetime(timestamp);
                }
                ePaperFileMapper.insertList(pfiles);
            }

        }catch (Exception e){
            log.error("保存试卷答案失败："+e.getMessage());
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }

    //获取答案改变的试题
    private List<EPaperQtypeQuestion> listChangeQuestionAnswer(List<EPaperQtypeQuestion> questions,Integer epid){
        List<EPaperQtypeQuestion> changelist = new ArrayList<>();
        //获取试卷中原试题答案
        List<EPaperQtypeQuestion> yqlist = ePaperQtypeQuestionMapper.listQuestionsByEpid(epid);
        for(EPaperQtypeQuestion tq : questions){
            if(N_Utils.isTrueInteger(tq.getEptqid()) && N_Utils.isNotEmpty(tq.getAnswer())){
                EPaperQtypeQuestion yq = yqlist.stream().filter(y -> y.getEptqid().equals(tq.getEptqid())).findFirst().orElse(null);
                if(yq.getCtype() == 1 || yq.getCtype() == 2 || yq.getCtype() == 4 || yq.getCtype() == 5 || yq.getCtype() == 6){
                    if(!tq.getAnswer().equalsIgnoreCase(yq.getAnswer())){
                        //说明新设置的答案和原设置的答案不一致，则为变动的
                        tq.setCtype(yq.getCtype());
                        tq.setScore(yq.getScore());
                        changelist.add(tq);
                    }
                }
            }
        }
        return changelist;
    }

    //对于已经开始考试的试卷修改正确答案重新判断试题
    public void dealChangeQuestionStuAnswer(List<EPaperQtypeQuestion> changeQs,Integer epid){
        int limitnum = 100;//一次处理条数
        for(EPaperQtypeQuestion q : changeQs){
            int eptqid = q.getEptqid();
            boolean hasmore = true;
            while (hasmore){
                //获取指定试题学生作答情况,指定条数的数据
                List<EPaperStudentQuestion> psqlist = ePaperStudentQuestionMapper.listPaperStudentQuestionsByeptqid(epid, eptqid,limitnum);
                if(N_Utils.isListNotEmpty(psqlist)){
                    List<EPaperStudentQuestion> uplist = setUpdateStuQuestions(q, psqlist);
                    if(N_Utils.isListNotEmpty(uplist)){
                        //批量更新学生试题分值
                        ePaperStudentQuestionMapper.updateBatchStuQuestionScore(uplist);
                        //获取需要更改的学生试卷
                        List<Integer> epsids = psqlist.stream().map(EPaperStudentQuestion::getEpsid).collect(Collectors.toList());
                        //更新学生试卷分值
                        ePaperStudentMapper.updateBathStudentPaperScoreByEpsid(epid,epsids);
                    }
                }else{
                    hasmore = false;
                }
            }
        }
    }

    //判断分值
    private List<EPaperStudentQuestion> setUpdateStuQuestions(EPaperQtypeQuestion q,List<EPaperStudentQuestion> psqlist){
        List<EPaperStudentQuestion> uplist = new ArrayList<>();//要更新的
        List<String> qanswers = JSON.parseArray(q.getAnswer(),String.class);//试题的正确答案
        //按照学生答案进行分组
        Map<String,List<EPaperStudentQuestion>> stuansmap = psqlist.stream().collect(Collectors.groupingBy(EPaperStudentQuestion::getStuanswer));
        //处理学生答案
        for(Map.Entry<String,List<EPaperStudentQuestion>> entry : stuansmap.entrySet()){
            String stuanswerstr = entry.getKey();
            List<EPaperStudentQuestion> sameanswerlist = entry.getValue();//答案对应的学生
            List<String> stuanswers = JSON.parseArray(stuanswerstr,String.class);
            Double stuscore = 0D;
            if(N_Utils.isListNotEmpty(stuanswers)){
                if(q.getCtype() == 1 || q.getCtype() == 4 || q.getCtype() == 5 || q.getCtype() == 6){
                    if(q.getAnswer().equalsIgnoreCase(stuanswerstr)){
                        stuscore = q.getScore();
                    }
                }else if(q.getCtype() == 2){
                    if(stuanswers.get(0).length() <= qanswers.get(0).length()){
                        String[] qanswerList = qanswers.get(0).split("");
                        String[] stuanswerList = stuanswers.get(0).split("");
                        int rightNum = 0;//选对个数
                        for(String sa : stuanswerList){
                            int right = 0;
                            for(String qa : qanswerList){
                                if(qa.equals(sa)){
                                    right = 1;
                                    rightNum ++;
                                }
                            }
                            if(right == 0){//说明选错
                                rightNum = 0;
                                break;
                            }
                        }
                        if(rightNum>0){
                            if(qanswerList.length == rightNum){
                                //全选对
                                stuscore = q.getScore();
                            }else if (qanswerList.length > rightNum){
                                //少选得半分
                                stuscore = ExamUtil.div(q.getScore(), 2, 1);
                            }
                        }
                    }
                }
            }

            for(EPaperStudentQuestion stuq : sameanswerlist){
                stuq.setStuscore(stuscore);
                uplist.add(stuq);
            }
        }

        return uplist;
    }

    /**
     * @Description 获取制作答题卡需要的试卷信息
     * @Param [epid]
     * @Return java.util.Map
     * @Author wn
     * @Date 2022/7/22 10:19
     **/
    public Map getPaperAndQuesitons(Integer epid){
        Map eps = ePaperMapper.getExamPaperAndSubject(epid);//考试考试科目名称
        List<Map> qtypes = new ArrayList<>();//题型试题
        if(eps!=null){
            qtypes = ePaperQtypeMapper.listPaperqtypeQuestionsForScan(epid);

            //设置答题卡需要默认值
            if(eps.get("scantronnote") == null){
                String scantronnote = "1.答题前，考生先将自己的姓名、班级、考场填写清楚，并认真核对条形码上的姓名和准考证号。<br />" +
                        "2.选择题部分请按题号用2B铅笔填涂方框，修改时用橡皮擦干净，不留痕迹。<br />" +
                        "3.非选择题部分请按题号用0.5毫米黑色墨水签字笔书写，否则作答无效。要求字体工整、笔迹清晰。作图时，必须使用2B铅笔，并描浓。<br />" +
                        "4.在草稿纸、试题卷上答题无效。";
                eps.put("scantronnote",scantronnote);
            }
        }

        Map rtnmap = new HashMap();
        rtnmap.put("paper",eps);
        rtnmap.put("qtypes",qtypes);
        return rtnmap;
    }

    /**
     * @Description 保存答题卡
     * @Param [paper]
     * @Return void
     * @Author wn
     * @Date 2022/7/25 17:38
     **/
    @Transactional(rollbackFor = Exception.class)
    public void savePaperScan(EPaper paper) {
        Integer examstate = ePaperMapper.getExamStateByEpId(paper.getEpid());
        if (2 <= examstate) throw new MissingParametersException("考试已结束禁止操作");
        List<EPaperQtypeQuestion> questions = paper.getQuestions();
        if (N_Utils.isNotEmpty(paper.getScantronfile())) {
            List<String> scanfiles = JSON.parseArray(paper.getScantronfile(), String.class);
            int pn = scanfiles.size() / 2;//答题卡的张数
            paper.setScantronnum(pn);
        }
        ePaperMapper.updatePaperScantron(paper);
        ePaperQtypeQuestionMapper.updateBatchQuestionForScan(questions);
        if (paper.getPstate() == 1) {
            eSubjectMapper.updateEsubjectStateByEpid(1, paper.getEpid());
            //提交之后把答题卡base图片转成pdf
            chandleScantronFile(paper.getEpid());
        }
    }

    //答题卡中图片处理
    public void chandleScantronFile(Integer epid){
        //获取试卷中答题卡文件，
        Map map = ePaperMapper.getPaperScantronfile(epid);
        if(map.get("scantronfile")!=null){
            List<String> scantronfiles = JSON.parseArray(map.get("scantronfile").toString(),String.class);
            if(N_Utils.isNotEmpty(scantronfiles)){
                Integer examid = Integer.parseInt(map.get("examid").toString());
                Integer schoolid = Integer.parseInt(map.get("schoolid").toString());
                String cloudcode =  map.get("cloudcode").toString();
                String path = cloudcode + File.separator + schoolid + File.separator + "exam";
                String filename = map.get("examname").toString() + "(" + map.get("subjectname").toString() + ")";
                Integer scantroncol = Integer.parseInt(map.get("scantroncol").toString());
                convertUtil.baseToPdf(examid,epid,scantronfiles,path,scantroncol,filename);
            }
        }
    }

    //试卷中所有试题题号信息
    public List<Map> listQn(Integer epid) {
        return ePaperQtypeQuestionMapper.listQnByEpid(epid);
    }

    /**
     * @Description 上传答案附件
     * @Date 2024/6/19 14:54
     * @Author YWX
     * @Param [file]
     * @Return void
     **/
    public void upAnswerFile(EPaperFile file) {
        ePaperFileMapper.delAnswerFile(file.getEpid());
        file.setFileclass(2);
        file.setFileorder(1);
        file.setCreatetime(N_Utils.getSecondTimestamp());
        ePaperFileMapper.insert(file);
    }

    /**
     * @Description 删除答案附件
     * @Date 2024/6/19 14:55
     * @Author YWX
     * @Param [epid]
     * @Return void
     **/
    public void delAnswerFile(Integer epid) {
        ePaperFileMapper.delAnswerFile(epid);
    }
}
