package com.xhkjedu.smarking.service.report.generate;

import com.alibaba.fastjson.JSON;
import com.xhkjedu.smarking.mapper.paper.MsPaperAnalyzeMapper;
import com.xhkjedu.smarking.mapper.report.reportstu.MsrStudentPointMapper;
import com.xhkjedu.smarking.mapper.report.reportsubject.MsrSubjectPointMapper;
import com.xhkjedu.smarking.mapper.report.reportsubject.MsrSubjectPointRankgroupMapper;
import com.xhkjedu.smarking.mapper.report.reportsubject.MsrSubjectPointSectionMapper;
import com.xhkjedu.smarking.model.exam.MsClassStudent;
import com.xhkjedu.smarking.model.paper.MsPaperAnalyze;
import com.xhkjedu.smarking.model.paper.MsPaperQtypeQuestion;
import com.xhkjedu.smarking.model.report.reportstu.MsrStudent;
import com.xhkjedu.smarking.model.report.reportstu.MsrStudentPoint;
import com.xhkjedu.smarking.model.report.reportsubject.MsrSubjectPoint;
import com.xhkjedu.smarking.model.report.reportsubject.MsrSubjectPointRankgroup;
import com.xhkjedu.smarking.model.report.reportsubject.MsrSubjectPointSection;
import com.xhkjedu.smarking.model.stupaper.MsPaperStudentQuestion;
import com.xhkjedu.smarking.utils.MarkingUtil;
import com.xhkjedu.smarking.vo.paper.QuestionPointVo;
import com.xhkjedu.smarking.vo.report.reportother.RankGroupVo;
import com.xhkjedu.smarking.vo.report.reportstu.PointQuestionVo;
import com.xhkjedu.smarking.vo.report.reportstu.PointStudentVo;
import com.xhkjedu.smarking.vo.report.reportsubject.PointLevelVo;
import com.xhkjedu.smarking.vo.report.reportsubject.PointParams;
import com.xhkjedu.smarking.vo.report.reportsubject.PointVo;
import com.xhkjedu.utils.N_Utils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Description：生成知识点相关分析
 * @Author: WN
 * @Date: 2024/12/16 11:30:54
 **/
@Service
public class ReportGeneratePointService {
    @Resource
    private MsPaperAnalyzeMapper msPaperAnalyzeMapper;
    @Resource
    private MsrSubjectPointMapper msrSubjectPointMapper;
    @Resource
    private MsrSubjectPointSectionMapper msrSubjectPointSectionMapper;
    @Resource
    private MsrSubjectPointRankgroupMapper msrSubjectPointRankgroupMapper;
    @Resource
    private MsrStudentPointMapper msrStudentPointMapper;

