package com.qmth.teachcloud.report.business.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qmth.teachcloud.common.bean.params.UserSaveParams;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.SysOrg;
import com.qmth.teachcloud.common.entity.SysRole;
import com.qmth.teachcloud.common.entity.SysUser;
import com.qmth.teachcloud.common.enums.DimensionEnum;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.enums.RoleTypeEnum;
import com.qmth.teachcloud.common.service.BasicCourseService;
import com.qmth.teachcloud.common.service.SysOrgService;
import com.qmth.teachcloud.common.service.SysRoleService;
import com.qmth.teachcloud.common.service.SysUserService;
import com.qmth.teachcloud.report.business.bean.dto.BasicExamCourseDataMd5;
import com.qmth.teachcloud.report.business.bean.dto.printOpen.*;
import com.qmth.teachcloud.report.business.bean.dto.query.TBSchoolClazzDto;
import com.qmth.teachcloud.report.business.bean.dto.query.TBSchoolCollegeDto;
import com.qmth.teachcloud.report.business.bean.dto.query.TBSchoolTeacherDto;
import com.qmth.teachcloud.report.business.entity.*;
import com.qmth.teachcloud.report.business.enums.NumberTypeEnum;
import com.qmth.teachcloud.report.business.service.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Description: 分析数据获取和编辑服务实现类
 * @Author: CaoZixuan
 * @Date: 2022-06-08
 */
@Service
public class AnalyzeDataGetAndEditServiceImpl implements AnalyzeDataGetAndEditService {
    @Resource
    private CallPrintOpenApiService callPrintOpenApiService;
    @Resource
    private TBExamCourseService tbExamCourseService;
    @Resource
    private BasicCourseService basicCourseService;

