package com.yida.data.school.exam.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yida.data.common.core.entity.exam.CoreExamination;
import com.yida.data.common.core.entity.exam.CoreExaminationCourse;
import com.yida.data.common.core.entity.exam.CoreExaminationPublish;
import com.yida.data.common.core.entity.exam.CoreExaminationPublishGradeConvertType;
import com.yida.data.common.core.entity.exam.CoreExaminationPublishRecord;
import com.yida.data.common.core.entity.exam.CoreExaminationStudent;
import com.yida.data.common.core.entity.exam.CoreExaminationStudentCourse;
import com.yida.data.common.core.entity.exam.EduExamAvg;
import com.yida.data.common.core.utils.CollUtil;
import com.yida.data.school.dto.exam.ClassCompareDTO;
import com.yida.data.school.dto.exam.ScoreSectionStasticDTO;
import com.yida.data.school.exam.mapper.CoreExaminationCourseMapper;
import com.yida.data.school.exam.mapper.CoreExaminationMapper;
import com.yida.data.school.exam.mapper.CoreExaminationPublishGradeConvertTypeMapper;
import com.yida.data.school.exam.mapper.CoreExaminationPublishMapper;
import com.yida.data.school.exam.mapper.CoreExaminationPublishRecordMapper;
import com.yida.data.school.exam.mapper.CoreExaminationStudentCourseMapper;
import com.yida.data.school.exam.mapper.CoreExaminationStudentMapper;
import com.yida.data.school.exam.mapper.EduExamAvgMapper;
import com.yida.data.school.exam.service.CoreExaminationAnalysisService;
import com.yida.data.school.vo.exam.ExamScoreAnalysisVO;
import com.yida.data.school.vo.exam.ScoreAndAvgCompareVO;
import com.yida.data.school.vo.exam.ScoreDistributeVO;
import com.yida.data.school.vo.exam.ScoreSectionStasticVO;
import com.yida.data.school.vo.exam.ScoreSectionVO;
import com.yida.data.school.vo.exam.ScoreTrendVO;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@RequiredArgsConstructor
@Service
@Transactional(readOnly = true)
public class CoreExaminationAnalysisServiceImpl implements CoreExaminationAnalysisService {
    private final CoreExaminationStudentMapper coreExaminationStudentMapper;
    private final CoreExaminationCourseMapper coreExaminationCourseMapper;
    private final CoreExaminationStudentCourseMapper coreExaminationStudentCourseMapper;
    private final CoreExaminationMapper coreExaminationMapper;
    private final CoreExaminationPublishRecordMapper coreExaminationPublishRecordMapper;
    private final CoreExaminationPublishMapper coreExaminationPublishMapper;
    private final EduExamAvgMapper eduExamAvgMapper;
    private final CoreExaminationPublishGradeConvertTypeMapper coreExaminationPublishGradeConvertTypeMapper;