    //知识点分析，题库知识点按母题分析
    public void generatePoint(List<MsPaperStudentQuestion> stuSubjectQuestions, List<MsPaperQtypeQuestion> qtypeQuestions,List<MsClassStudent> classStus,
                            List<MsrStudent> sturanks, Integer examid, String subjectid, Integer mpid, Double pscore,Integer raid) {
        //获取试卷分析
        MsPaperAnalyze paperAnalyze = msPaperAnalyzeMapper.getObjByMpId(mpid);
        if(paperAnalyze == null || N_Utils.isEmpty(paperAnalyze.getPointjson())) return;

        List<MsrStudentPoint> saveStuPoints = new ArrayList<>();//保存学生得分情况
        List<MsrSubjectPoint> saveSubjectPoints = new ArrayList<>();//保存科目班级知识点情况
        List<MsrSubjectPointSection> savePointSections = new ArrayList<>();//知识点学科总分区间
        List<MsrSubjectPointRankgroup>  savePointRankgroups = new ArrayList<>();//知识点分组

        List<QuestionPointVo> qpoints = JSON.parseArray(paperAnalyze.getQuespointjson(), QuestionPointVo.class);//题号对应知识点
        List<PointQuestionVo> pointques = JSON.parseArray(paperAnalyze.getPointjson(), PointQuestionVo.class);//知识点下题号

        List<PointStudentVo> schoolStuPoints = new ArrayList<>();//每个知识点每个学生的得分
        for (QuestionPointVo qpoint : qpoints) {
            List<Map<String,Object>> points = qpoint.getPointids();
            if(qpoint.getQlevel() == 1 || !N_Utils.isEmptyInteger(qpoint.getMptqid())){
                //说明本题是单题，获取该题下所有学生的得分情况
                List<MsPaperStudentQuestion> stuQuestions = stuSubjectQuestions.stream().filter(sq -> sq.getMptqid().equals(qpoint.getMptqid())).collect(Collectors.toList());
                for (MsPaperStudentQuestion sq : stuQuestions) {
                    setQuestionPointsForStuQuestion(schoolStuPoints, sq, points, qpoint.getMptqid().toString());
                }
            }else{
                //说明试题为复合题，先获取所有子题
                List<Integer> mptqids = qpoint.getMptqids();
                String mptqidsStr = mptqids.stream().map(Object::toString).collect(Collectors.joining(","));
                List<MsPaperStudentQuestion> stuQuestions = stuSubjectQuestions.stream().filter(sq -> mptqids.contains(sq.getMptqid())).collect(Collectors.toList());
                //根据每个学生id，获取学生对应试题的分值
                Map<Integer,List<MsPaperStudentQuestion>> stuQuestionMap = stuQuestions.stream().collect(Collectors.groupingBy(MsPaperStudentQuestion::getStudentid));
                for (Map.Entry<Integer, List<MsPaperStudentQuestion>> entry : stuQuestionMap.entrySet()){
                    List<MsPaperStudentQuestion> stuQuess = entry.getValue();
                    Double stuScore = stuQuess.stream().mapToDouble(MsPaperStudentQuestion::getStuscore).sum();
                    stuScore = N_Utils.formatDouble(stuScore, 1);
                    MsPaperStudentQuestion sq = new MsPaperStudentQuestion();
                    sq.setStudentid(entry.getKey());
                    sq.setStuscore(stuScore);
                    setQuestionPointsForStuQuestion(schoolStuPoints, sq, points, mptqidsStr);
                }
            }

        }

        //学科总分区间学生
        List<MsrSubjectPointSection> pointSections = setPointSection(sturanks,pscore);
        Map<Integer,String> qnMap = qtypeQuestions.stream().collect(Collectors.toMap(MsPaperQtypeQuestion::getMptqid, q -> q.getQnstr()));

        //知识点本分分析（三级知识点分析）
        for(PointQuestionVo pqvo : pointques){
            List<QuestionPointVo> quePoints = pqvo.getQues();//知识点下试题
            // 单个知识点学生得分情况:一个知识对应一个或多个试题，
            List<PointStudentVo> stuPoints = schoolStuPoints.stream().filter(ps -> ps.getPointid().equals(pqvo.getPointid())).collect(Collectors.toList());

            PointParams pointParams = new PointParams();
            pointParams.setPointid(pqvo.getPointid());
            pointParams.setPointname(pqvo.getPointname());
            pointParams.setFullscore(pqvo.getScore());
            pointParams.setExamid(examid);
            pointParams.setSubjectid(subjectid);
            pointParams.setRaid(raid);
            pointParams.setPointlevel(3);
            //三级知识点对应信息
            pointTopAndUpForOther(stuPoints,quePoints,qnMap,pointParams,classStus,pointSections,sturanks,saveStuPoints,saveSubjectPoints,savePointSections,savePointRankgroups);
        }

        //获取知识点顶级和上级知识点
        Map<String,Map<String,List<PointLevelVo>>> pointTopAndUpMap = listSubjectPoints(subjectid,examid,pointques);
        Map<String,List<PointLevelVo>> pointUpMap = pointTopAndUpMap.get("up");//上级知识点
        Map<String,List<PointLevelVo>> pointTopMap = pointTopAndUpMap.get("top");//顶级知识点
        //知识点分析--三级知识点（知识点分析）
        Map<String, List<MsrSubjectPoint>> subjectPointMap = saveSubjectPoints.stream().filter(p -> p.getPointlevel()==3).collect(Collectors.groupingBy(MsrSubjectPoint::getPointid));
        //知识点学科总分区间--三级知识点（知识点分析）
        Map<String, List<MsrSubjectPointSection>> pointSectionMap = savePointSections.stream().filter(p -> p.getPointlevel()==3).collect(Collectors.groupingBy(MsrSubjectPointSection::getPointid));
        //知识点分组--三级知识点（知识点分析）
        Map<String, List<MsrSubjectPointRankgroup>> pointRankgroupMap = savePointRankgroups.stream().filter(p -> p.getPointlevel()==3).collect(Collectors.groupingBy(MsrSubjectPointRankgroup::getPointid));

        //上层知识点（二级知识点）
        for(Map.Entry<String,List<PointLevelVo>> entry : pointUpMap.entrySet()) {
            List<PointLevelVo> pointLevels = entry.getValue();
            PointLevelVo firstPoint = pointLevels.get(0);
            if(pointLevels.size() == 1){
                //上层知识点下知识点只有一个，该知识点的分析和三级知识点一致
                pointTopAndUpForSelf(firstPoint,2,subjectPointMap,pointSectionMap,pointRankgroupMap,saveSubjectPoints,savePointSections,savePointRankgroups);
            }else{
                //上层知识点所包含的知识点id集合
                List<String> pointids = pointLevels.stream().map(PointLevelVo::getPointid).collect(Collectors.toList());
                //知识点下试题，以及学生得分
                List<PointQuestionVo> levelPointQues = pointques.stream().filter(q -> pointids.contains(q.getPointid())).collect(Collectors.toList());
                List<PointStudentVo> stuPoints = schoolStuPoints.stream().filter(q -> pointids.contains(q.getPointid())).collect(Collectors.toList());
                List<QuestionPointVo> ques = new ArrayList<>();//知识点下所有试题
                for(PointQuestionVo point : levelPointQues) {
                    ques.addAll(point.getQues());
                }
                Double fullScore = levelPointQues.stream().mapToDouble(PointQuestionVo::getScore).sum();
                fullScore = N_Utils.formatDouble(fullScore, 1);
                PointParams pointParams = new PointParams();
                pointParams.setRaid(raid);
                pointParams.setPointid(firstPoint.getTopPointid());
                pointParams.setPointname(firstPoint.getTopPointname());
                pointParams.setFullscore(fullScore);
                pointParams.setExamid(examid);
                pointParams.setSubjectid(subjectid);
                pointParams.setPointlevel(2);
                //级知识点对应信息
                pointTopAndUpForOther(stuPoints,ques,qnMap,pointParams,classStus,pointSections,sturanks,saveStuPoints,saveSubjectPoints,savePointSections,savePointRankgroups);
            }
        }

        //顶级知识点 (一级知识点)
        for(Map.Entry<String,List<PointLevelVo>> entry : pointTopMap.entrySet()) {
            List<PointLevelVo> pointLevels = entry.getValue();
            PointLevelVo firstPoint = pointLevels.get(0);
            if(pointLevels.size() == 1){
                //上层知识点下知识点只有一个，该知识点的分析和三级知识点一致
                pointTopAndUpForSelf(firstPoint,1,subjectPointMap,pointSectionMap,pointRankgroupMap,saveSubjectPoints,savePointSections,savePointRankgroups);
            }else{
                //上层知识点所包含的知识点id集合
                List<String> pointids = pointLevels.stream().map(PointLevelVo::getPointid).collect(Collectors.toList());
                //知识点下试题，以及学生得分
                List<PointQuestionVo> levelPointQues = pointques.stream().filter(q -> pointids.contains(q.getPointid())).collect(Collectors.toList());
                List<PointStudentVo> stuPoints = schoolStuPoints.stream().filter(q -> pointids.contains(q.getPointid())).collect(Collectors.toList());
                List<QuestionPointVo> ques = new ArrayList<>();//知识点下所有试题
                for(PointQuestionVo point : levelPointQues) {
                    ques.addAll(point.getQues());
                }
                Double fullScore = levelPointQues.stream().mapToDouble(PointQuestionVo::getScore).sum();
                fullScore = N_Utils.formatDouble(fullScore, 1);
                PointParams pointParams = new PointParams();
                pointParams.setPointid(firstPoint.getTopPointid());
                pointParams.setPointname(firstPoint.getTopPointname());
                pointParams.setFullscore(fullScore);
                pointParams.setExamid(examid);
                pointParams.setSubjectid(subjectid);
                pointParams.setRaid(raid);
                pointParams.setPointlevel(1);
                //级知识点对应信息
                pointTopAndUpForOther(stuPoints,ques,qnMap,pointParams,classStus,pointSections,sturanks,saveStuPoints,saveSubjectPoints,savePointSections,savePointRankgroups);
            }
        }

        if(!saveStuPoints.isEmpty()) msrStudentPointMapper.insertList(saveStuPoints);
        if(!saveSubjectPoints.isEmpty()) msrSubjectPointMapper.insertList(saveSubjectPoints);
        if(!savePointSections.isEmpty()) msrSubjectPointSectionMapper.insertList(savePointSections);
        if(!savePointRankgroups.isEmpty()) msrSubjectPointRankgroupMapper.insertList(savePointRankgroups);
    }