    @Resource
    private TBPaperService tbPaperService;
    @Resource
    private TBDimensionService tbDimensionService;
    @Resource
    private TBPaperStructService tbPaperStructService;
    @Resource
    private TBModuleProficiencyService tbModuleProficiencyService;
    @Resource
    private TBModuleConfigService tbModuleConfigService;
    @Resource
    private TBSchoolClazzService tbSchoolClazzService;
    @Resource
    private SysOrgService sysOrgService;
    @Resource
    private SysUserService sysUserService;
    @Resource
    private SysRoleService sysRoleService;
    @Resource
    private TBStudentService tbStudentService;
    @Resource
    private TBExamService tbExamService;
    @Resource
    private TBExamStudentService tbExamStudentService;
    @Resource
    private TBExamRecordService tbExamRecordService;
    @Resource
    private TBAnswerService tbAnswerService;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean tbPaperDispose(Long examId, String courseCode, Long schoolId) throws IOException {
        boolean repeat = false;
        if (tbExamCourseService.verifyExamCourseCantRun(examId, schoolId, courseCode, null)) {
            throw ExceptionResultEnum.ERROR.exception("课程编号为【" + courseCode + "】的课程不能进行数据更改");
        }
        String courseName = basicCourseService.findByCourseCode(courseCode, schoolId).getName();
        PaperConfig paperConfig = callPrintOpenApiService.callPaperConfig(schoolId, examId, courseCode);
        // md5 检验
        TBExamCourse tbExamCourse = tbExamCourseService.getOne(new QueryWrapper<TBExamCourse>().lambda()
                .eq(TBExamCourse::getSchoolId, schoolId)
                .eq(TBExamCourse::getExamId, examId)
                .eq(TBExamCourse::getCourseCode, courseCode));
        BasicExamCourseDataMd5 md5 = JSON.parseObject(tbExamCourse.getOpenDataMd5(), BasicExamCourseDataMd5.class);
        String oldMd5 = "";
        if (Objects.nonNull(md5)) {
            oldMd5 = md5.getPaperMd5();
        } else {
            md5 = new BasicExamCourseDataMd5();
        }
        String currentMd5 = this.buildPaperDataMd5(paperConfig);
        if (!currentMd5.equals(oldMd5)) {
            // md5 不一致需要重算
            repeat = true;
            md5.setPaperMd5(currentMd5);
            tbExamCourse.setOpenDataMd5(JSON.toJSONString(md5));
            tbExamCourseService.saveOrUpdate(tbExamCourse);


            BigDecimal coefficient = BigDecimal.ZERO;
            if (Objects.nonNull(paperConfig.getCoefficient())) {
                coefficient = BigDecimal.valueOf(Double.parseDouble(String.valueOf(paperConfig.getCoefficient())));
            }
            String paperType = paperConfig.getPaperType();
            List<TBPaper> oldList = tbPaperService.list(new QueryWrapper<TBPaper>().lambda()
                    .eq(TBPaper::getExamId, examId).eq(TBPaper::getCourseCode, courseCode).eq(TBPaper::getPaperType, paperType));
            Long id;
            if (oldList.size() == 1) {
                id = oldList.get(0).getId();
            } else if (oldList.size() < 1) {
                id = SystemConstant.getDbUuid();
            } else {
                throw ExceptionResultEnum.ERROR.exception("表数据异常[t_b_paper]");
            }

            TBPaper tbPaper = new TBPaper();
            tbPaper.setExamId(examId);
            tbPaper.setCourseCode(courseCode);
            tbPaper.setCourseName(courseName);
            tbPaper.setPaperType(paperConfig.getPaperType());
            Long startTime = tbPaper.getStartTime();
            Long endTime = tbPaper.getEndTime();
            if (!SystemConstant.isOneNull(startTime, endTime)) {
                tbPaper.setStartTime(startTime);
                tbPaper.setEndTime(endTime);
            }
            tbPaper.setCoefficient(coefficient);
            tbPaper.setTotalScore(paperConfig.getTotalScore());
            tbPaper.setPassScore(paperConfig.getPassScore());
            tbPaper.setScoreType(paperConfig.getScoreType());
            tbPaper.setId(id);
            tbPaperService.saveOrUpdate(tbPaper);
        }
        return repeat;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean tbPaperDimensionDispose(Long examId, String courseCode, Long schoolId) throws IOException {
        boolean repeat = false;
        if (tbExamCourseService.verifyExamCourseCantRun(examId, schoolId, courseCode, null)) {
            throw ExceptionResultEnum.ERROR.exception("课程编号为【" + courseCode + "】的课程不能进行数据更改");
        }
        List<PaperDimension> paperDimensionList = callPrintOpenApiService.callPaperDimension(schoolId, examId, courseCode);

        // md5 检验
        TBExamCourse tbExamCourse = tbExamCourseService.getOne(new QueryWrapper<TBExamCourse>().lambda()
                .eq(TBExamCourse::getSchoolId, schoolId)
                .eq(TBExamCourse::getExamId, examId)
                .eq(TBExamCourse::getCourseCode, courseCode));
        BasicExamCourseDataMd5 md5 = JSON.parseObject(tbExamCourse.getOpenDataMd5(), BasicExamCourseDataMd5.class);
        String oldMd5 = "";
        if (Objects.nonNull(md5)) {
            oldMd5 = md5.getDimensionMd5();
        }
        String currentMd5 = this.buildDimensionDataMd5(paperDimensionList);
        if (!currentMd5.equals(oldMd5)) {
            // md5 不一致需要重算
            repeat = true;
            md5.setDimensionMd5(currentMd5);
            tbExamCourse.setOpenDataMd5(JSON.toJSONString(md5));
            tbExamCourseService.saveOrUpdate(tbExamCourse);
            // -- --

            String courseName = basicCourseService.findByCourseCode(courseCode, schoolId).getName();
            List<TBDimension> old = tbDimensionService.list(new QueryWrapper<TBDimension>().lambda().eq(TBDimension::getExamId, examId).eq(TBDimension::getCourseCode, courseCode));
            if (old != null && old.size() > 0) {
                repeat = this.checkTBDimensionRepeat(old, paperDimensionList);
            }

            List<TBDimension> tbDimensionList = paperDimensionList.stream().flatMap(e -> {
                TBDimension tbDimension = new TBDimension();
                tbDimension.setId(SystemConstant.getDbUuid());
                tbDimension.setExamId(examId);
                tbDimension.setCourseCode(courseCode);
                tbDimension.setCourseName(courseName);
                tbDimension.setDimensionType(e.getDimensionType().getDesc());
                tbDimension.setCodePrimary(e.getCodePrimary());
                tbDimension.setNamePrimary(e.getNamePrimary());
                tbDimension.setCodeSecond(e.getCodeSecond());
                tbDimension.setNameSecond(e.getNameSecond());
                tbDimension.setInterpretation(e.getInterpretation());
                return Stream.of(tbDimension);
            }).collect(Collectors.toList());
            // 根据课程编号删除已有
            tbDimensionService.remove(new QueryWrapper<TBDimension>().lambda().eq(TBDimension::getExamId, examId).eq(TBDimension::getCourseCode, courseCode));
            // 批量新增
            tbDimensionService.saveBatch(tbDimensionList);
        }
        return repeat;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean tbPaperStructDispose(Long examId, String courseCode, Long schoolId) throws IOException {
        boolean repeat = false;
        if (tbExamCourseService.verifyExamCourseCantRun(examId, schoolId, courseCode, null)) {
            throw ExceptionResultEnum.ERROR.exception("课程编号为【" + courseCode + "】的课程不能进行数据更改");
        }
        List<TBPaper> tbPaperList = tbPaperService.list(new QueryWrapper<TBPaper>().lambda().eq(TBPaper::getExamId, examId).eq(TBPaper::getCourseCode, courseCode));
        if (tbPaperList.size() != 1) {
            throw ExceptionResultEnum.ERROR.exception("未找到考试id为【" + examId + "】,课程编号为【" + courseCode + "】的唯一试卷");
        }
        TBPaper tbPaper = tbPaperList.get(0);
        Long paperId = tbPaper.getId();

        List<PaperStructure> paperStructureList = callPrintOpenApiService.callPaperStruct(schoolId, examId, courseCode);

        // md5 检验
        TBExamCourse tbExamCourse = tbExamCourseService.getOne(new QueryWrapper<TBExamCourse>().lambda()
                .eq(TBExamCourse::getSchoolId, schoolId)
                .eq(TBExamCourse::getExamId, examId)
                .eq(TBExamCourse::getCourseCode, courseCode));
        BasicExamCourseDataMd5 md5 = JSON.parseObject(tbExamCourse.getOpenDataMd5(), BasicExamCourseDataMd5.class);
        String oldMd5 = "";
        if (Objects.nonNull(md5)) {
            oldMd5 = md5.getStructMd5();
        }
        String currentMd5 = this.buildStructDataMd5(paperStructureList);
        //因为t_b_paper表是做更新操作的所以当结构数据md5一致，即使是t_b_paper的数据改了，也不影响试卷结构数据所绑定的paper_id 所以不用重新算
        if (!currentMd5.equals(oldMd5)) {
            // md5 不一致需要重算
            repeat = true;
            md5.setStructMd5(currentMd5);
            tbExamCourse.setOpenDataMd5(JSON.toJSONString(md5));
            tbExamCourseService.saveOrUpdate(tbExamCourse);
            // -- --
            List<TBDimension> tbDimensionList = tbDimensionService.list(new QueryWrapper<TBDimension>()
                    .lambda()
                    .eq(TBDimension::getExamId, examId)
                    .eq(TBDimension::getCourseCode, courseCode));

            // 知识 - 二级维度
            List<String> knowledgeDatasource = tbDimensionList.stream()
                    .filter(e -> DimensionEnum.KNOWLEDGE.getDesc().equals(e.getDimensionType()))
                    .map(TBDimension::getCodeSecond).distinct()
                    .collect(Collectors.toList());
            // 能力 - 一级维度
            List<String> abilityDatasource = tbDimensionList.stream()
                    .filter(e -> DimensionEnum.ABILITY.getDesc().equals(e.getDimensionType()))
                    .map(TBDimension::getCodePrimary).distinct()
                    .collect(Collectors.toList());

            List<TBPaperStruct> tbPaperStructList = paperStructureList.stream().flatMap(e -> {
                TBPaperStruct tbPaperStruct = new TBPaperStruct();
                tbPaperStruct.setId(SystemConstant.getDbUuid());
                tbPaperStruct.setPaperId(paperId);
                tbPaperStruct.setQuestionName(e.getQuestionName());
                tbPaperStruct.setNumberType(e.getNumberType().getDesc());
                tbPaperStruct.setBigQuestionNumber(e.getBigQuestionNumber());
                tbPaperStruct.setSmallQuestionNumber(e.getSmallQuestionNumber());
                tbPaperStruct.setQuestionType(e.getBigTopicName());
                tbPaperStruct.setFullScore(e.getFullScore());
                tbPaperStruct.setScoreRules(e.getScoreRules());
                String knowledgeDimension = e.getKnowledgeDimension();
                String abilityDimension = e.getAbilityDimension();
                // 校验试卷结构每题的维度点都在该科目的维度池中（知识二级能力一级）
                if (SystemConstant.strNotNull(knowledgeDimension)) {
                    for (String knowledge : knowledgeDimension.split(",")) {
                        if (!knowledgeDatasource.contains(knowledge)) {
                            throw ExceptionResultEnum.ERROR.exception("试卷结构知识点二级维度【" + knowledge + "】不在知识维度池中");
                        }
                    }
                    tbPaperStruct.setKnowledgeDimension(knowledgeDimension);
                }
                if (SystemConstant.strNotNull(abilityDimension)) {
                    for (String ability : abilityDimension.split(",")) {
                        if (!abilityDatasource.contains(ability)) {
                            throw ExceptionResultEnum.ERROR.exception("试卷结构能力点一级维度【" + ability + "】不在能力维度池中");
                        }
                    }
                    tbPaperStruct.setAbilityDimension(abilityDimension);
                }
                return Stream.of(tbPaperStruct);
            }).collect(Collectors.toList());

            // 删除试卷id下所有试卷结构
            tbPaperStructService.remove(new QueryWrapper<TBPaperStruct>().lambda().eq(TBPaperStruct::getPaperId, paperId));
            // 新增试卷id下的试卷结构
            tbPaperStructService.saveBatch(tbPaperStructList);
        }
        return repeat;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean tbPaperModuleDispose(Long examId, String courseCode, Long schoolId) throws IOException {
        boolean repeat = false;
        if (tbExamCourseService.verifyExamCourseCantRun(examId, schoolId, courseCode, null)) {
            throw ExceptionResultEnum.ERROR.exception("课程编号为【" + courseCode + "】的课程不能进行数据更改");
        }
        String courseName = basicCourseService.findByCourseCode(courseCode, schoolId).getName();
        List<PaperEvaluation> paperEvaluationList = callPrintOpenApiService.callPaperModule(schoolId, examId, courseCode);

        // md5 检验
        TBExamCourse tbExamCourse = tbExamCourseService.getOne(new QueryWrapper<TBExamCourse>().lambda()
                .eq(TBExamCourse::getSchoolId, schoolId)
                .eq(TBExamCourse::getExamId, examId)
                .eq(TBExamCourse::getCourseCode, courseCode));
        BasicExamCourseDataMd5 md5 = JSON.parseObject(tbExamCourse.getOpenDataMd5(), BasicExamCourseDataMd5.class);
        String oldMd5 = "";
        if (Objects.nonNull(md5)) {
            oldMd5 = md5.getModuleMd5();
        }
        String currentMd5 = this.buildModuleDataMd5(paperEvaluationList);
        if (!currentMd5.equals(oldMd5)) {
            // md5 不一致需要重算
            repeat = true;
            md5.setModuleMd5(currentMd5);
            tbExamCourse.setOpenDataMd5(JSON.toJSONString(md5));
            tbExamCourseService.saveOrUpdate(tbExamCourse);
            // -- --

            List<TBModuleProficiency> tbModuleProficiencyList = new ArrayList<>();
            List<TBModuleConfig> tbModuleConfigList = new ArrayList<>();
            Map<DimensionEnum, PaperEvaluation> checkDimensionType = new HashMap<>();
            for (PaperEvaluation paperEvaluation : paperEvaluationList) {
                // 校验大的数据结构
                DimensionEnum moduleType = paperEvaluation.getModuleType();
                if (checkDimensionType.containsKey(moduleType)) {
                    throw ExceptionResultEnum.ERROR.exception("模块数据存在相同模块类型【" + moduleType + "】异常");
                }
                checkDimensionType.put(moduleType, paperEvaluation);

                String interpret = paperEvaluation.getInterpret();
                String remark = paperEvaluation.getRemark();
                String formula = paperEvaluation.getFormula().getDesc();

                // 解析并生成't_b_module_proficiency' 二级维度精熟度
                List<SecondaryDimensionLevelDefine> secondaryDimensionLevelDefineList = paperEvaluation.getSecondaryDimensionLevelDefineList();
                List<TBModuleProficiency> tbModuleProficiencyCell = secondaryDimensionLevelDefineList.stream().flatMap(e -> {
                    TBModuleProficiency tbModuleProficiency = new TBModuleProficiency();
                    tbModuleProficiency.setId(SystemConstant.getDbUuid());
                    tbModuleProficiency.setExamId(examId);
                    tbModuleProficiency.setCourseCode(courseCode);
                    tbModuleProficiency.setCourseName(courseName);
                    tbModuleProficiency.setModuleType(moduleType.getDesc());
                    tbModuleProficiency.setInterpret(interpret);
                    tbModuleProficiency.setRemark(remark);
                    tbModuleProficiency.setDefine(SystemConstant.strNotNull(e.getDefine()) ? e.getDefine().trim() : null);
                    tbModuleProficiency.setLevel(e.getLevel());
                    tbModuleProficiency.setMin(e.getMin());
                    tbModuleProficiency.setMax(e.getMax());
                    tbModuleProficiency.setScope(e.getScope());
                    return Stream.of(tbModuleProficiency);
                }).collect(Collectors.toList());
                tbModuleProficiencyList.addAll(tbModuleProficiencyCell);

                // 解析并生成't_b_module_config' 维度模块等级评价及建议
                List<ModuleEvaluation> moduleEvaluationList = paperEvaluation.getModuleEvaluationList();
                List<TBModuleConfig> tbModuleConfigCell = moduleEvaluationList.stream().flatMap(e -> {
                    TBModuleConfig tbModuleConfig = new TBModuleConfig();
                    tbModuleConfig.setId(SystemConstant.getDbUuid());
                    tbModuleConfig.setExamId(examId);
                    tbModuleConfig.setCourseCode(courseCode);
                    tbModuleConfig.setCourseName(courseName);
                    tbModuleConfig.setModuleType(moduleType.getDesc());
                    tbModuleConfig.setFormula(formula);
                    tbModuleConfig.setScope(e.getScope());
                    tbModuleConfig.setLevelCode(e.getLevelCode());
                    tbModuleConfig.setLevelName(e.getLevelName());
                    tbModuleConfig.setResult(e.getResult());
                    tbModuleConfig.setAdvice(e.getAdvice());
                    if (DimensionEnum.KNOWLEDGE.equals(moduleType)) {
                        tbModuleConfig.setAttribute("knowledgeDimension");
                    } else if (DimensionEnum.ABILITY.equals(moduleType)) {
                        tbModuleConfig.setAttribute("abilityDimension");
                    }
                    return Stream.of(tbModuleConfig);
                }).collect(Collectors.toList());
                tbModuleConfigList.addAll(tbModuleConfigCell);
            }
            // 删除后新增
            tbModuleProficiencyService.remove(new QueryWrapper<TBModuleProficiency>().lambda()
                    .eq(TBModuleProficiency::getExamId, examId)
                    .eq(TBModuleProficiency::getCourseCode, courseCode));
            tbModuleProficiencyService.saveBatch(tbModuleProficiencyList);

            tbModuleConfigService.remove(new QueryWrapper<TBModuleConfig>().lambda()
                    .eq(TBModuleConfig::getExamId, examId)
                    .eq(TBModuleConfig::getCourseCode, courseCode));
            tbModuleConfigService.saveBatch(tbModuleConfigList);
        }
        return repeat;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean tbExamStudentScoreDatasourceDispose(Long examId, String courseCode, Long schoolId) throws IOException {
        boolean repeat = false;
        if (tbExamCourseService.verifyExamCourseCantRun(examId, schoolId, courseCode, null)) {
            throw ExceptionResultEnum.ERROR.exception("课程编号为【" + courseCode + "】的课程不能进行数据更改");
        }
        String courseName = basicCourseService.findByCourseCode(courseCode, schoolId).getName();
        List<ExamStudentScore> examStudentScoreList = callPrintOpenApiService.callExamStudentScore(schoolId, examId, courseCode);
        // md5 检查
        TBExamCourse tbExamCourse = tbExamCourseService.getOne(new QueryWrapper<TBExamCourse>().lambda()
                .eq(TBExamCourse::getSchoolId, schoolId)
                .eq(TBExamCourse::getExamId, examId)
                .eq(TBExamCourse::getCourseCode, courseCode));
        BasicExamCourseDataMd5 md5 = JSON.parseObject(tbExamCourse.getOpenDataMd5(), BasicExamCourseDataMd5.class);
        String oldMd5 = "";
        if (Objects.nonNull(md5)) {
            oldMd5 = md5.getStudentScoreMd5();
        }
        String currentMd5 = this.buildExamStudentDataMd5(examStudentScoreList);

        //因为t_b_paper表是做更新操作的所以当学生数据md5一致，即使是t_b_paper的数据改了，也不影响学生数据所绑定的paper_id 所以不用重新算
        if (!currentMd5.equals(oldMd5)) {
            // md5 不一致需要重算
            repeat = true;
            md5.setStudentScoreMd5(currentMd5);
            tbExamCourse.setOpenDataMd5(JSON.toJSONString(md5));
            tbExamCourseService.saveOrUpdate(tbExamCourse);
            // -- --

            // 1.创建班级数据
            this.createTBSchoolClazz(examStudentScoreList, schoolId);
            // 2.筛选并创建学校学院表
            this.createCollegeInfo(examStudentScoreList, schoolId);
            // 3.筛选并创建教师
            this.saveTeacherInfo(examStudentScoreList, examId, courseCode, schoolId);
            // 4.创建学生及作答
            this.saveExamStudentScore(examStudentScoreList, examId, courseCode, courseName, schoolId);
        }
        return repeat;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean dataGetAndEdit(Long examId, String courseCode, Long schoolId) throws IOException {
        boolean repeat = false;
        boolean repeatForPaper = this.tbPaperDispose(examId, courseCode, schoolId);
        boolean repeatForDimension = this.tbPaperDimensionDispose(examId, courseCode, schoolId);
        boolean repeatForStruct = this.tbPaperStructDispose(examId, courseCode, schoolId);
        boolean repeatForModule = this.tbPaperModuleDispose(examId, courseCode, schoolId);
        boolean repeatForExamStudentScore = this.tbExamStudentScoreDatasourceDispose(examId, courseCode, schoolId);
        if (repeatForPaper || repeatForDimension || repeatForStruct || repeatForModule || repeatForExamStudentScore) {
            repeat = true;
        }
        return repeat;
    }

    /**
     * 创建基础班级数据
     *
     * @param examStudentScoreList 考生成绩数据源
     * @param schoolId             学校id
     */
    private void createTBSchoolClazz(List<ExamStudentScore> examStudentScoreList, Long schoolId) {
        List<TBSchoolClazzDto> tbSchoolClazzDtoList = new ArrayList<>();
        List<String> clazzList = examStudentScoreList.stream()
                .map(ExamStudentScore::getClassName)
                .distinct().collect(Collectors.toList());
        for (String clazzInfo : clazzList) {
            TBSchoolClazzDto tbSchoolClazzDto = new TBSchoolClazzDto();
            tbSchoolClazzDto.setSchoolId(schoolId);
            tbSchoolClazzDto.setClazzCode(clazzInfo);
            tbSchoolClazzDto.setClazzName(clazzInfo);
            tbSchoolClazzDtoList.add(tbSchoolClazzDto);
        }
        tbSchoolClazzService.saveClazzInfo(tbSchoolClazzDtoList);
    }

    /**
     * 筛选并创建学校学院表
     *
     * @param examStudentScoreList 考生集合
     * @param schoolId             学校id
     */
    private void createCollegeInfo(List<ExamStudentScore> examStudentScoreList, Long schoolId) {
        List<TBSchoolCollegeDto> tbSchoolCollegeDtoList = new ArrayList<>();
        List<String> collegeList = examStudentScoreList.stream()
                .map(ExamStudentScore::getCollege)
                .distinct().collect(Collectors.toList());
        for (String collegeInfo : collegeList) {
            TBSchoolCollegeDto tbSchoolCollegeDto = new TBSchoolCollegeDto();
            tbSchoolCollegeDto.setSchoolId(schoolId);
            tbSchoolCollegeDto.setCollegeCode(collegeInfo);
            tbSchoolCollegeDto.setCollegeName(collegeInfo);
            tbSchoolCollegeDtoList.add(tbSchoolCollegeDto);
        }
        for (TBSchoolCollegeDto tbSchoolCollegeDto : tbSchoolCollegeDtoList) {
            sysOrgService.searchOrInsert(tbSchoolCollegeDto.getSchoolId(), tbSchoolCollegeDto.getCollegeName());
        }
    }


    /**
     * 更新或新增教师信息
     *
     * @param examStudentScoreList 考生集合
     * @param examId               考试id
     * @param courseCode           课程编号
     * @param schoolId             学校id
     */
    private void saveTeacherInfo(List<ExamStudentScore> examStudentScoreList, Long examId, String courseCode, Long schoolId) {
        TBExamCourse tbExamCourse = tbExamCourseService.getOne(new QueryWrapper<TBExamCourse>().lambda()
                .eq(TBExamCourse::getExamId, examId)
                .eq(TBExamCourse::getCourseCode, courseCode)
                .eq(TBExamCourse::getSchoolId, schoolId));
        if (Objects.isNull(tbExamCourse)) {
            throw ExceptionResultEnum.ERROR.exception("缺少课程数据");
        }
        Long teachCollegeId = tbExamCourse.getTeachCollegeId();
        if (!SystemConstant.longNotNull(teachCollegeId)) {
            throw ExceptionResultEnum.ERROR.exception("课程数据缺少开课学院异常");
        }

        Map<String, String> teacherMap = new HashMap<>();
        for (ExamStudentScore examStudentScore : examStudentScoreList) {
            String teacherCode = examStudentScore.getTeacherCode();
            String teacherName = examStudentScore.getTeacherName();
            if (SystemConstant.isOneNull(teacherCode, teacherName)) {
                throw ExceptionResultEnum.ERROR.exception("缺少教师数据");
            }
            if (teacherMap.containsKey(teacherCode)) {
                String value = teacherMap.get(teacherCode);
                if (!teacherName.equals(value)) {
                    throw ExceptionResultEnum.ERROR.exception("教师工号【" + teacherCode + "】对应多个教师名称");
                }
                continue;
            }
            teacherMap.put(teacherCode, teacherName);
        }

        List<TBSchoolTeacherDto> tbSchoolTeacherDtoList = teacherMap.keySet().stream().flatMap(e -> {
            TBSchoolTeacherDto tbSchoolTeacherDto = new TBSchoolTeacherDto();
            tbSchoolTeacherDto.setSchoolId(schoolId);
            tbSchoolTeacherDto.setTeacherCode(e);
            tbSchoolTeacherDto.setTeacherName(teacherMap.get(e));
            tbSchoolTeacherDto.setOrgId(teachCollegeId);
            return Stream.of(tbSchoolTeacherDto);
        }).collect(Collectors.toList());


        Map<String, String> checkMap = new HashMap<>();
        for (TBSchoolTeacherDto tbSchoolTeacherDto : tbSchoolTeacherDtoList) {
            if (checkMap.containsKey(tbSchoolTeacherDto.getTeacherCode())) {
                continue;
            }
            SysUser old = sysUserService.getOne(new QueryWrapper<SysUser>().lambda()
                    .eq(SysUser::getSchoolId, tbSchoolTeacherDto.getSchoolId())
                    .eq(SysUser::getLoginName, tbSchoolTeacherDto.getTeacherCode())
                    .eq(SysUser::getRealName, tbSchoolTeacherDto.getTeacherName()));
            checkMap.put(tbSchoolTeacherDto.getTeacherCode(), tbSchoolTeacherDto.getTeacherName());
            Long id = 0L;
            if (Objects.nonNull(old)) {
                id = old.getId();
            }

            SysRole teacherRole = sysRoleService.list(new QueryWrapper<SysRole>().lambda().eq(SysRole::getType, RoleTypeEnum.TEACHER)).get(0);
            List<Long> roleIds = new ArrayList<>();
            roleIds.add(teacherRole.getId());

            UserSaveParams userSaveParams = new UserSaveParams();
            if (id > 0) {
                userSaveParams.setId(id);
            }


            userSaveParams.setSchoolId(tbSchoolTeacherDto.getSchoolId());
            userSaveParams.setLoginName(tbSchoolTeacherDto.getTeacherCode());
            userSaveParams.setRealName(tbSchoolTeacherDto.getTeacherName());
            userSaveParams.setPassword(SystemConstant.DEFAULT_PASSWORD);
            userSaveParams.setOrgId(tbSchoolTeacherDto.getOrgId());
            userSaveParams.setEnable(true);
            userSaveParams.setRoleIds(roleIds.toArray(new Long[0]));
            sysUserService.saveUserNoAuth(userSaveParams);
        }
    }

    /**
     * 新增处理考生成绩相关数据
     * <p>
     * 1.t_b_student
     * 2.t_b_exam_student
     * 3.t_b_exam_record
     * 4.t_b_answer
     * </p>
     *
     * @param examStudentScoreList 考生成绩相关信息
     * @param examId               考试id
     * @param courseCode           课程编号
     * @param courseName           课程名称
     * @param schoolId             学校id
     */
    private void saveExamStudentScore(List<ExamStudentScore> examStudentScoreList, Long examId, String courseCode, String courseName, Long schoolId) {
        List<TBStudent> tbStudentList = new ArrayList<>();
        List<TBExamStudent> tbExamStudentList = new ArrayList<>();
        List<TBExamRecord> tbExamRecordList = new ArrayList<>();
        List<TBAnswer> tbAnswerList = new ArrayList<>();

        List<String> paperTypeList = examStudentScoreList.stream().map(ExamStudentScore::getPaperType).distinct().collect(Collectors.toList());
        final String specialPaperType = "#";
        paperTypeList.remove(specialPaperType);
        int count = paperTypeList.size();
        int i = 0;

        Map<String, TBStudent> checkMap = new HashMap<>();
        for (ExamStudentScore examStudentScore : examStudentScoreList) {
            String studentCode = examStudentScore.getStudentCode(); //学号
            String name = examStudentScore.getName(); //名称
            String paperType = examStudentScore.getPaperType(); //试卷类型
            // 循环依次为#生成（分配）试卷编号为A、B、C......A、B、C......
            if (count > 0 && paperType.equals(specialPaperType)) {
                paperType = paperTypeList.get(i);
                i++;
                if (i == count) {
                    i = 0;
                }
            }

            String college = examStudentScore.getCollege(); //学院
            String className = examStudentScore.getClassName(); //班级名称
            String teacherCode = examStudentScore.getTeacherCode(); //教师
            String teacherName = examStudentScore.getTeacherName();
            // 缺考状态 2 -> 缺考 ； 3 -> 违纪
            int status = examStudentScore.getStatus(); //学生考试状态
            BigDecimal totalScore = examStudentScore.getTotalScore(); //考生总分
            BigDecimal objectiveScore = examStudentScore.getObjectiveScore(); //客观题总分
            BigDecimal subjectiveScore = examStudentScore.getSubjectiveScore(); //主观题总分
            List<AnswerInfo> objectiveScoreDetailList = examStudentScore.getObjectiveScoreDetail(); //客观题明细
            List<AnswerInfo> subjectiveScoreDetailList = examStudentScore.getSubjectiveScoreDetail(); //主观题答题明细

            /*
                组建学生基础信息 student
             */
            if (checkMap.containsKey(studentCode)) {
                if (!checkMap.get(studentCode).getName().equals(name)) {
                    throw ExceptionResultEnum.ERROR.exception("有学号【" + studentCode + "】的学生名称不统一");
                }
            } else {
                TBStudent studentTemp = tbStudentService.getOne(new QueryWrapper<TBStudent>().lambda()
                        .eq(TBStudent::getSchoolId, schoolId)
                        .eq(TBStudent::getStudentCode, studentCode));
                Long studentId;
                if (Objects.nonNull(studentTemp)) {
                    studentId = studentTemp.getId();
                } else {
                    studentId = SystemConstant.getDbUuid();
                }
                TBStudent tbStudent = new TBStudent();
                tbStudent.setId(studentId);
                tbStudent.setSchoolId(schoolId);
                tbStudent.setName(name);
                tbStudent.setStudentCode(studentCode);
                checkMap.put(studentCode, tbStudent);
                tbStudentList.add(tbStudent);
            }


            /*
                组建考生考试信息 exm_pap_tik
             */
            // 开课学院id
            TBExamCourse tbExamCourse = tbExamCourseService.getOne(new QueryWrapper<TBExamCourse>().lambda()
                    .eq(TBExamCourse::getExamId, examId)
                    .eq(TBExamCourse::getCourseCode, courseCode)
                    .eq(TBExamCourse::getSchoolId, schoolId));
            if (Objects.isNull(tbExamCourse)) {
                throw ExceptionResultEnum.ERROR.exception("缺少课程数据");
            }
            Long teachCollegeId = tbExamCourse.getTeachCollegeId();
            if (!SystemConstant.longNotNull(teachCollegeId)) {
                throw ExceptionResultEnum.ERROR.exception("课程数据缺少开课学院异常");
            }

            // 获取关联的基础表主键
            SysOrg tbSchoolCollege = sysOrgService.findByForeignKey(schoolId, college, college);
            TBSchoolClazz tbSchoolClazz = tbSchoolClazzService.findByForeignKey(schoolId, className, className);
            SysUser tbSchoolTeacher = sysUserService.findByForeignKey(schoolId, teacherCode);

            TBExamStudent tbExamStudent = new TBExamStudent();
            Long examStudentId = SystemConstant.getDbUuid();
            tbExamStudent.setId(examStudentId);
            tbExamStudent.setSchoolId(tbExamService.getById(examId).getSchoolId());
            tbExamStudent.setExamId(examId);
            tbExamStudent.setName(name);
            tbExamStudent.setStudentId(checkMap.get(studentCode).getId());
            tbExamStudent.setStudentCode(studentCode);
            tbExamStudent.setCourseCode(courseCode);
            tbExamStudent.setCourseName(courseName);
            tbExamStudent.setTeachCollegeId(teachCollegeId);
            tbExamStudent.setInspectCollegeId(tbSchoolCollege.getId());
            tbExamStudent.setClazzId(tbSchoolClazz.getId());
            tbExamStudent.setMajorId(0L);
            if (Objects.nonNull(tbSchoolTeacher)) {
                tbExamStudent.setTeacherId(tbSchoolTeacher.getId());
            } else {
                tbExamStudent.setTeacherId(0L);
            }
            tbExamStudent.setTicketNumber(studentCode);
            tbExamStudent.setAbsent(status == 2 || status == 3);
            // 全部设置为本届
            tbExamStudent.setStudentCurrent(true);
            tbExamStudentList.add(tbExamStudent);

            // 构建考生作答记录表(t_b_exam_record)
            Long examRecordId = SystemConstant.getDbUuid();
            TBExamRecord tbExamRecord = new TBExamRecord();
            tbExamRecord.setId(examRecordId);
            tbExamRecord.setExamId(examId);
            tbExamRecord.setPaperId(tbPaperService.findByForeignKey(examId, courseCode, courseName, paperType).getId());
            tbExamRecord.setPaperType(paperType);
            tbExamRecord.setExamStudentId(examStudentId);
            tbExamRecord.setSubjectiveScore(subjectiveScore);
            tbExamRecord.setObjectiveScore(objectiveScore);
            tbExamRecord.setTotalScore(totalScore);
            tbExamRecordList.add(tbExamRecord);

            // 构建考生作答明细表（t_b_answer）正常考生才记录
            // 客观题（选择）
            if (status == 1) {
                for (AnswerInfo objective : objectiveScoreDetailList) {
                    Long answerId = SystemConstant.getDbUuid();
                    TBAnswer tbAnswer = new TBAnswer();
                    tbAnswer.setId(answerId);
                    tbAnswer.setExamRecordId(examRecordId);
                    tbAnswer.setNumberType(NumberTypeEnum.OBJECTIVE.getValue());
                    String cloudMainNumber = String.valueOf(objective.getMainNumber());
                    String cloudSubNumber = objective.getSubNumber();
                    tbAnswer.setMainNumber(cloudMainNumber);
                    tbAnswer.setSubNumber(cloudSubNumber);
                    tbAnswer.setScore(objective.getScore());
                    tbAnswer.setAnswer(objective.getAnswer());
                    tbAnswerList.add(tbAnswer);
                }
                // 主观题
                for (AnswerInfo subjective : subjectiveScoreDetailList) {
                    Long answerId = SystemConstant.getDbUuid();
                    TBAnswer tbAnswer = new TBAnswer();
                    tbAnswer.setId(answerId);
                    tbAnswer.setExamRecordId(examRecordId);
                    tbAnswer.setNumberType(NumberTypeEnum.SUBJECTIVE.getValue());
                    String cloudMainNumber = String.valueOf(subjective.getMainNumber());
                    String cloudSubNumber = subjective.getSubNumber();
                    tbAnswer.setMainNumber(cloudMainNumber);
                    tbAnswer.setSubNumber(cloudSubNumber);
                    tbAnswer.setScore(subjective.getScore());
                    tbAnswer.setAnswer(subjective.getAnswer());
                    tbAnswerList.add(tbAnswer);
                }
            }
        }

        // 处理并向数据库插入学生信息
        tbStudentService.saveOrUpdateBatch(tbStudentList);

        // 删除原t_b_answer、t_b_exam_record、t_b_exam_student表数据
        List<String> courseInfoList = tbExamStudentList.stream().map(TBExamStudent::getCourseCode).collect(Collectors.toList());
        Set<Long> examStudentRemoveIdSet = new HashSet<>();
        for (String s : courseInfoList) {
            Set<Long> ids = tbExamStudentService.list(new QueryWrapper<TBExamStudent>().lambda()
                            .eq(TBExamStudent::getCourseCode, s))
                    .stream().map(TBExamStudent::getId).collect(Collectors.toSet());
            examStudentRemoveIdSet.addAll(ids);
        }

        if (examStudentRemoveIdSet.size() > 0) {
            // 删除考生表
            tbExamStudentService.removeByIds(examStudentRemoveIdSet);
            List<TBExamRecord> willRemoveRecord = tbExamRecordService.list(new QueryWrapper<TBExamRecord>()
                    .lambda().in(TBExamRecord::getExamStudentId, examStudentRemoveIdSet));
            if (willRemoveRecord.size() > 0) {
                List<Long> willRemoveRecordIdList = willRemoveRecord.stream().map(TBExamRecord::getId).collect(Collectors.toList());
                // 删除考生作答
                tbExamRecordService.removeByIds(willRemoveRecordIdList);
                // 删除考生作答
                tbAnswerService.remove(new QueryWrapper<TBAnswer>().lambda().in(TBAnswer::getExamRecordId, willRemoveRecordIdList));
            }
        }

        // 保存数据
        tbExamStudentService.saveBatch(tbExamStudentList);
        tbExamRecordService.saveBatch(tbExamRecordList);
        tbAnswerService.saveBatch(tbAnswerList);
    }

    /**
     * 检验基础试卷有变动需要重新计算
     *
     * @param old     旧的试卷
     * @param current 现在的试卷
     * @return 1：重算 - 0 ：不用
     */
    private boolean checkTBPaperRepeat(TBPaper old, PaperConfig current) {
        String oldStr = old.getPaperType() + old.getScoreType() + old.getCoefficient() + old.getTotalScore() + old.getPassScore();
        String currentStr = current.getPaperType() + current.getScoreType() + current.getCoefficient() + current.getTotalScore() + current.getPassScore();
        return !currentStr.equals(oldStr);
    }

    /**
     * 检验维度点变动的重新计算
     *
     * @param old     旧维度
     * @param current 新维度
     * @return 1：重算 - 0 ：不用
     */
    private boolean checkTBDimensionRepeat(List<TBDimension> old, List<PaperDimension> current) {
        if (old.isEmpty() || current.size() != old.size()) {
            return false;
        } else {
            old = old.stream().sorted(Comparator.comparing(TBDimension::getDimensionType)
                            .thenComparing(TBDimension::getCodePrimary)
                            .thenComparing(TBDimension::getCodeSecond))
                    .collect(Collectors.toList());
            current = current.stream().sorted(Comparator.comparing(PaperDimension::getDimensionType)
                            .thenComparing(PaperDimension::getCodePrimary)
                            .thenComparing(PaperDimension::getCodeSecond))
                    .collect(Collectors.toList());

            List<String> oldStrList = old.stream().flatMap(e -> {
                String x = e.getDimensionType() + e.getNamePrimary() + e.getCodePrimary() + e.getNameSecond() + e.getCodeSecond() + e.getInterpretation();
                return Stream.of(x);
            }).collect(Collectors.toList());
            List<String> currentStrList = current.stream().flatMap(e -> {
                String x = e.getDimensionType() + e.getNamePrimary() + e.getCodePrimary() + e.getNameSecond() + e.getCodeSecond() + e.getInterpretation();
                return Stream.of(x);
            }).collect(Collectors.toList());
            return !oldStrList.toString().equals(currentStrList.toString());
        }
    }

    /**
     * 构建试卷信息md5
     *
     * @param paperConfig 试卷配置
     * @return md5
     */
    private String buildPaperDataMd5(PaperConfig paperConfig) {
        return DigestUtils.md5Hex(JSON.toJSONString(paperConfig));
    }

    /**
     * 构建维度信息md5
     *
     * @param paperDimensionList 维度信息
     * @return MD5
     */
    private String buildDimensionDataMd5(List<PaperDimension> paperDimensionList) {
        paperDimensionList = paperDimensionList.stream().sorted(Comparator.comparing(PaperDimension::getDimensionType)
                        .thenComparing(PaperDimension::getCodePrimary)
                        .thenComparing(PaperDimension::getCodeSecond))
                .collect(Collectors.toList());
        return DigestUtils.md5Hex(JSON.toJSONString(paperDimensionList));
    }

    /**
     * 构建结构信息md5
     *
     * @param paperStructureList 试卷结构信息
     * @return MD5
     */
    private String buildStructDataMd5(List<PaperStructure> paperStructureList) {
        paperStructureList = paperStructureList.stream().sorted(Comparator.comparing(PaperStructure::getNumberType)
                .thenComparing(PaperStructure::getBigQuestionNumber)
                .thenComparing(PaperStructure::getSmallQuestionNumber)).collect(Collectors.toList());
        return DigestUtils.md5Hex(JSON.toJSONString(paperStructureList));
    }

    /**
     * 构建模块信息MD5
     *
     * @param paperEvaluationList 试卷模块信息
     * @return MD5
     */
    private String buildModuleDataMd5(List<PaperEvaluation> paperEvaluationList) {
        paperEvaluationList = paperEvaluationList.stream().sorted(Comparator.comparing(PaperEvaluation::getModuleType))
                .collect(Collectors.toList());
        return DigestUtils.md5Hex(JSON.toJSONString(paperEvaluationList));
    }

    /**
     * 构建学生成绩数据md5
     *
     * @param examStudentScoreList 学生成绩数据
     * @return md5
     */
    private String buildExamStudentDataMd5(List<ExamStudentScore> examStudentScoreList) {
        examStudentScoreList = examStudentScoreList.stream().sorted(Comparator.comparing(ExamStudentScore::getStudentCode)).collect(Collectors.toList());
        return DigestUtils.md5Hex(JSON.toJSONString(examStudentScoreList));
    }
}