    @Override
    public List<ExamScoreAnalysisVO> classCompare(ClassCompareDTO dto) {
        if (coreExaminationStudentMapper.selectCount(Wrappers.lambdaQuery(new CoreExaminationStudent())
                .eq(CoreExaminationStudent::getCoreExaminationId, dto.getExamId())) == 0) {
            return null;
        }
        if (dto.getCourseId() == null) {
            CoreExamination exam = coreExaminationMapper.selectById(dto.getExamId());
            dto.setScore(exam.getScore());
        } else {
            CoreExaminationCourse course = coreExaminationCourseMapper.selectOne(Wrappers.lambdaQuery(new CoreExaminationCourse())
                    .eq(CoreExaminationCourse::getCoreCourseId, dto.getCourseId())
                    .eq(CoreExaminationCourse::getCoreExaminationId, dto.getExamId()));
            dto.setScore(course.getCoreCourseScore());
        }
        List<ExamScoreAnalysisVO> analysisList = dto.getCourseId() == null
                ? coreExaminationStudentMapper.getScoreAnalysis(dto)
                : coreExaminationStudentMapper.getCourseScoreAnalysis(dto);
        ExamScoreAnalysisVO all = null;
        for (ExamScoreAnalysisVO analysis : analysisList) {
            // 计算各种率
            analysis.setAvgScoreRate(analysis.getAvgScore() * 100 / dto.getScore());
            analysis.setHighScoreRate(analysis.getHighScoreNum() * 100D / analysis.getStudentNum());
            analysis.setExcellentScoreRate(analysis.getExcellentScoreNum() * 100D / analysis.getStudentNum());
            analysis.setGoodScoreRate(analysis.getGoodScoreNum() * 100D / analysis.getStudentNum());
            analysis.setPassScoreRate(analysis.getPassScoreNum() * 100D / analysis.getStudentNum());
            analysis.setLowScoreRate(analysis.getLowScoreNum() * 100D / analysis.getStudentNum());
            analysis.setComplexScoreRate(analysis.getAvgScoreRate() * 0.5 + analysis.getExcellentScoreRate() * 0.25 + analysis.getPassScoreRate() * 0.25);
            if (analysis.getClassId() == null) {
                all = analysis;
            }
        }
        analysisList.remove(all);
        int showRank = 0;
        int realRank = 1;
        ExamScoreAnalysisVO prev = null;
        // 计算平均分排名
        analysisList =
                analysisList.stream().sorted((y, x) -> x.getAvgScoreRate().compareTo(y.getAvgScoreRate())).collect(Collectors.toList());
        for (int j = 0; j < analysisList.size(); j++) {
            if (analysisList.get(j).getClassId() != null) {
                if (prev == null || !prev.getAvgScoreRate().equals(analysisList.get(j).getAvgScoreRate())) {
                    showRank++;
                } else {
                    showRank = realRank;
                }
                analysisList.get(j).setAvgScoreRank(showRank);
                realRank++;
                prev = analysisList.get(j);
            }
        }
        // 高分排名
        showRank = 0;
        realRank = 1;
        prev = null;
        analysisList =
                analysisList.stream().sorted((y, x) -> x.getHighScoreRate().compareTo(y.getHighScoreRate())).collect(Collectors.toList());
        for (int j = 0; j < analysisList.size(); j++) {
            if (analysisList.get(j).getClassId() != null) {
                if (prev == null || !prev.getHighScoreRate().equals(analysisList.get(j).getHighScoreRate())) {
                    showRank++;
                } else {
                    showRank = realRank;
                }
                analysisList.get(j).setHighScoreRank(showRank);
                realRank++;
                prev = analysisList.get(j);
            }
        }
        // 优秀排名
        showRank = 0;
        realRank = 1;
        prev = null;
        analysisList =
                analysisList.stream().sorted((y, x) -> x.getExcellentScoreRate().compareTo(y.getExcellentScoreRate())).collect(Collectors.toList());
        for (int j = 0; j < analysisList.size(); j++) {
            if (analysisList.get(j).getClassId() != null) {
                if (prev == null || !prev.getExcellentScoreRate().equals(analysisList.get(j).getExcellentScoreRate())) {
                    showRank++;
                } else {
                    showRank = realRank;
                }
                analysisList.get(j).setExcellentScoreRank(showRank);
                realRank++;
                prev = analysisList.get(j);
            }
        }
        // 良好排名
        showRank = 0;
        realRank = 1;
        prev = null;
        analysisList =
                analysisList.stream().sorted((y, x) -> x.getGoodScoreRate().compareTo(y.getGoodScoreRate())).collect(Collectors.toList());
        for (int j = 0; j < analysisList.size(); j++) {
            if (analysisList.get(j).getClassId() != null) {
                if (prev == null || !prev.getGoodScoreRate().equals(analysisList.get(j).getGoodScoreRate())) {
                    showRank++;
                } else {
                    showRank = realRank;
                }
                analysisList.get(j).setGoodScoreRank(showRank);
                realRank++;
                prev = analysisList.get(j);
            }
        }
        // 及格排名
        showRank = 0;
        realRank = 1;
        prev = null;
        analysisList =
                analysisList.stream().sorted((y, x) -> x.getPassScoreRate().compareTo(y.getPassScoreRate())).collect(Collectors.toList());
        for (int j = 0; j < analysisList.size(); j++) {
            if (analysisList.get(j).getClassId() != null) {
                if (prev == null || !prev.getPassScoreRate().equals(analysisList.get(j).getPassScoreRate())) {
                    showRank++;
                } else {
                    showRank = realRank;
                }
                analysisList.get(j).setPassScoreRank(showRank);
                realRank++;
                prev = analysisList.get(j);
            }
        }
        // 低分排名
        showRank = 0;
        realRank = 1;
        prev = null;
        analysisList =
                analysisList.stream().sorted((y, x) -> y.getLowScoreRate().compareTo(x.getLowScoreRate())).collect(Collectors.toList());
        for (int j = 0; j < analysisList.size(); j++) {
            if (analysisList.get(j).getClassId() != null) {
                if (prev == null || !prev.getLowScoreRate().equals(analysisList.get(j).getLowScoreRate())) {
                    showRank++;
                } else {
                    showRank = realRank;
                }
                analysisList.get(j).setLowScoreRank(showRank);
                realRank++;
                prev = analysisList.get(j);
            }
        }
        // 综合率
        showRank = 0;
        realRank = 1;
        prev = null;
        analysisList =
                analysisList.stream().sorted((y, x) -> x.getComplexScoreRate().compareTo(y.getComplexScoreRate())).collect(Collectors.toList());
        for (int j = 0; j < analysisList.size(); j++) {
            if (analysisList.get(j).getClassId() != null) {
                if (prev == null || !prev.getComplexScoreRate().equals(analysisList.get(j).getComplexScoreRate())) {
                    showRank++;
                } else {
                    showRank = realRank;
                }
                analysisList.get(j).setComplexScoreRank(showRank);
                realRank++;
                prev = analysisList.get(j);
            }
        }
        analysisList.add(0, all);
        analysisList = analysisList.stream().filter(
                x -> x.getClassId() == null
                        || cn.hutool.core.collection.CollUtil.contains(dto.getClassIds(), x.getClassId())
        ).collect(Collectors.toList());

        return analysisList;
    }