    // 知识点:设置每个学生每个试题知识点得分
    private void setQuestionPointsForStuQuestion(List<PointStudentVo> schoolStuPoints, MsPaperStudentQuestion sq, List<Map<String,Object>> points, String mptqids) {
        if (points.size() == 1) {
            Map<String, Object> pointmap = points.get(0);
            // 说明该试题仅有一个知识点得分直接为改知识点分值
            PointStudentVo pscvo = new PointStudentVo();
            pscvo.setStudentid(sq.getStudentid());
            pscvo.setStuscore(sq.getStuscore());
            pscvo.setPointid(pointmap.get("pointid").toString());
            pscvo.setMptqids(mptqids);
            schoolStuPoints.add(pscvo);
        } else {
            // 计算每个知识点所占分值（平均分配）
            Double[] avgps = N_Utils.getPointAvgScore(points.size(), sq.getStuscore());
            for (int j = 0; j < points.size(); j++) {
                Map<String, Object> pointmap = points.get(j);
                PointStudentVo pscvo = new PointStudentVo();
                pscvo.setStudentid(sq.getStudentid());
                pscvo.setPointid(pointmap.get("pointid").toString());
                pscvo.setMptqids(mptqids);
                if (avgps.length == 2 && (j + 1) == points.size()) {
                    pscvo.setStuscore(avgps[1]);
                } else {
                    pscvo.setStuscore(avgps[0]);
                }
                schoolStuPoints.add(pscvo);
            }
        }
    }

    //知识点分析--班级知识点
    private MsrSubjectPoint pointLevelClass(List<PointStudentVo> pointStuScores, MsrSubjectPoint subjectPoint){
        List<Double> stuScores = pointStuScores.stream().map(PointStudentVo::getStuscore).collect(Collectors.toList());
        double sumScore = pointStuScores.stream().mapToDouble(PointStudentVo::getStuscore).sum();
        int stuNum = pointStuScores.size();
        MsrSubjectPoint classPoint = new MsrSubjectPoint();
        classPoint.setRaid(subjectPoint.getRaid());
        classPoint.setExamid(subjectPoint.getExamid());
        classPoint.setSubjectid(subjectPoint.getSubjectid());
        classPoint.setClassid(subjectPoint.getClassid());
        classPoint.setPointlevel(subjectPoint.getPointlevel());
        classPoint.setPointid(subjectPoint.getPointid());
        classPoint.setPointname(subjectPoint.getPointname());
        classPoint.setFullscore(subjectPoint.getFullscore());
        classPoint.setMaxscore(pointStuScores.stream().mapToDouble(PointStudentVo::getStuscore).max().orElse(0.0));
        classPoint.setMinscore(pointStuScores.stream().mapToDouble(PointStudentVo::getStuscore).min().orElse(0.0));
        classPoint.setScorerate(MarkingUtil.div(sumScore, subjectPoint.getFullscore() * stuNum));
        classPoint.setAvgscore(MarkingUtil.div(sumScore, stuNum));
        classPoint.setAvgrate(MarkingUtil.div(classPoint.getAvgscore(), subjectPoint.getFullscore()));
        classPoint.setBzc(MarkingUtil.bzc(stuScores));
        classPoint.setCyxs(MarkingUtil.div(classPoint.getBzc(), classPoint.getAvgscore()));
        classPoint.setQfd(MarkingUtil.qfd(stuScores));
        classPoint.setJbzs(MarkingUtil.jbzs(stuScores, subjectPoint.getFullscore()));
        classPoint.setQns(subjectPoint.getQns());
        classPoint.setMptqids(subjectPoint.getMptqids());
        //满分人
        List<PointStudentVo> fullScoreStus = pointStuScores.stream().filter(q -> q.getStuscore().equals(subjectPoint.getFullscore())).collect(Collectors.toList());
        if(fullScoreStus.isEmpty()){
            classPoint.setMfnum(0);
        }else{
            classPoint.setMfnum(fullScoreStus.size());
            classPoint.setMfids(fullScoreStus.stream().map(q -> q.getStudentid().toString()).collect(Collectors.joining(",")));
        }

        //零分人
        List<PointStudentVo> zeroScoreStus = pointStuScores.stream().filter(q -> q.getStuscore()==0).collect(Collectors.toList());
        if(fullScoreStus.isEmpty()){
            classPoint.setLfnum(0);
        }else{
            classPoint.setLfnum(zeroScoreStus.size());
            classPoint.setLfids(zeroScoreStus.stream().map(q -> q.getStudentid().toString()).collect(Collectors.joining(",")));
        }

        return classPoint;
    }