    @Override
    public List<ScoreSectionStasticVO> scoreSectionStasticDTO(ScoreSectionStasticDTO dto) {
        if (coreExaminationStudentMapper.selectCount(Wrappers.lambdaQuery(new CoreExaminationStudent())
                .eq(CoreExaminationStudent::getCoreExaminationId, dto.getExamId())) == 0) {
            return null;
        }
        // 构建分数区间
        List<ScoreSectionVO> sectionList = new ArrayList<>();
        Double bottom = dto.getMinScore();
        Double top = dto.getScoreInterval() + bottom;
        while (top <= dto.getMaxScore()) {
            ScoreSectionVO section = new ScoreSectionVO();
            section.setTop(top);
            section.setBottom(bottom);
            section.setStudentNum(0);
            sectionList.add(section);
            bottom += dto.getScoreInterval();
            top += dto.getScoreInterval();
        }
        if (top > dto.getMaxScore() && bottom < dto.getMaxScore()) {
            ScoreSectionVO section = new ScoreSectionVO();
            top = dto.getMaxScore();
            section.setTop(top);
            section.setBottom(bottom);
            section.setStudentNum(0);
            sectionList.add(section);
        }
        // 查询分数信息
        List<CoreExaminationStudent> studentList = null;
        List<CoreExaminationStudentCourse> studentCourseList = null;
        if (dto.getCourseId() == null) {
            studentList =
                    coreExaminationStudentMapper.selectList(Wrappers.lambdaQuery(new CoreExaminationStudent())
                            .eq(CoreExaminationStudent::getCoreExaminationId, dto.getExamId())
                            .eq(CoreExaminationStudent::getMiss, "0"));
        } else {
            studentCourseList =
                    coreExaminationStudentCourseMapper.selectList(Wrappers.lambdaQuery(new CoreExaminationStudentCourse())
                            .eq(CoreExaminationStudentCourse::getCoreExaminationId, dto.getExamId())
                            .eq(CoreExaminationStudentCourse::getCoreExaminationCourseId, dto.getCourseId()));
        }
        List<ScoreSectionStasticVO> stasticList =
                dto.getCourseId() != null ? coreExaminationStudentMapper.getCourseScoreSectionStastic(dto)
                        : coreExaminationStudentMapper.getScoreSectionStastic(dto);
        // 遍历填充区间信息
        for (ScoreSectionStasticVO stastic : stasticList) {
            List<ScoreSectionVO> copySectionList = CollUtil.deepCopy(sectionList);
            if (dto.getCourseId() == null) {
                for (CoreExaminationStudent student : studentList) {
                    for (ScoreSectionVO vo : copySectionList) {
                        if (stastic.getClassId() == null || stastic.getClassId().equals(student.getClassId())) {
                            if (student.getScore() > vo.getBottom() && student.getScore() <= vo.getTop()) {
                                vo.setStudentNum(vo.getStudentNum() + 1);
                            }
                        }
                    }
                }
            } else {
                for (CoreExaminationStudentCourse student : studentCourseList) {
                    for (ScoreSectionVO vo : copySectionList) {
                        if (stastic.getClassId() == null || stastic.getClassId().equals(student.getClassId())) {
                            if (student.getScore() > vo.getBottom() && student.getScore() <= vo.getTop()) {
                                vo.setStudentNum(vo.getStudentNum() + 1);
                            }
                        }
                    }
                }
            }
            for (ScoreSectionVO section : copySectionList) {
                section.setPercent(section.getStudentNum() * 100D / stastic.getStudentNum());
            }
            stastic.setSectionList(copySectionList);
        }
        return stasticList;
    }