    // 知识点-科目分段-默认5分一段为后续试题在段上学生得分率做准备
    private List<MsrSubjectPointSection> setPointSection(List<MsrStudent> StuPapers, Double pscore) {
        // 把科目总分分段，默认5分一段
        List<RankGroupVo> fdList = MarkingUtil.fdScore(pscore, 5);
        List<MsrSubjectPointSection> sections = new ArrayList<>();
        MsrStudent fdStuPaper = StuPapers.get(0);
        for (RankGroupVo fd : fdList) {
            // 获取学生得分在指定区间的学生
            List<MsrStudent> fdStuPapers;
            if (fd.getMaxvalue() == pscore) {
                fdStuPapers = StuPapers.stream().filter(s -> s.getStuscore() >= fd.getMinvalue()).collect(Collectors.toList());
            } else {
                fdStuPapers = StuPapers.stream().filter(s -> s.getStuscore() >= fd.getMinvalue() && s.getStuscore() < fd.getMaxvalue()).collect(Collectors.toList());
            }

            MsrSubjectPointSection question = new MsrSubjectPointSection();
            question.setExamid(fdStuPaper.getExamid());
            question.setSubjectid(fdStuPaper.getSubjectid());
            question.setFdfw(fd.getGroupname());
            question.setFdnum(fdStuPapers.size());
            question.setFdids(fdStuPapers.stream().map(s -> s.getStudentid().toString()).collect(Collectors.joining(",")));
            sections.add(question);
        }
        return sections;
    }
    //知识点-与总分分数区间相关性分析
    private List<MsrSubjectPointSection> pointSection(List<PointStudentVo> pointStuScores,List<MsrSubjectPointSection> sections,PointParams pointParams){
        List<MsrSubjectPointSection> rtnList = new ArrayList<>();
        for(MsrSubjectPointSection section : sections){
            String[] userids = section.getFdids().split(",");
            List<String> useridList = Arrays.asList(userids);
            List<PointStudentVo> sectionStuPoints = pointStuScores.stream().filter(q -> useridList.contains(q.getStudentid().toString())).collect(Collectors.toList());

            MsrSubjectPointSection sps = new MsrSubjectPointSection();
            sps.setRaid(pointParams.getRaid());
            sps.setExamid(pointParams.getExamid());
            sps.setSubjectid(pointParams.getSubjectid());
            sps.setPointlevel(pointParams.getPointlevel());
            sps.setPointid(pointParams.getPointid());
            sps.setPointname(pointParams.getPointname());
            sps.setFdfw(section.getFdfw());
            if(!sectionStuPoints.isEmpty()){
                // 获取总分
                double sumScore = sectionStuPoints.stream().mapToDouble(PointStudentVo::getStuscore).sum();
                int stuNum = sectionStuPoints.size();
                // 获取平均分
                double avgScore = MarkingUtil.div(sumScore, stuNum);
                // 获取平均得分率
                sps.setAvgrate(MarkingUtil.div(avgScore, pointParams.getFullscore()));
                sps.setAvgscore(avgScore);
            }else{
                sps.setAvgrate(0.0);
                sps.setAvgscore(0.0);
            }

            rtnList.add(sps);
        }
        return rtnList;
    }

    //知识点-考试排名分组分析
    private List<MsrSubjectPointRankgroup> pointRankGroup(List<PointStudentVo> pointStuScores, List<MsrStudent> stuPapers, PointQuestionVo pqvo,Integer examid,String subjectid, Integer pointlevel,Integer raid){
        //获取学生排名最大名次的树
        Integer totalRank = stuPapers.stream().mapToInt(MsrStudent::getSchoolrank).max().orElse(0);
        //获取排名分组,默认分为7组
        List<RankGroupVo> rankGroups = MarkingUtil.rankGroup(totalRank,7);
        //获取知识点分段,1分1段
        List<RankGroupVo> sectionScores = MarkingUtil.fdScore(pqvo.getScore(),5);
        List<MsrSubjectPointRankgroup> rtnList = new ArrayList<>();
        for (RankGroupVo rankGroup : rankGroups) {
            //名次下学生信息
            List<MsrStudent> groupStus = stuPapers.stream().filter(s -> s.getSchoolrank() >= rankGroup.getMinvalue() && s.getSchoolrank() <= rankGroup.getMaxvalue()).collect(Collectors.toList());
            MsrSubjectPointRankgroup sqr = new MsrSubjectPointRankgroup();
            sqr.setRaid(raid);
            sqr.setExamid(examid);
            sqr.setSubjectid(subjectid);
            sqr.setPointid(pqvo.getPointid());
            sqr.setPointname(pqvo.getPointname());
            sqr.setPointlevel(pointlevel);
            sqr.setRgroup(rankGroup.getGroupname());

            List<Integer> groupStuids;
            List<PointStudentVo> groupStuPoints = null;
            if(!groupStus.isEmpty()){
                groupStuids = groupStus.stream().map(MsrStudent::getStudentid).collect(Collectors.toList());
                //名次下学生试题作答情况
                groupStuPoints = pointStuScores.stream().filter(q -> groupStuids.contains(q.getStudentid())).collect(Collectors.toList());
                sqr.setStunum(groupStuPoints.size());
                sqr.setStuids(groupStuPoints.stream().map(q -> q.getStudentid().toString()).collect(Collectors.joining(",")));
            } else {
                groupStuids = null;
                sqr.setStunum(0);
            }

            //试题分段区间
            for(RankGroupVo sectionScore : sectionScores){
                MsrSubjectPointRankgroup sqrg = new MsrSubjectPointRankgroup();
                sqrg.setRaid(raid);
                sqrg.setExamid(examid);
                sqrg.setSubjectid(subjectid);
                sqrg.setPointid(pqvo.getPointid());
                sqrg.setPointname(pqvo.getPointname());
                sqrg.setPointlevel(pointlevel);
                sqrg.setRgroup(rankGroup.getGroupname());
                sqrg.setRsection(sectionScore.getGroupname());

                if(groupStuids != null && !groupStuids.isEmpty()){
                    //名次分组下有学生，进行学生分数段计算
                    List<PointStudentVo> sectionStuQuestions;
                    if(sectionScore.getMinvalue() == pqvo.getScore()){
                        //最小值为满分时分段形式为[qscore,qscore)
                        sectionStuQuestions = groupStuPoints.stream().filter(q -> q.getStuscore() >= sectionScore.getMinvalue()).collect(Collectors.toList());
                    }else{
                        sectionStuQuestions = groupStuPoints.stream().filter(q -> q.getStuscore() >= sectionScore.getMinvalue() && q.getStuscore() < sectionScore.getMaxvalue()).collect(Collectors.toList());
                    }

                    sqrg.setStunum(sectionStuQuestions.size());
                    sqrg.setStuids(sectionStuQuestions.stream().map(q -> q.getStudentid().toString()).collect(Collectors.joining(",")));
                }else{
                    sqrg.setStunum(0);
                }

                rtnList.add(sqrg);
            }

            rtnList.add(sqr);
        }
        return rtnList;
    }