    @Override
    public ScoreDistributeVO scoreDistribute(Long examId, Long studentId, Long courseId) {
        CoreExamination exam = coreExaminationMapper.selectById(examId);
        CoreExaminationPublish publish = coreExaminationPublishMapper.selectOne(Wrappers.lambdaQuery(new CoreExaminationPublish())
                .eq(CoreExaminationPublish::getCoreExaminationId, examId));
        ScoreDistributeVO vo = new ScoreDistributeVO();
        List<ScoreSectionVO> sectionList = null;
        Integer sectionScore = courseId == null ? publish.getScoreSection() : publish.getCourseScoreSection();
        CoreExaminationStudent nowStudent = coreExaminationStudentMapper.selectOne(Wrappers.lambdaQuery(new CoreExaminationStudent())
                .eq(CoreExaminationStudent::getCoreExaminationId, examId)
                .eq(CoreExaminationStudent::getCoreStudentId, studentId));
        CoreExaminationPublishRecord courseRecord = null;
        CoreExaminationCourse scoreCourse =
                coreExaminationCourseMapper.selectOne(Wrappers.lambdaQuery(new CoreExaminationCourse())
                        .eq(CoreExaminationCourse::getCoreExaminationId, examId)
                        .eq(CoreExaminationCourse::getCoreCourseId, courseId));
        Double allScore = courseId == null ? exam.getScore() : scoreCourse.getCoreCourseScore();
        // 划分分数区间
        // 未进行等级转换
        if (courseId != null) {
            courseRecord =
                    coreExaminationPublishRecordMapper.selectOne(Wrappers.lambdaQuery(new CoreExaminationPublishRecord())
                            .eq(CoreExaminationPublishRecord::getCoreExaminationId, examId)
                            .eq(CoreExaminationPublishRecord::getCoreStudentId, studentId)
                            .eq(CoreExaminationPublishRecord::getCoreExaminationCourseId, courseId));
        }
        if (publish.getScoreBlock() == 0) {
            if (courseId == null) {
                sectionList = divideSection(exam.getScore(), sectionScore);
            } else {
                sectionList = divideSection(scoreCourse.getCoreCourseScore(), sectionScore);
            }
        } else {
            // 进行了等级转换
            List<CoreExaminationPublishGradeConvertType> typeList = coreExaminationPublishGradeConvertTypeMapper.listType(examId);
            sectionList = new ArrayList<>();
            for (CoreExaminationPublishGradeConvertType type : typeList) {
                ScoreSectionVO section = new ScoreSectionVO();
                section.setLevel(type.getLevel());
                section.setTop(type.getMaxScore() * allScore / 100);
                section.setBottom(type.getMinScore() * allScore / 100);
                section.setStudentNum(0);
                sectionList.add(section);
            }
        }
        // 查询分数信息
        List<CoreExaminationStudent> studentList = null;
        List<CoreExaminationStudentCourse> studentCourseList = null;
        if (courseId == null) {
            studentList =
                    coreExaminationStudentMapper.selectList(Wrappers.lambdaQuery(new CoreExaminationStudent())
                            .eq(CoreExaminationStudent::getCoreExaminationId, examId)
                            .eq(CoreExaminationStudent::getMiss, "0"));
        } else {
            studentCourseList =
                    coreExaminationStudentCourseMapper.selectList(Wrappers.lambdaQuery(new CoreExaminationStudentCourse())
                            .eq(CoreExaminationStudentCourse::getCoreExaminationId, examId)
                            .eq(CoreExaminationStudentCourse::getCoreExaminationCourseId, courseId));
        }
        // 遍历填充区间信息
        for (ScoreSectionVO sectionVO : sectionList) {
            if (courseId == null) {
                for (CoreExaminationStudent student : studentList) {
                    if (sectionVO.getTop() >= student.getScore() && sectionVO.getBottom() < student.getScore()) {
                        sectionVO.setStudentNum(sectionVO.getStudentNum() + 1);
                    }
                }
            } else {
                for (CoreExaminationStudentCourse studentCourse : studentCourseList) {
                    if (studentCourse.getScore() > sectionVO.getBottom() && studentCourse.getScore() <= sectionVO.getTop()) {
                        sectionVO.setStudentNum(sectionVO.getStudentNum() + 1);
                    }
                }
            }
        }
        if (publish.getScoreBlock() == 0) {
            // 合并首部空白区间
            while (sectionList.size() > 1) {
                if (sectionList.get(0).getStudentNum() == 0) {
                    sectionList.get(0).setTop(sectionList.get(1).getTop());
                    sectionList.get(0).setStudentNum(sectionList.get(1).getStudentNum());
                    sectionList.remove(1);
                    continue;
                }
                break;
            }
            // 合并尾部空白区间
            while (sectionList.size() > 1) {
                if (sectionList.get(sectionList.size() - 1).getStudentNum() == 0) {
                    sectionList.get(sectionList.size() - 1).setBottom(sectionList.get(sectionList.size() - 2).getBottom());
                    sectionList.get(sectionList.size() - 1).setStudentNum(sectionList.get(sectionList.size() - 2).getStudentNum());
                    sectionList.remove(sectionList.size() - 2);
                    continue;
                }
                break;
            }
        }
        // 当前考生分数区间
        int index = 0;
        for (ScoreSectionVO sectionVO : sectionList) {
            if (courseId == null) {
                if (sectionVO.getTop() >= nowStudent.getScore() && sectionVO.getBottom() < nowStudent.getScore()) {
                    vo.setBottom(sectionVO.getBottom());
                    vo.setTop(sectionVO.getTop());
                    vo.setLevel(sectionVO.getLevel());
                    vo.setGradeStudentNum(sectionVO.getStudentNum());
                    vo.setIndex(index);
                }
            } else {
                if (sectionVO.getTop() >= courseRecord.getScore() && sectionVO.getBottom() < courseRecord.getScore()) {
                    vo.setBottom(sectionVO.getBottom());
                    vo.setTop(sectionVO.getTop());
                    vo.setLevel(sectionVO.getLevel());
                    vo.setGradeStudentNum(sectionVO.getStudentNum());
                    vo.setIndex(index);
                }
            }
            index++;
        }
        // 班级人数与年级人数
        CoreExaminationStudent finalNowStudent = nowStudent;
        vo.setClassStudentNum((int) (courseId == null
                ? studentList.stream()
                .filter(x -> x.getClassId().equals(finalNowStudent.getClassId()) && x.getScore() > vo.getBottom() && x.getScore() <= vo.getTop())
                .count()
                : studentCourseList.stream()
                .filter(x -> x.getClassId().equals(finalNowStudent.getClassId()) && x.getScore() > vo.getBottom() && x.getScore() <= vo.getTop())
                .count()
        ));
        vo.setSectionList(sectionList);
        return vo;
    }