    //获取处理知识点对应的顶层、上层知识点
    private Map<String,Map<String,List<PointLevelVo>>> listSubjectPoints(String subjectid,Integer examid,List<PointQuestionVo> pointques){
        //获取所有知识点
        List<PointVo> points = msrSubjectPointMapper.listSubjectPoints(subjectid,examid);
        Map<String,PointVo> pointMap = points.stream().collect(Collectors.toMap(PointVo::getPointid, Function.identity()));

        List<PointLevelVo> upPoints = new ArrayList<>();//知识点的上层(二级)知识点
        List<PointLevelVo> topPoints = new ArrayList<>();//知识点的顶层层(一级)知识点
        for(PointQuestionVo point : pointques){
            PointLevelVo upPoint = new PointLevelVo();
            upPoint.setPointid(point.getPointid());
            upPoint.setPointname(point.getPointname());

            PointLevelVo topPoint = new PointLevelVo();
            topPoint.setPointid(point.getPointid());
            topPoint.setPointname(point.getPointname());

            //获取知识点的详细信息
            if(pointMap.containsKey(point.getPointid()) && pointMap.get(point.getPointid()).getPointpid()!= null){
                PointVo pointVo = pointMap.get(point.getPointid());
                //说明知识点的上层知识点不为空
                PointVo parentNode =pointVo.getParent(points);//上层知识点
                upPoint.setTopPointid(parentNode.getPointid());
                upPoint.setTopPointname(parentNode.getPointname());

                //找到顶层知识点
                PointVo rootNode = getRootNode(parentNode, points);
                if(rootNode!= null){
                    topPoint.setTopPointid(rootNode.getPointid());
                    topPoint.setTopPointname(rootNode.getPointname());
                }else{
                    topPoint.setTopPointid(point.getPointid());
                    topPoint.setTopPointname(point.getPointname());
                }
            }else{
                //知识点的父知识点为空，即上层、顶层知识点都是知识点本身
                upPoint.setTopPointid(point.getPointid());
                upPoint.setTopPointname(point.getPointname());

                topPoint.setTopPointid(point.getPointid());
                topPoint.setTopPointname(point.getPointname());
            }

            upPoints.add(upPoint);
            topPoints.add(topPoint);
        }

        Map<String,List<PointLevelVo>> upMap = upPoints.stream().collect(Collectors.groupingBy(PointLevelVo::getTopPointid));
        Map<String,List<PointLevelVo>> topMap = topPoints.stream().collect(Collectors.groupingBy(PointLevelVo::getTopPointid));
        Map<String,Map<String,List<PointLevelVo>>> rtnMap = new HashMap<>();
        rtnMap.put("up",upMap);
        rtnMap.put("top",topMap);
        return rtnMap;
    }
    //获取顶层节点
    private PointVo getRootNode(PointVo targetNode, List<PointVo> allNodes) {
        PointVo current = targetNode;
        while (N_Utils.isNotEmpty(current.getPointpid())) {
            current = current.getParent(allNodes);
        }
        return current;
    }