    @Override
    public List<ScoreTrendVO> scoreTrend(Long examId, Long studentId, Long courseId) {
        CoreExamination exam = coreExaminationMapper.selectById(examId);
        LocalDate examStartDate = exam.getStartDate();
        LocalDate startDate, endDate;
        if (examStartDate.getMonthValue() >= 9) {
            startDate = LocalDate.of(examStartDate.getYear(), 9, 1);
            endDate = LocalDate.of(examStartDate.getYear() + 1, 8, 31);
        } else {
            startDate = LocalDate.of(examStartDate.getYear() - 1, 9, 1);
            endDate = LocalDate.of(examStartDate.getYear(), 8, 31);
        }
        List<ScoreTrendVO> scoreTrend = courseId == null
                ? coreExaminationStudentMapper.findScoreTrend(startDate, endDate, studentId)
                : coreExaminationPublishRecordMapper.findScoreTrend(startDate, endDate, studentId, courseId);
        return scoreTrend;
    }

    @Override
    public List<ScoreAndAvgCompareVO> scoreAndAvgCompare(Long examId, Long studentId) {
        List<ScoreAndAvgCompareVO> voList = new ArrayList<>();
        CoreExaminationStudent student = coreExaminationStudentMapper.selectOne(Wrappers.lambdaQuery(new CoreExaminationStudent())
                .eq(CoreExaminationStudent::getCoreExaminationId, examId)
                .eq(CoreExaminationStudent::getCoreStudentId, studentId));
        // 班级
        List<EduExamAvg> classAvgList = eduExamAvgMapper.selectList(Wrappers.lambdaQuery(new EduExamAvg())
                .eq(EduExamAvg::getExamId, examId)
                .eq(EduExamAvg::getDeptId, student.getClassId())
                .eq(EduExamAvg::getDeptType, 0));
        // 年级
        List<EduExamAvg> gradeAvgList = eduExamAvgMapper.selectList(Wrappers.lambdaQuery(new EduExamAvg())
                .eq(EduExamAvg::getExamId, examId)
                .eq(EduExamAvg::getDeptId, student.getGradeId())
                .eq(EduExamAvg::getDeptType, 1));
        // 各科分数
        List<CoreExaminationPublishRecord> studentCourseList =
                coreExaminationPublishRecordMapper.selectList(Wrappers.lambdaQuery(new CoreExaminationPublishRecord())
                        .eq(CoreExaminationPublishRecord::getCoreExaminationId, examId)
                        .eq(CoreExaminationPublishRecord::getCoreExaminationStudentId, student.getId()));
        for (CoreExaminationPublishRecord studentCourse : studentCourseList) {
            ScoreAndAvgCompareVO vo = new ScoreAndAvgCompareVO();
            vo.setScore(studentCourse.getScore());
            vo.setScoreRate(studentCourse.getScore() * 100 / studentCourse.getCourseScore());
            vo.setCourseName(studentCourse.getCoreExaminationCourseName());
            // 遍历填充班级平均
            for (EduExamAvg classAvg : classAvgList) {
                if (studentCourse.getCoreExaminationCourseId().equals(classAvg.getCourseId())) {
                    vo.setClassAvgScore(classAvg.getScoreAvg());
                    vo.setClassAvgScoreRate(classAvg.getScoreAvgRate());
                }
            }
            // 遍历填充年级平均
            for (EduExamAvg gradeAvg : gradeAvgList) {
                if (studentCourse.getCoreExaminationCourseId().equals(gradeAvg.getCourseId())) {
                    vo.setGradeAvgScore(gradeAvg.getScoreAvg());
                    vo.setGradeAvgScoreRate(gradeAvg.getScoreAvgRate());
                }
            }
            voList.add(vo);
        }
        return voList;
    }

    private List<ScoreSectionVO> divideSection(Double score, Integer sectionScore) {
        List<ScoreSectionVO> sectionList = new ArrayList<>();
        Double top = score;
        Double bottom = score - sectionScore;
        while (bottom >= 0) {
            ScoreSectionVO section = new ScoreSectionVO();
            section.setTop(top);
            section.setBottom(bottom);
            section.setStudentNum(0);
            sectionList.add(section);
            bottom -= sectionScore;
            top -= sectionScore;
        }
        if (bottom < 0 && top > 0) {
            ScoreSectionVO section = new ScoreSectionVO();
            section.setTop(top);
            section.setBottom(0D);
            section.setStudentNum(0);
            sectionList.add(section);
        }
        sectionList.sort((x, y) -> x.getBottom().compareTo(y.getBottom()));
        return sectionList;
    }
}