    //层级知识点分析--顶层和上层知识点是知识点本身
    private void pointTopAndUpForSelf(PointLevelVo firstPoint,Integer pointlevel,Map<String, List<MsrSubjectPoint>> subjectPointMap,
            Map<String, List<MsrSubjectPointSection>> pointSectionMap,Map<String, List<MsrSubjectPointRankgroup>> pointRankgroupMap,
            List<MsrSubjectPoint> saveSubjectPoints,List<MsrSubjectPointSection> savePointSections, List<MsrSubjectPointRankgroup> savePointRankgroups) {

        //知识点分析
        List<MsrSubjectPoint> subpoints = subjectPointMap.get(firstPoint.getPointid());
        for(MsrSubjectPoint subpoint : subpoints){

            MsrSubjectPoint subpointvo = new MsrSubjectPoint();
            BeanUtils.copyProperties(subpointvo, subpoint);
            subpointvo.setPointid(firstPoint.getTopPointid());
            subpointvo.setPointname(firstPoint.getPointname());
            subpointvo.setPointlevel(pointlevel);
            subpointvo.setFullscore(subpoint.getFullscore());

            saveSubjectPoints.add(subpointvo);
        }

        //分数分段
        List<MsrSubjectPointSection> sepoints = pointSectionMap.get(firstPoint.getPointid());
        for(MsrSubjectPointSection sepoint : sepoints) {
            MsrSubjectPointSection sepointvo = new MsrSubjectPointSection();
            BeanUtils.copyProperties(sepointvo, sepoint);
            sepointvo.setPointid(firstPoint.getTopPointid());
            sepointvo.setPointname(firstPoint.getPointname());
            sepointvo.setPointlevel(pointlevel);
            savePointSections.add(sepointvo);
        }

        //分组分析
        List<MsrSubjectPointRankgroup> rgpoints = pointRankgroupMap.get(firstPoint.getPointid());
        for(MsrSubjectPointRankgroup rgpoint : rgpoints) {
            MsrSubjectPointRankgroup rgpointvo = new MsrSubjectPointRankgroup();
            BeanUtils.copyProperties(rgpointvo, rgpoint);
            rgpointvo.setPointid(firstPoint.getTopPointid());
            rgpointvo.setPointname(firstPoint.getPointname());
            rgpointvo.setPointlevel(pointlevel);
            savePointRankgroups.add(rgpointvo);
        }
    }
    //层级知识点分析--顶层和上层知识点下多知识点分析
    private void pointTopAndUpForOther(List<PointStudentVo> levelStuPoints, List<QuestionPointVo> ques, Map<Integer,String> qnMap, PointParams pointParam,
                                        List<MsClassStudent> classStus, List<MsrSubjectPointSection> pointSections, List<MsrStudent> sturanks,List<MsrStudentPoint> saveStuPoints,
                                        List<MsrSubjectPoint> saveSubjectPoints, List<MsrSubjectPointSection> savePointSections, List<MsrSubjectPointRankgroup> savePointRankgroups){
        List<Integer> mptqids = new ArrayList<>();
        for(QuestionPointVo qpointvo : ques){
            mptqids.addAll(qpointvo.getMptqids());
        }

        StringBuilder qnStr= new StringBuilder();
        String mptqidStr = mptqids.stream().map(Object::toString).collect(Collectors.joining(","));
        for(Map.Entry<Integer,String> qnentry : qnMap.entrySet()){
            if(mptqids.contains(qnentry.getKey())){
                qnStr.append(qnentry.getValue()).append(",");
            }
        }
        if(N_Utils.isNotEmpty(qnStr.toString())){
            qnStr = new StringBuilder(qnStr.substring(0, qnStr.length() - 1));
        }

        //知识点多个试题，处理成单个学生试题总分值
        List<PointStudentVo> pointStuScores = new ArrayList<>();//处理成学生知识点形式，后续计算使用
        Map<Integer, List<PointStudentVo>> pointStuMap = levelStuPoints.stream().collect(Collectors.groupingBy(PointStudentVo::getStudentid));
        for (Map.Entry<Integer, List<PointStudentVo>> psentry : pointStuMap.entrySet()){
            List<PointStudentVo> pstuScores = psentry.getValue();
            double stuScore = pstuScores.stream().mapToDouble(PointStudentVo::getStuscore).sum();
            stuScore = N_Utils.formatDouble(stuScore, 1);
            PointStudentVo pstuvo = new PointStudentVo();
            pstuvo.setStudentid(psentry.getKey());
            pstuvo.setPointid(pointParam.getPointid());
            pstuvo.setStuscore(stuScore);
            pstuvo.setScore(pointParam.getFullscore());
            pointStuScores.add(pstuvo);
        }

        MsrSubjectPoint subjectPoint = new MsrSubjectPoint();
        subjectPoint.setRaid(pointParam.getRaid());
        subjectPoint.setExamid(pointParam.getExamid());
        subjectPoint.setSubjectid(pointParam.getSubjectid());
        subjectPoint.setPointid(pointParam.getPointid());
        subjectPoint.setPointname(pointParam.getPointname());
        subjectPoint.setClassid(0);
        subjectPoint.setFullscore(pointParam.getFullscore());
        subjectPoint.setPointlevel(pointParam.getPointlevel());
        subjectPoint.setMptqids(mptqidStr);
        subjectPoint.setQns(qnStr.toString());

        //校知识点分析
        MsrSubjectPoint schoolPoint = pointLevelClass(pointStuScores, subjectPoint);
        saveSubjectPoints.add(schoolPoint);

        //班级知识点分析
        List<Integer> classIds = classStus.stream().map(MsClassStudent::getClassid).distinct().collect(Collectors.toList());
        List<MsrSubjectPoint> classPoints = new ArrayList<>();
        for (Integer classid : classIds) {
            // 获取班级下学生id
            List<Integer> classStuIds = classStus.stream().filter(c -> c.getClassid().equals(classid)).map(MsClassStudent::getStudentid).collect(Collectors.toList());
            // 获取班级下学生试题
            List<PointStudentVo> classStuPoints = pointStuScores.stream().filter(q -> classStuIds.contains(q.getStudentid())).collect(Collectors.toList());
            subjectPoint.setClassid(classid);
            MsrSubjectPoint classPoint = pointLevelClass(classStuPoints, subjectPoint);
            classPoints.add(classPoint);
        }

        // 班级知识点保存后，要对平均分排序
        List<Double> avgScores = classPoints.stream().map(MsrSubjectPoint::getAvgscore).collect(Collectors.toList());
        Map<Double,Integer> avgScoreRankMap = MarkingUtil.fspm(avgScores);
        for(MsrSubjectPoint sp : classPoints){
            sp.setAvgrank(avgScoreRankMap.get(sp.getAvgscore()));
        }
        saveSubjectPoints.addAll(classPoints);

        PointQuestionVo pqvo = new PointQuestionVo();
        pqvo.setPointid(pointParam.getPointid());
        pqvo.setPointname(pointParam.getPointname());
        pqvo.setScore(pointParam.getFullscore());

        //知识点分段分析(知识点与总分的相关性)
        List<MsrSubjectPointSection> pointSecs = pointSection(pointStuScores, pointSections, pointParam);
        savePointSections.addAll(pointSecs);

        //知识点考生分组分析
        List<MsrSubjectPointRankgroup> pointRankg = pointRankGroup(pointStuScores,sturanks, pqvo, pointParam.getExamid(), pointParam.getSubjectid(), pointParam.getPointlevel(),pointParam.getRaid());
        savePointRankgroups.addAll(pointRankg);

        if(pointParam.getPointlevel() == 3){
            double schoolSumScore = pointStuScores.stream().mapToDouble(PointStudentVo::getStuscore).sum();
            int stunum = pointStuScores.size();
            double schoolAvgScore = MarkingUtil.div(schoolSumScore, stunum);
            double schoolScoreRate = MarkingUtil.div(schoolSumScore, pqvo.getScore() * stunum);
            //处理学生得分情况
            for(PointStudentVo pstuvo : pointStuScores){
                MsrStudentPoint stuPoint = new MsrStudentPoint();
                stuPoint.setRaid(pointParam.getRaid());
                stuPoint.setExamid(pointParam.getExamid());
                stuPoint.setSubjectid(pointParam.getSubjectid());
                stuPoint.setStudentid(pstuvo.getStudentid());
                stuPoint.setPointid(pqvo.getPointid());
                stuPoint.setPointname(pqvo.getPointname());
                stuPoint.setFullscore(pqvo.getScore());
                stuPoint.setStuscore(pstuvo.getStuscore());
                stuPoint.setSturate(MarkingUtil.div(pstuvo.getStuscore(), pqvo.getScore()));
                stuPoint.setSchoolavg(schoolAvgScore);
                stuPoint.setSchoolrate(schoolScoreRate);
                stuPoint.setQns(qnStr.toString());
                stuPoint.setMptqids(mptqidStr);
                saveStuPoints.add(stuPoint);
            }
        }
    }

}
