package com.ssj.service.kmt.exercise;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ssj.bean.conch.conch.dto.KmtExerciseQuestionProblemDto;
import com.ssj.bean.kmt.kmt.domain.KmtExerciseBook;
import com.ssj.bean.kmt.kmt.domain.KmtExerciseBookCourse;
import com.ssj.bean.kmt.kmt.domain.KmtExerciseQuestion;
import com.ssj.bean.kmt.kmt.domain.KmtExerciseQuestionRollback;
import com.ssj.bean.kmt.kmt.request.exercise.KmtHandlingQuestionRequest;
import com.ssj.bean.sys.homework.domain.HomeworkCount;
import com.ssj.bean.sys.homework.domain.StudentWeeklyReport;
import com.ssj.bean.weixin.libmy.domain.TbLibManager;
import com.ssj.es.entiy.EsResModel;
import com.ssj.es.service.ExerciseQuestionSearchService;
import com.ssj.es.service.base.BaseSearchService;
import com.ssj.framework.core.util.PropertiesUtil;
import com.ssj.framework.core.util.ResponseEntity;
import com.ssj.framework.core.util.StringUtil;
import com.ssj.framework.weixin.util.DateUtil;
import com.ssj.kmt.utils.JSONFileUtil;
import com.ssj.mapper.knowledge.KmtKnowledgeMapper;
import com.ssj.service.conch.parents.v2.dto.*;
import com.ssj.service.kmt.constant.KnowledgeVersion;
import com.ssj.service.kmt.dto.*;
import com.ssj.service.kmt.dto.exercise.*;
import com.ssj.service.kmt.request.ExerciseBookIdDealTypeRequest;
import com.ssj.service.kmt.request.ExerciseConditionRequest;
import com.ssj.service.kmt.request.ExerciseQuestionsRequest;
import com.ssj.service.kmt.request.UnitAndPeriodListRequest;
import com.ssj.service.kmt.service.*;
import com.ssj.service.mapper.KmtExerciseMapper;
import com.ssj.service.weixin.library.service.IBookManagerService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@Service(version = "1.0")
public class KmtExerciseMapperServiceImpl implements KmtExerciseMapperService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private KmtExerciseMapper kmtExerciseMapper;
    @Autowired
    private KmtKnowledgeMapper kmtKnowledgeMapper;
    @Autowired
    private KnowledgeVersion knowledgeVersion;
    @Autowired
    private KmtExerciseQuestionService kmtExerciseQuestionService;
    @Autowired
    private BaseSearchService baseSearchService;
    @Autowired
    private KmtExerciseBookCourseService kmtExerciseBookCourseService;
    @Autowired
    private ExerciseQuestionSearchService exerciseQuestionSearchService;
    @Autowired
    private IBookManagerService bookManagerService;
    @Autowired
    private KmtExerciseBookService kmtExerciseBookService;
    @Autowired
    private KmtExerciseService kmtExerciseService;

    @Override
    public List<String> findWrongQuestionKnowHowDetailIdList(String questionId) {
        return kmtExerciseMapper.findWrongQuestionKnowHowDetailIdList(questionId).stream().distinct().collect(Collectors.toList());
    }

    @Override
    public List<OriginalQuestionDTO> findRecommendQuestionList(List<String> wrongQuestionKnowHowDetailIdList, Set<String> needExcludedQuestionIdSet, int needNum) {
        List<OriginalQuestionDTO> recommendQuestionList = new LinkedList<>();
        List<JSONObject> bucketList = new LinkedList<>();

        Set<String> newNeedExcludedQuestionIdSet = new HashSet<>(needExcludedQuestionIdSet);
        //对小题进行匹配
        Map<String, Object> selectParamMap = this.getSelectParam(wrongQuestionKnowHowDetailIdList, newNeedExcludedQuestionIdSet, 2, needNum);
        if (selectParamMap != null) {
            Map<String, Object> queryMap = (Map<String, Object>) selectParamMap.get("queryMap");
            Map<String, Object> pageMap = (Map<String, Object>) selectParamMap.get("pageMap");
            Map<String, Object> aggregationMap = (Map<String, Object>) selectParamMap.get("aggregationMap");
            EsResModel esResModel = baseSearchService.findPage("kmt_exercise_question_know", queryMap, null, null, pageMap, aggregationMap);
            JSONObject aggregations = esResModel.getAggregations();
            if (aggregations != null) {
                JSONArray buckets = aggregations.getJSONObject("group_by_question_id").getJSONArray("buckets");
                bucketList.addAll(buckets.toJavaList(JSONObject.class));
                bucketList.forEach(bucket -> {
                    JSONObject hitObj = (JSONObject) bucket.getJSONObject("result_top_hits").getJSONObject("hits").getJSONArray("hits").get(0);
                    newNeedExcludedQuestionIdSet.add(hitObj.getJSONObject("_source").getString("parent_id"));
                });
            }
        }

        //对大题进行匹配
        selectParamMap = this.getSelectParam(wrongQuestionKnowHowDetailIdList, newNeedExcludedQuestionIdSet, 1, needNum);
        if (selectParamMap != null) {
            Map<String, Object> queryMap = (Map<String, Object>) selectParamMap.get("queryMap");
            Map<String, Object> pageMap = (Map<String, Object>) selectParamMap.get("pageMap");
            Map<String, Object> aggregationMap = (Map<String, Object>) selectParamMap.get("aggregationMap");
            EsResModel esResModel = baseSearchService.findPage("kmt_exercise_question_know", queryMap, null, null, pageMap, aggregationMap);
            JSONObject aggregations = esResModel.getAggregations();
            if (aggregations != null) {
                JSONArray buckets = aggregations.getJSONObject("group_by_question_id").getJSONArray("buckets");
                bucketList.addAll(buckets.toJavaList(JSONObject.class));
            }
        }

        //根据匹配数量倒排（一道题中相同知识点数量）
        OriginalQuestionDTO recommendQuestion;
        Set<String> parentQuestionIdSet = new HashSet<>();
        bucketList = bucketList.stream()
                .sorted(Comparator.comparingInt(it -> it.getIntValue("doc_count")))
                .collect(Collectors.toList());
        Collections.reverse(bucketList);
        int count = 0;
        String questionJsonStr;
        for (Object bucket : bucketList) {
            if (count >= needNum) {
                break;
            }

            JSONObject tempObj = (JSONObject) bucket;
            JSONArray hitsJsonArray = tempObj.getJSONObject("result_top_hits").getJSONObject("hits").getJSONArray("hits");
            for (Object tempHitObj : hitsJsonArray) {
                JSONObject hitObj = (JSONObject) tempHitObj;
                JSONObject questionObj = hitObj.getJSONObject("_source");
                String parentId = questionObj.getString("parent_id");
                if (StringUtils.isBlank(parentId)) {
                    //不区分大小题
                    recommendQuestion = new OriginalQuestionDTO();
                    recommendQuestion.setId(questionObj.getString("question_id"));
                    recommendQuestion.setType(2);
                    recommendQuestion.setQuestion(questionObj.getString("question"));
                    questionJsonStr = questionObj.getString("question_json");
                    if (StringUtils.isNotBlank(questionJsonStr) &&
                            !"[]".equals(questionJsonStr)) {
                        recommendQuestion.setQuestionJson(JSON.parseArray(questionJsonStr, ExerciseQuestionAnswerValue.class));
                    }
                    recommendQuestion.setBookId(questionObj.getString("book_id"));
                    recommendQuestion.setNum(questionObj.getInteger("num"));
                    recommendQuestionList.add(recommendQuestion);
                } else {
                    //区分大小题，通过大题查询整道题目
                    if (parentQuestionIdSet.contains(parentId)) {
                        continue;
                    }
                    parentQuestionIdSet.add(parentId);
                    List<OriginalQuestionDTO> tempFullBigQuestionList = this.findFullBigQuestionByParentIds(Collections.singletonList(parentId), 2);
                    if (!tempFullBigQuestionList.isEmpty()) {
                        tempFullBigQuestionList = tempFullBigQuestionList.stream()
                                .sorted((question1, question2) -> {
                                    String bookId1 = Optional.ofNullable(question1.getBookId()).orElse("");
                                    String bookId2 = Optional.ofNullable(question2.getBookId()).orElse("");
                                    Integer num1 = Optional.ofNullable(question1.getNum()).orElse(0);
                                    Integer num2 = Optional.ofNullable(question2.getNum()).orElse(0);
                                    return Objects.equals(bookId1, bookId2) ? num1 - num2 : bookId1.compareTo(bookId2);
                                })
                                .collect(Collectors.toList());
                        tempFullBigQuestionList.get(0).setType(2);
                        recommendQuestionList.addAll(tempFullBigQuestionList);
                    }
                }
            }

            count ++;
        }

        return recommendQuestionList.stream().sorted(Comparator.comparingInt(OriginalQuestionDTO::getNum)).collect(Collectors.toList());
    }

    /**
     * 查询大小题
     *
     * @param parentIds 大题id
     * @param type 错题本打印原题时作为什么类型题目（1：原题，2：推荐题）
     *
     * @return 题目
     */
    public List<OriginalQuestionDTO> findFullBigQuestionByParentIds(List<String> parentIds, int type) {
        List<OriginalQuestionDTO> tempFullBigQuestionList = new ArrayList<>();
        List<Map> tempFullBigQuestionListTemp = exerciseQuestionSearchService.findFullBigQuestionByParentId(parentIds);
        if (tempFullBigQuestionListTemp != null){
            String parentId;
            String questionJsonStr;
            for (Map item : tempFullBigQuestionListTemp){
                OriginalQuestionDTO temp = new OriginalQuestionDTO();
                temp.setBookId(item.getOrDefault("bookId", "").toString());
                temp.setId(item.get("id").toString());
                temp.setNum(Integer.parseInt(item.getOrDefault("num", "0").toString()));
                temp.setQuestion(item.getOrDefault("question", "").toString());
                questionJsonStr = item.getOrDefault("questionJson", "").toString();
                if (StringUtils.isNotBlank(questionJsonStr) &&
                        !"[]".equals(questionJsonStr)) {
                    temp.setQuestionJson(JSON.parseArray(questionJsonStr, ExerciseQuestionAnswerValue.class));
                }
                parentId = item.getOrDefault("parentId", "").toString();
                temp.setParentId(parentId);
                if (StringUtils.isBlank(parentId)) {
                    temp.setType(type);
                } else {
                    temp.setType(1);
                }
                tempFullBigQuestionList.add(temp);
            }
        }
        return tempFullBigQuestionList;
    }


    @Override
    public List<KmtExerciseQuestion> findKmtExerciseQuestionsByIdIn(List<String> ids) {
        return kmtExerciseMapper.findKmtExerciseQuestionsByIdIn(ids);
    }

    @Override
    public void deleteKmtExerciseQuestionKnowByQuestionIds(List<String> questionIds) {
        kmtExerciseMapper.deleteKmtExerciseQuestionKnowByQuestionIds(questionIds);
    }

    @Override
    public void updateKmtExerciseQuestion2Review(List<String> questionIds) {
        kmtExerciseMapper.updateKmtExerciseQuestion2Review(questionIds);
    }

    @Override
    public List<ExerciseQuetionDto> findQuestionByBookCourseIdAndUserId(ExerciseQuestionsRequest request, Page page,  String userId) {
        return kmtExerciseMapper.findQuestionByBookCourseIdAndUserId(request.getPeriodId(), request.getDealType(), userId, request.getRollbackType(), request.getExerciseBookId(), page);
    }

    @Override
    public List<KmtExerciseQuestionRollback> findKmtExerciseQuestionRollbacks(List<String> questionIds, int dealType) {
        return kmtExerciseMapper.findKmtExerciseQuestionRollbacks(questionIds, dealType);
    }

    @Override
    public List<KmtExerciseQuestionRollBackInfo> findQuestionRollbackRecord(String questionId) {
        return kmtExerciseMapper.findQuestionRollbackRecord(questionId);
    }

    @Override
    public List<ExerciseQuestionRollbacks> findQuestionRollbackRecordOld(String questionId) {
        return kmtExerciseMapper.findQuestionRollbackRecordOld(questionId);
    }


    @Override
    public int computeLearningScore(String vipId, String subject, Date beginDateTime, Date endDateTime) {
        StudentWeeklyReport studentWeeklyReport = null; //homeworkMapper.findWeeklyReportByVipIdAndSubjectAndBeginDate(vipId, subject, DateUtil.format_yyyyMMdd(beginDateTime));
        if (studentWeeklyReport == null) {
            return 0;
        }

        return studentWeeklyReport.getAccuracyRate();
    }

    @Override
    public List<KnowledgePointProportionDTO> getKnowledgePointProportionList(String vipId, String subject, Date beginDateTime, Date endDateTime) {
        String beginDateTimeStr = DateUtil.format_yyyyMMdd(beginDateTime) + " 00:00:00";
        String endDateTimeStr = DateUtil.format_yyyyMMdd(endDateTime) + " 23:59:59";
        List<Map<String, Object>> knowledgeTimesMapList = new ArrayList<>();

        // 查询平台批改老师批改匹配知识点
        List<Map<String, Object>> tempKnowledgeTimesMapList = kmtExerciseMapper.countPlatformCorrectionKnowledgeTimes(vipId, subject, beginDateTimeStr, endDateTimeStr);
        if (CollectionUtils.isNotEmpty(tempKnowledgeTimesMapList)) {
            knowledgeTimesMapList.addAll(tempKnowledgeTimesMapList);
        }

        // 查询校区批改老师批改
        tempKnowledgeTimesMapList = this.countCampusCorrectionKnowledgeTimes(vipId, subject, beginDateTimeStr, endDateTimeStr);
        if (CollectionUtils.isNotEmpty(tempKnowledgeTimesMapList)) {
            knowledgeTimesMapList.addAll(tempKnowledgeTimesMapList);
        }

        List<KnowledgePointProportionDTO> knowledgePointProportionDTOList = new ArrayList<>();
        if (CollectionUtils.isEmpty(knowledgeTimesMapList)) {
            return knowledgePointProportionDTOList;
        }

        //统计所有知识点涉及总次数(每个知识点涉及次数之和)
        int allTotalCount = 0;
        for (Map<String, Object> knowledgeTimesMap : knowledgeTimesMapList) {
            allTotalCount += Integer.parseInt(knowledgeTimesMap.get("count_num").toString());
        }

        //计算每个知识点占比(自身涉及次数/所有知识点涉及总次数)
        for (Map<String, Object> knowledgeTimesMap : knowledgeTimesMapList) {
            Optional<KnowledgePointProportionDTO> optional = knowledgePointProportionDTOList.stream()
                    .filter(it -> Objects.equals(it.getKnowledgeName(), knowledgeTimesMap.get("alias")))
                    .findFirst();
            if (optional.isPresent()) {
                //已存在，说明两中批改方式均有此知识点的批改记录，累加涉及次数
                KnowledgePointProportionDTO knowledgePointProportionDTO = optional.get();
                int countNum = Integer.parseInt(knowledgeTimesMap.get("count_num").toString());
                knowledgePointProportionDTO.setCountNum(countNum + knowledgePointProportionDTO.getCountNum());
            } else {
                //记录此知识点涉及次数
                KnowledgePointProportionDTO knowledgePointProportionDTO = new KnowledgePointProportionDTO();
                knowledgePointProportionDTO.setKnowledgeName(Optional.ofNullable(knowledgeTimesMap.get("alias")).orElse("").toString());
                int countNum = Integer.parseInt(knowledgeTimesMap.get("count_num").toString());
                knowledgePointProportionDTO.setCountNum(countNum);
                knowledgePointProportionDTO.setAllTotalCount(allTotalCount);
                knowledgePointProportionDTOList.add(knowledgePointProportionDTO);
            }
        }

        //计算所有知识点占比之和，如果小于或大于1（四舍五入导致），则在第一条知识点记录中进行修正，使得占比之和为1
        BigDecimal totalProportion = BigDecimal.ZERO;
        for (KnowledgePointProportionDTO knowledgePointProportionDTO : knowledgePointProportionDTOList) {
            totalProportion = totalProportion.add(knowledgePointProportionDTO.getProportion());
        }

        knowledgePointProportionDTOList.removeIf(it -> BigDecimal.ZERO.compareTo(it.getProportion()) == 0);

        int index = 0;
        while (totalProportion.compareTo(BigDecimal.ONE) < 0) {
            if (CollectionUtils.isEmpty(knowledgePointProportionDTOList)) {
                break;
            }

            if (index >= knowledgePointProportionDTOList.size()) {
                index = 0;
            }
            KnowledgePointProportionDTO knowledgePointProportionDTO = knowledgePointProportionDTOList.get(index);
            BigDecimal increment = new BigDecimal("0.01");
            knowledgePointProportionDTO.setProportion(knowledgePointProportionDTO.getProportion().add(increment));
            totalProportion = totalProportion.add(increment);

            index ++;
        }

        return knowledgePointProportionDTOList;
    }

    /**
     * 统计校区批改知识点涉及次数
     *
     * @param vipId 学生id
     * @param subject 科目
     * @param beginDateTimeStr 开始时间
     * @param endDateTimeStr 结束时间
     */
    private List<Map<String, Object>> countCampusCorrectionKnowledgeTimes(String vipId, String subject,
                                                                          String beginDateTimeStr,
                                                                          String endDateTimeStr) {
        // 查询错题
        List<Map<String, Object>> wrongQuestionMapList = kmtExerciseMapper.findWrongQuestion(vipId, subject, beginDateTimeStr, endDateTimeStr);
        if (CollectionUtils.isEmpty(wrongQuestionMapList)) {
            return Collections.emptyList();
        }

        // 错题根据作业分组，分别统计知识点出现次数
        Map<String, List<String>> wrongQuestionIdGroupByHomeworkId = wrongQuestionMapList.stream().collect(Collectors.groupingBy(it -> Optional.ofNullable(it.get("homework_id")).map(Object::toString).orElse(""),
                Collectors.mapping(it -> Optional.ofNullable(it.get("question_id")).map(Object::toString).orElse(""), Collectors.toList())));
        List<Map<String, Object>> tempKnowledgeTimesMapList;
        List<Map<String, Object>> knowledgeTimesMapList = new ArrayList<>();
        int existCountNum;
        int tempCountNum;
        for (Map.Entry<String, List<String>> entry : wrongQuestionIdGroupByHomeworkId.entrySet()) {
            if (StringUtils.isBlank(entry.getKey()) || CollectionUtils.isEmpty(entry.getValue())) {
                continue;
            }

            tempKnowledgeTimesMapList = kmtExerciseMapper.countCampusCorrectionKnowledgeTimesByQuestionIds(entry.getValue());
            if (CollectionUtils.isNotEmpty(tempKnowledgeTimesMapList)) {
                for (Map<String, Object> tempKnowledgeTimesMap : tempKnowledgeTimesMapList) {
                    Optional<Map<String, Object>> existTempKnowledgeTimesMapOptional = knowledgeTimesMapList.stream()
                            .filter(it -> Objects.equals(it.get("alias"), tempKnowledgeTimesMap.get("alias"))).findFirst();
                    if (existTempKnowledgeTimesMapOptional.isPresent()) {
                        Map<String, Object> existTempKnowledgeTimesMap = existTempKnowledgeTimesMapOptional.get();
                        existCountNum = Integer.parseInt(existTempKnowledgeTimesMap.get("count_num").toString());
                        tempCountNum = Integer.parseInt(tempKnowledgeTimesMap.get("count_num").toString());
                        existTempKnowledgeTimesMap.put("count_num", existCountNum + tempCountNum);
                    } else {
                        knowledgeTimesMapList.add(tempKnowledgeTimesMap);
                    }
                }
            }
        }

        return knowledgeTimesMapList;
    }

    @Override
    public List<KnowledgePointMasteryDTO> getKnowledgePointMasteryList(String vipId, String subject, Date beginDateTime, Date endDateTime) {
        String beginDateTimeStr = DateUtil.format_yyyyMMdd(beginDateTime) + " 00:00:00";
        String endDateTimeStr = DateUtil.format_yyyyMMdd(endDateTime) + " 23:59:59";
        List<Map<String, Object>> knowledgeMasteryMapList = kmtExerciseMapper.countKnowledgeMastery(vipId, subject, beginDateTimeStr, endDateTimeStr);

        return getKnowledgePointMasteryDTOListV2(knowledgeMasteryMapList, null);
    }

    @Override
    public List<ModuleDTO> getModuleList(String vipId, String subject, Date beginDateTime, Date endDateTime) {
        String beginDateTimeStr = DateUtil.format_yyyyMMdd(beginDateTime) + " 00:00:00";
        String endDateTimeStr = DateUtil.format_yyyyMMdd(endDateTime) + " 23:59:59";
        List<Map<String, Object>> knowledgeMasteryMapList = kmtExerciseMapper.countKnowledgeMastery(vipId, subject, beginDateTimeStr, endDateTimeStr);

        List<ModuleDTO> moduleDTOList = new LinkedList<>();
        knowledgeMasteryMapList.stream().collect(Collectors.groupingBy(it -> it.get("module")))
                .forEach((module, knowledgeMasteryMapListGrouped) -> {
                    ModuleDTO moduleDTO = new ModuleDTO();
                    moduleDTO.setModule(String.valueOf(module));
                    List<KnowledgePointMasteryDTO> knowledgePointMasteryDTOList = this.getKnowledgePointMasteryDTOList(knowledgeMasteryMapListGrouped);
                    moduleDTO.setKnowledgePointMasteryList(knowledgePointMasteryDTOList);

                    moduleDTOList.add(moduleDTO);
                });

        return moduleDTOList;
    }

    /**
     * 计算每个知识点掌握情况（指定时间区间内，作业涉及知识点的题目正确率）
     * @param knowledgeMasteryMapList 来自kmtExerciseMapper.countKnowledgeMastery()
     */
    private List<KnowledgePointMasteryDTO> getKnowledgePointMasteryDTOList(List<Map<String, Object>> knowledgeMasteryMapList) {
        List<KnowledgePointMasteryDTO> knowledgePointMasteryDTOList = new LinkedList<>();
        knowledgeMasteryMapList.forEach(knowledgeMasteryMap -> {
            Optional<KnowledgePointMasteryDTO> optional = knowledgePointMasteryDTOList.stream()
                    .filter(it -> Objects.equals(it.getKnowledgeName(), knowledgeMasteryMap.get("alias")))
                    .findFirst();
            if (optional.isPresent()) {
                //已存在，说明两中批改方式均有此知识点的批改记录，累加涉及错题数和题目总数
                KnowledgePointMasteryDTO knowledgePointMasteryDTO = optional.get();
                knowledgePointMasteryDTO.setWrongCount(knowledgePointMasteryDTO.getWrongCount() + Integer.parseInt(knowledgeMasteryMap.get("wrong_count").toString()));
                knowledgePointMasteryDTO.setTotalCount(knowledgePointMasteryDTO.getTotalCount() + Integer.parseInt(knowledgeMasteryMap.get("total_count").toString()));
            } else {
                //记录此知识点涉及错题数和题目总数
                KnowledgePointMasteryDTO knowledgePointMasteryDTO = new KnowledgePointMasteryDTO();
                knowledgePointMasteryDTO.setKnowledgeName(Optional.ofNullable(knowledgeMasteryMap.get("alias")).orElse("").toString());
                knowledgePointMasteryDTO.setWrongCount(Integer.parseInt(knowledgeMasteryMap.get("wrong_count").toString()));
                knowledgePointMasteryDTO.setTotalCount(Integer.parseInt(knowledgeMasteryMap.get("total_count").toString()));

                //知识点详情，同名知识点的所有知识点id及版本
                String[] knowHowDetailIds = String.valueOf(knowledgeMasteryMap.get("know_how_detail_id_str")).split(",");
                String[] knowledgeVersions = String.valueOf(knowledgeMasteryMap.get("knowledge_version_str")).split(",");
                List<KnowHowDetailDTO> knowHowDetailDTOList = new ArrayList<>();
                for (int i = 0; i < knowHowDetailIds.length; i++) {
                    String knowHowDetailId = knowHowDetailIds[i];
                    boolean exist = false;
                    for (KnowHowDetailDTO temp : knowHowDetailDTOList) {
                        if (Objects.equals(temp.getKnowHowDetailId(), knowHowDetailId) && Objects.equals(temp.getKnowledgeVersion(), knowledgeVersions[i])) {
                            exist = true;
                            break;
                        }
                    }
                    if (!exist) {
                        KnowHowDetailDTO knowHowDetailDTO = new KnowHowDetailDTO();
                        knowHowDetailDTO.setKnowHowDetailId(knowHowDetailId);
                        knowHowDetailDTO.setKnowledgeVersion(knowledgeVersions[i]);
                        knowHowDetailDTOList.add(knowHowDetailDTO);
                    }
                }
                knowledgePointMasteryDTO.setKnowHowDetailList(knowHowDetailDTOList);

                knowledgePointMasteryDTOList.add(knowledgePointMasteryDTO);
            }
        });
        return knowledgePointMasteryDTOList;
    }

    @Override
    public HomeworkCount findMonthHomeworkCount(String vipId, String homeworkMonth) {
        return kmtExerciseMapper.findMonthHomeworkCount(vipId, homeworkMonth);
    }

    @Override
    public SubjectKnowledgeInfoDTO getSubjectKnowledgeInfoDTO(String vipId, String subject, Date beginDateTime, Date endDateTime) {
        SubjectKnowledgeInfoDTO subjectKnowledgeInfoDTO = new SubjectKnowledgeInfoDTO();
        subjectKnowledgeInfoDTO.setSubject(subject);

        String beginDateTimeStr = DateUtil.format_yyyyMMdd(beginDateTime) + " 00:00:00";
        String endDateTimeStr = DateUtil.format_yyyyMMdd(endDateTime) + " 23:59:59";
        List<Map<String, Object>> knowledgeMasteryMapList = kmtExerciseMapper.countPlatformCorrectionKnowledgeMastery(vipId, subject, beginDateTimeStr, endDateTimeStr);

        //学习的单元和需要加强的知识点（正确率低于85%）
        List<KnowledgePointMasteryDTO> knowledgePointMasteryDTOList = this.getKnowledgePointMasteryDTOListV2(knowledgeMasteryMapList, subjectKnowledgeInfoDTO);
        knowledgePointMasteryDTOList = knowledgePointMasteryDTOList.stream()
                .filter(it -> it.getMastery() < 0.85)
                .sorted(Comparator.comparingDouble(KnowledgePointMasteryDTO::getMastery))
                .collect(Collectors.toList());
        subjectKnowledgeInfoDTO.setWeakKnowledgePointMasteryList(knowledgePointMasteryDTOList);

        return subjectKnowledgeInfoDTO;
    }

    /**
     * 计算每个知识点掌握情况（指定时间区间内，作业涉及知识点的题目正确率）
     * @param knowledgeMasteryMapList 来自kmtExerciseMapper.countKnowledgeMastery()
     * @param subjectKnowledgeInfoDTO 月报查询掌握知识点是需要传入此参数，查询本月学习的单元
     */
    private List<KnowledgePointMasteryDTO> getKnowledgePointMasteryDTOListV2(List<Map<String, Object>> knowledgeMasteryMapList, SubjectKnowledgeInfoDTO subjectKnowledgeInfoDTO) {
        List<LearnedUnitDTO> learnedUnitList = null;
        if (subjectKnowledgeInfoDTO != null) {
            //月报，需查询学习得单元
            learnedUnitList = new LinkedList<>();
            subjectKnowledgeInfoDTO.setLearnedUnitList(learnedUnitList);
        }

        Map<String, List<Map<String, Object>>> knowledgeMasteryMapListGroupByVersion = knowledgeMasteryMapList.stream()
                .collect(Collectors.groupingBy(it -> Optional.ofNullable(it.get("version")).orElse("").toString()));
        Map<String, List<Map<String, Object>>> knowledgeMasteryMapListGroupByHowDetailId = knowledgeMasteryMapList.stream()
                .collect(Collectors.groupingBy(it -> Optional.ofNullable(it.get("how_detail_id")).orElse("").toString()));
        List<KnowledgePointMasteryDTO> knowledgePointMasteryDTOList = new LinkedList<>();
        for (Map.Entry<String, List<Map<String, Object>>> entry : knowledgeMasteryMapListGroupByVersion.entrySet()) {
            String version = entry.getKey();
            if (StringUtils.isNotBlank(version)) {
                Set<String> howDetailIdSet = entry.getValue().stream()
                        .map(it -> Optional.ofNullable(it.get("how_detail_id")).orElse("").toString())
                        .collect(Collectors.toSet());
                howDetailIdSet.remove("");
                if (CollectionUtils.isNotEmpty(howDetailIdSet)) {
                    List<Map<String, Object>> knowledgeInfoMapList = kmtKnowledgeMapper.findKnowledgeInfoByHowDetailIdAndType(howDetailIdSet, Integer.parseInt(version));
                    if (CollectionUtils.isNotEmpty(knowledgeInfoMapList)) {
                        for (Map<String, Object> knowledgeInfoMap : knowledgeInfoMapList) {
                            if (learnedUnitList != null) {
                                //月报查询学习得单元
                                String howName = String.valueOf(knowledgeInfoMap.get("how_name"));
                                boolean howExisted = learnedUnitList.stream().anyMatch(it -> Objects.equals(it.getUnitName(), howName));
                                if (!howExisted) {
                                    LearnedUnitDTO learnedUnitDTO = new LearnedUnitDTO();
                                    learnedUnitDTO.setUnitName(howName);
                                    learnedUnitList.add(learnedUnitDTO);
                                }
                            }

                            Optional<KnowledgePointMasteryDTO> optional = knowledgePointMasteryDTOList.stream()
                                    .filter(it -> Objects.equals(it.getKnowledgeName(), knowledgeInfoMap.get("knowledge_name")))
                                    .findFirst();
                            String howDetailId = String.valueOf(knowledgeInfoMap.get("how_details_id"));
                            Map<String, Object> tempKnowledgeMasteryMap = knowledgeMasteryMapListGroupByHowDetailId.get(howDetailId).get(0);
                            KnowledgePointMasteryDTO knowledgePointMasteryDTO;
                            if (optional.isPresent()) {
                                //已存在，说明两中批改方式均有此知识点的批改记录，累加涉及错题数和题目总数
                                knowledgePointMasteryDTO = optional.get();
                                knowledgePointMasteryDTO.setWrongCount(knowledgePointMasteryDTO.getWrongCount() + Integer.parseInt(tempKnowledgeMasteryMap.get("wrong_count").toString()));
                                knowledgePointMasteryDTO.setTotalCount(knowledgePointMasteryDTO.getTotalCount() + Integer.parseInt(tempKnowledgeMasteryMap.get("total_count").toString()));
                            } else {
                                //记录此知识点涉及错题数和题目总数
                                knowledgePointMasteryDTO = new KnowledgePointMasteryDTO();
                                knowledgePointMasteryDTO.setKnowledgeName(String.valueOf(knowledgeInfoMap.get("knowledge_name")));
                                knowledgePointMasteryDTO.setWrongCount(Integer.parseInt(tempKnowledgeMasteryMap.get("wrong_count").toString()));
                                knowledgePointMasteryDTO.setTotalCount(Integer.parseInt(tempKnowledgeMasteryMap.get("total_count").toString()));
                                knowledgePointMasteryDTOList.add(knowledgePointMasteryDTO);
                            }

                            //根据知识点别名分组知识点（不同id知识点可能别名相同）
                            List<KnowHowDetailDTO> knowHowDetailDTOList = knowledgePointMasteryDTO.getKnowHowDetailList();
                            KnowHowDetailDTO knowHowDetailDTO = new KnowHowDetailDTO();
                            knowHowDetailDTO.setKnowHowDetailId(howDetailId);
                            knowHowDetailDTO.setKnowledgeVersion(version);
                            knowHowDetailDTOList.add(knowHowDetailDTO);
                        }
                    }
                }
            }
        }

        return knowledgePointMasteryDTOList;
    }

    @Override
    public List<KmtExerciseQuestionProblemDto> findSimilarQuestionByIds(List<String> ids) {
        List<KmtExerciseQuestionProblemDto> questions = kmtExerciseMapper.findSimilarQuestionByIds(ids);
        for (KmtExerciseQuestionProblemDto kmtExerciseQuestion : questions){
            //读取大字段文件
            if (StringUtil.isNotBlank(kmtExerciseQuestion.getQuestionPath())){
                String path = PropertiesUtil.getValue("EXERCISE_JSON_FILE_PATH") + kmtExerciseQuestion.getQuestionPath();
                logger.debug("文件路径:{}", path);
                String content = JSONFileUtil.readJSONFile(path);
                logger.debug("文件内容：{}", content);
                if (StringUtils.isNotBlank(content)){
                    JSONObject jsonObject = JSONObject.parseObject(content);
                    kmtExerciseQuestion.setQuestion(jsonObject.getString("question"));
                    kmtExerciseQuestion.setAnswerJson(jsonObject.getString("answer_json"));
                }
            }
        }
        return questions;
    }

    @Override
    public SubjectKnowledgeInfoDTOV2 getSubjectKnowledgeInfoDTOV2(String vipId, String subject, Date beginDateTime, Date endDateTime) {
        SubjectKnowledgeInfoDTOV2 subjectKnowledgeInfoDTOV2 = new SubjectKnowledgeInfoDTOV2();
        subjectKnowledgeInfoDTOV2.setSubject(subject);
        subjectKnowledgeInfoDTOV2.setModuleList(this.getModuleListV2(vipId, subject, beginDateTime, endDateTime, subjectKnowledgeInfoDTOV2));

        return subjectKnowledgeInfoDTOV2;
    }

    @Override
    public List<ModuleDTO> getModuleListV2(String vipId, String subject, Date beginDateTime, Date endDateTime, SubjectKnowledgeInfoDTOV2 subjectKnowledgeInfoDTOV2) {
        String beginDateStr = DateUtil.format_yyyyMMdd(beginDateTime);
        String beginDateTimeStr = beginDateStr + " 00:00:00";
        String endDateTimeStr = DateUtil.format_yyyyMMdd(endDateTime) + " 23:59:59";
        List<Map<String, Object>> knowledgeMasteryMapList = new ArrayList<>();
        // 查询平台批改老师批改匹配知识点
        List<Map<String, Object>> tempKnowledgeMasteryMapList = kmtExerciseMapper.countPlatformCorrectionKnowledgeMastery(vipId, subject, beginDateTimeStr, endDateTimeStr);
        if (CollectionUtils.isNotEmpty(tempKnowledgeMasteryMapList)) {
            knowledgeMasteryMapList.addAll(tempKnowledgeMasteryMapList);
        }
        // 查询校区批改老师批改知识点
        tempKnowledgeMasteryMapList = this.countCampusCorrectionKnowledgeMastery(vipId, subject, beginDateTimeStr, endDateTimeStr);
        if (CollectionUtils.isNotEmpty(tempKnowledgeMasteryMapList)) {
            knowledgeMasteryMapList.addAll(tempKnowledgeMasteryMapList);
        }

        List<LearnedUnitDTO> learnedUnitList = null;
        if (subjectKnowledgeInfoDTOV2 != null) {
            //月报，需查询学习得单元
            learnedUnitList = new LinkedList<>();
            subjectKnowledgeInfoDTOV2.setLearnedUnitList(learnedUnitList);
        }

        String lastWeekGrade = null; //homeworkMapper.findGradeLastWeek(vipId, beginDateTimeStr, endDateTimeStr);
        LocalDate beginDate = LocalDate.parse(beginDateStr);
        LocalDate beginDateOfFirstSemester = LocalDate.of(beginDate.getYear(), 8, 1);
        LocalDate beginDateOfSecondSemester = LocalDate.of(beginDate.getYear(), 2, 14);
        int lastWeekSemester = 1;
        if (beginDateOfSecondSemester.isBefore(beginDate) && beginDateOfFirstSemester.isAfter(beginDate)) {
            //下学期
            lastWeekSemester = 2;
        }
        //遍历根据版本分组之后的知识点id，查询知识点信息
        List<ModuleDTO> moduleDTOList = new LinkedList<>();
        String howDetailId;
        String grade;
        int semester;
        String version;
        KnowledgePointMasteryDTO knowledgePointMasteryDTO;
        ModuleDTO notCurrentSemesterKnowledge = null;
        ModuleDTO moduleDTO;
        for (Map<String, Object> knowledgeMasteryMap : knowledgeMasteryMapList) {
            howDetailId = Optional.ofNullable(knowledgeMasteryMap.get("how_detail_id"))
                    .orElse("").toString();
            grade = Optional.ofNullable(knowledgeMasteryMap.get("grade")).orElse("").toString();
            semester = Integer.parseInt(Optional.ofNullable(knowledgeMasteryMap.get("semester"))
                    .orElse(0).toString());
            version = Optional.ofNullable(knowledgeMasteryMap.get("version"))
                    .orElse(0).toString();

            //根据知识点id的set和版本查询知识点信息
            Map<String, Object> knowledgeInfoMap =
                    kmtKnowledgeMapper.findKnowledgeInfoByHowDetailIdAndTypeAndGradeAndSemester(howDetailId,
                            Integer.parseInt(version), grade, semester);
            if (knowledgeInfoMap != null) {
                if (learnedUnitList != null) {
                    //月报查询学习得单元
                    String howName = String.valueOf(knowledgeInfoMap.get("how_name"));
                    boolean howExisted = learnedUnitList.stream()
                            .anyMatch(it -> Objects.equals(it.getUnitName(), howName));
                    if (!howExisted) {
                        LearnedUnitDTO learnedUnitDTO = new LearnedUnitDTO();
                        learnedUnitDTO.setUnitName(howName);
                        learnedUnitList.add(learnedUnitDTO);
                    }
                }

                if (!Objects.equals(lastWeekGrade, grade) || lastWeekSemester != semester) {
                    //非本学期知识点
                    if (notCurrentSemesterKnowledge == null) {
                        notCurrentSemesterKnowledge = new ModuleDTO();
                        notCurrentSemesterKnowledge.setType(2);
                        notCurrentSemesterKnowledge.setModule("非本学期知识点");
                    }
                    moduleDTO = notCurrentSemesterKnowledge;
                } else {
                    Optional<ModuleDTO> moduleOptional = moduleDTOList.stream()
                            .filter(it -> Objects.equals(it.getModule(), knowledgeInfoMap.get("module")))
                            .findFirst();
                    if (moduleOptional.isPresent()) {
                        moduleDTO = moduleOptional.get();
                    } else {
                        moduleDTO = new ModuleDTO();
                        moduleDTO.setModule(String.valueOf(knowledgeInfoMap.get("module")));
                        moduleDTOList.add(moduleDTO);
                    }
                }
                List<KnowledgePointMasteryDTO> knowledgePointMasteryDTOList = moduleDTO.getKnowledgePointMasteryList();

                Optional<KnowledgePointMasteryDTO> optional = knowledgePointMasteryDTOList.stream()
                        .filter(it -> Objects.equals(it.getKnowledgeName(), knowledgeInfoMap.get("knowledge_name")))
                        .findFirst();
                if (optional.isPresent()) {
                    //已存在，说明两中批改方式均有此知识点的批改记录，累加涉及错题数和题目总数
                    knowledgePointMasteryDTO = optional.get();
                    knowledgePointMasteryDTO.setWrongCount(knowledgePointMasteryDTO.getWrongCount() + Integer.parseInt(knowledgeMasteryMap.get("wrong_count").toString()));
                    knowledgePointMasteryDTO.setTotalCount(knowledgePointMasteryDTO.getTotalCount() + Integer.parseInt(knowledgeMasteryMap.get("total_count").toString()));
                } else {
                    //记录此知识点涉及错题数和题目总数
                    knowledgePointMasteryDTO = new KnowledgePointMasteryDTO();
                    knowledgePointMasteryDTO.setKnowledgeName(String.valueOf(knowledgeInfoMap.get("knowledge_name")));
                    knowledgePointMasteryDTO.setWrongCount(Integer.parseInt(knowledgeMasteryMap.get("wrong_count").toString()));
                    knowledgePointMasteryDTO.setTotalCount(Integer.parseInt(knowledgeMasteryMap.get("total_count").toString()));
                    knowledgePointMasteryDTOList.add(knowledgePointMasteryDTO);
                }

                //根据知识点别名分组知识点（不同id知识点可能别名相同）
                List<KnowHowDetailDTO> knowHowDetailDTOList = knowledgePointMasteryDTO.getKnowHowDetailList();
                KnowHowDetailDTO knowHowDetailDTO = new KnowHowDetailDTO();
                knowHowDetailDTO.setKnowHowDetailId(howDetailId);
                knowHowDetailDTO.setKnowledgeVersion(version);
                knowHowDetailDTOList.add(knowHowDetailDTO);
            }
        }

        if (notCurrentSemesterKnowledge != null) {
            //存在非本学期知识点，放在集合的最后面
            moduleDTOList.add(notCurrentSemesterKnowledge);
        }

        Iterator<ModuleDTO> iterator = moduleDTOList.iterator();
        while (iterator.hasNext()) {
            moduleDTO = iterator.next();
            List<KnowledgePointMasteryDTO> finalKnowledgePointMasteryList = moduleDTO.getKnowledgePointMasteryList();
            if (subjectKnowledgeInfoDTOV2 != null) {
                //月报返回的是需要加强的知识点（掌握率小于85%）
                finalKnowledgePointMasteryList = finalKnowledgePointMasteryList.stream()
                        .filter(it -> it.getMastery() < 0.85)
                        .collect(Collectors.toList());
            }
            finalKnowledgePointMasteryList = finalKnowledgePointMasteryList.stream()
                    .sorted(Comparator.comparingDouble(KnowledgePointMasteryDTO::getMastery))
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(finalKnowledgePointMasteryList)) {
                moduleDTO.setKnowledgePointMasteryList(finalKnowledgePointMasteryList);
            } else {
                iterator.remove();
            }
        }

        return moduleDTOList;
    }


    private List<Map<String, Object>> countCampusCorrectionKnowledgeMastery(String vipId, String subject,
                                                                            String beginDateTimeStr,
                                                                            String endDateTimeStr) {

        List<Map<String, Object>> wrongQuestion4MasteryMapList = kmtExerciseMapper.findWrongQuestion4Mastery(vipId, subject, beginDateTimeStr, endDateTimeStr);
        if (CollectionUtils.isEmpty(wrongQuestion4MasteryMapList)) {
            return Collections.emptyList();
        }

        String questionId;
        List<Map<String, Object>> knowledgeMapList = new ArrayList<>(wrongQuestion4MasteryMapList.size() * 10);
        Map<String, Object> knowledgeMap;
        List<Map<String, Object>> tempKnowledgeMapList;
        for (Map<String, Object> wrongQuestion4MasteryMap : wrongQuestion4MasteryMapList) {
            questionId = Optional.ofNullable(wrongQuestion4MasteryMap.get("question_id")).map(Object::toString).orElse("");
            if (StringUtils.isBlank(questionId)) {
                continue;
            }

            tempKnowledgeMapList = kmtExerciseMapper.findKnowledgeByQuestionId(questionId);
            if (CollectionUtils.isNotEmpty(tempKnowledgeMapList)) {
                for (Map<String, Object> tempKnowledgeMap : tempKnowledgeMapList) {
                    knowledgeMap = new HashMap<>();
                    knowledgeMap.put("type", wrongQuestion4MasteryMap.get("type"));
                    knowledgeMap.put("how_detail_id", tempKnowledgeMap.get("how_detail_id"));
                    knowledgeMap.put("version", tempKnowledgeMap.get("version"));
                    knowledgeMap.put("grade", tempKnowledgeMap.get("grade"));
                    knowledgeMap.put("semester", tempKnowledgeMap.get("semester"));
                    knowledgeMap.put("alias", tempKnowledgeMap.get("alias"));
                    knowledgeMapList.add(knowledgeMap);
                }
            }
        }

        Map<String, List<Map<String, Object>>> knowledgeMapGroupByAlias = knowledgeMapList.stream()
                .collect(Collectors.groupingBy(it -> Optional.ofNullable(it.get("alias")).map(Object::toString).orElse("")));
        List<Map<String, Object>> knowledgeMasteryMapList = new ArrayList<>(knowledgeMapGroupByAlias.size());
        Map<String, Object> knowledgeMasteryMap;
        for (Map.Entry<String, List<Map<String, Object>>> entry : knowledgeMapGroupByAlias.entrySet()) {
            int wrongCount = 0;
            int totalCount = 0;
            knowledgeMasteryMap = new HashMap<>();
            Map<String, Object> firstKnowledgeMap = entry.getValue().get(0);
            knowledgeMasteryMap.put("how_detail_id", firstKnowledgeMap.get("how_detail_id"));
            knowledgeMasteryMap.put("version", firstKnowledgeMap.get("version"));
            knowledgeMasteryMap.put("grade", firstKnowledgeMap.get("grade"));
            knowledgeMasteryMap.put("semester", firstKnowledgeMap.get("semester"));
            for (Map<String, Object> tempKnowledgeMap : entry.getValue()) {
                totalCount ++;
                if (Objects.equals(1, tempKnowledgeMap.get("type"))) {
                    wrongCount ++;
                }
            }
            knowledgeMasteryMap.put("wrong_count", wrongCount);
            knowledgeMasteryMap.put("total_count", totalCount);
            knowledgeMasteryMapList.add(knowledgeMasteryMap);
        }

        return knowledgeMasteryMapList;
    }

    @Override
    public List<Map<String, Object>> findData2EsByQuestionList(List<String> questionIdList) {
        return kmtExerciseMapper.findData2EsByQuestionList(questionIdList);
    }

    @Override
    public long updateTotal2Es() {
        logger.info("更新es索引kmt_exercise_question_know开始");

        int pageSize = 625;
        long updateCount = 0;
        List<Map<String, Object>> dataMapList = new ArrayList<>();
        int failedCount = 0;
        boolean isContinue = true;
        boolean updateSuccess;

        do {
            if (dataMapList.isEmpty()) {
                dataMapList = kmtExerciseMapper.findAll2Es(pageSize);
                if (dataMapList.size() < pageSize) {
                    isContinue = false;
                }
            }

            if (!dataMapList.isEmpty()) {
                // 获取题目扩展信息
                kmtExerciseService.appendQuestionMapFromJSONFile(dataMapList);

                //添加到es
                updateSuccess = baseSearchService.updateOrInsertBatch("kmt_exercise_question_know", dataMapList);
                if (updateSuccess) {
                    baseSearchService.clearCache("kmt_exercise_question_know");
                    updateCount += dataMapList.size();

                    //更新加载状态为已加载
                    List<String> kmtExerciseQuestionKnowIdList = dataMapList.stream().map(it -> String.valueOf(it.get("id"))).collect(Collectors.toList());
                    kmtExerciseMapper.updateExerciseQuestionKnowEsLoadStatus(kmtExerciseQuestionKnowIdList, 1);

                    logger.info("------>已加载{}条数据", updateCount);

                    dataMapList.clear();
                } else if (failedCount < 5){
                    failedCount ++;
                } else {
                    //更新加载状态为加载失败
                    List<String> kmtExerciseQuestionKnowIdList = dataMapList.stream().map(it -> String.valueOf(it.get("id"))).collect(Collectors.toList());
                    kmtExerciseMapper.updateExerciseQuestionKnowEsLoadStatus(kmtExerciseQuestionKnowIdList, 2);
                    dataMapList.clear();
                    failedCount = 0;
                }
            }
        } while (isContinue);

        logger.info("更新es索引kmt_exercise_question_know结束，共更新{}条记录", updateCount);

        return updateCount;
    }

    @Override
    public int countQuestionByKnowledgeAndVersion(List<String> knowledgeIdList, int version) {
        return kmtExerciseMapper.countQuestionByKnowledgeAndVersion(knowledgeIdList, version);
    }

    /**
     * 获取调用ES查询所需的参数
     *
     * @param wrongQuestionKnowHowDetailIdList 错题关联的知识点id列表
     * @param needExcludedQuestionIdSet 需要排除的题目id
     * @param selectType 查询类型（1查询大题，2查询小题）
     * @param needNum 查询多少道题
     *
     * @return 示例
     * {
     * 	"query": {
     * 		"bool": {
     * 			"should": [
     *                {
     * 					"query_string": {
     * 						"default_field": "how_details_id.keyword",
     * 						"query": "dbe890a0-4c23-4ce3-95bc-01538c65f90b"
     *                    }
     *                },
     *                {
     * 					"query_string": {
     * 						"default_field": "how_details_id.keyword",
     * 						"query": "3a790f6f-4bd7-45ad-8036-3db0a7c9c8be"
     *                    }
     *                }
     * 			],
     * 			"must_not": [
     *                {
     * 					"query_string": {
     * 						"default_field": "question_id.keyword",
     * 						"query": "313a3153-d6a9-33f9-8fef-3b4da4046cc1"
     *                    }
     *                }
     * 			]
     * 		}
     * 	},
     * 	"size": 0,
     * 	"aggs": {
     * 		"group_by_question_id": {
     * 			"terms": {
     * 				"field": "question_id.keyword",
     * 				"order": {
     * 					"_count": "desc"
     *                },
     * 				"size": 2
     * 			},
     * 			"aggs": {
     * 				"result_top_hits": {
     * 					"top_hits": {
     * 						"_source": {
     * 							"includes": [
     * 								"question_id",
     * 								"num",
     * 								"question"
     * 							]
     *                        },
     * 						"size": 1
     *                    }
     *                }
     *            }
     *        }
     *  }
     * }
     */
    private Map<String, Object> getSelectParam(List<String> wrongQuestionKnowHowDetailIdList, Set<String> needExcludedQuestionIdSet, int selectType, int needNum) {
        if (CollectionUtils.isEmpty(wrongQuestionKnowHowDetailIdList)) {
            //必须先匹配知识点，未关联知识点的题目不进行推荐
            return null;
        }
        String query = "query";
        Map<String, Object> queryMap = new HashMap<>();
        //第一层
        Map<String, Object> boolMap = new HashMap<>();
        queryMap.put("bool", boolMap);
        //第二层
        List<Map<String, Object>> boolMustList = new ArrayList<>();
        boolMap.put("must", boolMustList);
        //第三层
        Map<String, Object> boolMustObj1 = new HashMap<>();
        boolMustObj1.put("exists", Collections.singletonMap("field", "book_id.keyword"));
        boolMustList.add(boolMustObj1);

        //第三层
        Map<String, Object> boolMustObj = new HashMap<>();
        boolMustList.add(boolMustObj);
        //第四层
        Map<String, Object> boolMustBoolMap = new HashMap<>();
        boolMustObj.put("bool", boolMustBoolMap);
        //第五层
        List<Map<String, Object>> boolMustBoolShouldList = new ArrayList<>();
        boolMustBoolMap.put("should", boolMustBoolShouldList);
        //第六层
        wrongQuestionKnowHowDetailIdList.forEach(knowledgeId -> {
            Map<String, Object> mustBoolShouldObj = new HashMap<>();
            boolMustBoolShouldList.add(mustBoolShouldObj);
            //第七层
            Map<String, Object> queryStringMap = new HashMap<>();
            mustBoolShouldObj.put("query_string", queryStringMap);
            queryStringMap.put("default_field", "how_details_id.keyword");
            queryStringMap.put(query, knowledgeId);
        });

        //第二层
        List<Map<String, Object>> boolMustNotList = new LinkedList<>();
        boolMap.put("must_not", boolMustNotList);
        //第三层
        Map<String, Object> boolMustNotObj1 = new HashMap<>();
        boolMustNotObj1.put("term", Collections.singletonMap("book_id.keyword", ""));
        boolMustNotList.add(boolMustNotObj1);

        //第三层
        needExcludedQuestionIdSet.forEach(needExcludedQuestionId -> {
            Map<String, Object> mustBoolMustNotObj = new HashMap<>();
            boolMustNotList.add(mustBoolMustNotObj);
            //第四层
            Map<String, Object> queryStringMap = new HashMap<>();
            mustBoolMustNotObj.put("query_string", queryStringMap);
            queryStringMap.put("default_field", "question_id.keyword");
            queryStringMap.put(query, needExcludedQuestionId);
        });
        String groupByColumn = "question_id";
        if (Objects.equals(2, selectType)) {
            groupByColumn = "parent_id";
            Map<String, Object> mustBoolMustNotObj = new HashMap<>();
            boolMustNotList.add(mustBoolMustNotObj);
            //第四层
            Map<String, Object> queryStringMap = new HashMap<>();
            mustBoolMustNotObj.put("term", queryStringMap);
            queryStringMap.put("parent_id.keyword", "");
        } else {
            //第三层
            Map<String, Object> mustBoolMustObj = new HashMap<>();
            boolMustList.add(mustBoolMustObj);
            //第四层
            Map<String, Object> queryStringMap = new HashMap<>();
            mustBoolMustObj.put("term", queryStringMap);
            queryStringMap.put("parent_id.keyword", "");
        }

        //分页
        Map<String, Object> pageMap = new HashMap<>();
        pageMap.put("size", 0);

        //聚合
        Map<String, Object> aggregationMap = JSON.parseObject("{\"group_by_question_id\":{\"terms\":{\"field\":\"" + groupByColumn + ".keyword\",\"order\":{\"_count\":\"desc\"},\"size\":" + needNum + "},\"aggs\":{\"result_top_hits\":{\"top_hits\":{\"_source\":{\"includes\":[\"question_id\",\"num\",\"parent_id\",\"question\",\"question_json\",\"book_id\"]},\"size\":1}}}}}");

        Map<String, Object> selectParamMap = new HashMap<>();
        selectParamMap.put("queryMap", queryMap);
        selectParamMap.put("aggregationMap", aggregationMap);
        selectParamMap.put("pageMap", pageMap);

        return selectParamMap;
    }


    @Override
    public List<ExerciseBookDto> findExerciseBooks(ExerciseConditionRequest request, String userId) {
        List<ExerciseBookDto> list = null, result = new ArrayList<>();
        if (request.getDealType() == 1){
            if (StringUtils.isBlank(request.getGrade())){
                //待加工页面没有科目年级，只判断年级
                list = kmtExerciseMapper.findUnHandleBooks(userId,request.getBookName());
            } else {
                //准备废弃
                list = kmtExerciseMapper.findUndistributedHandlerBooks(request.getSubject(), request.getSemester(), request.getVersionType(),  request.getGrade());
            }
        } else if (request.getDealType() == 2){
            if (StringUtils.isBlank(request.getGrade())){
                //待审核页面没有科目年级，只判断年级
                list = kmtExerciseMapper.findUnAuditingBooks(userId,request.getBookName());
            } else {
                //准备废弃
                list = kmtExerciseMapper.findUndistributedAuditerBooks(request.getSubject(), request.getSemester(), request.getVersionType(),  request.getGrade());
            }
        } else if (request.getDealType() == 4) {
            //解析加工练习册列表
            list = kmtExerciseMapper.findUnAnalysisHandleBooks(userId,request.getBookName());
        } else if (request.getDealType() == 5) {
            //解析审核练习册列表
            list = kmtExerciseMapper.findUnAnalysisAuditingBooks(userId,request.getBookName());
        } else if (request.getDealType() == 6){
            //未校对练习册列表
            list = kmtExerciseMapper.findUnCorrectAnswerBooks(userId, request.getBookName());
//            List<ExerciseBookDto> tempList = kmtExerciseMapper.findUnCorrectAnswerBooks(userId, request.getBookName());
//            list = new LinkedList<>();
//            List<String> exerciseBookIds = exerciseQuestionSearchService.findAnswerCorrectExerciseBookId(userId, request.getDealType());
//            if (CollectionUtils.isNotEmpty(exerciseBookIds)){
//                for (ExerciseBookDto temp : tempList){
//                    if  (exerciseBookIds.contains(temp.getExerciseBookId())){
//                        list.add(temp);
//                    }
//                }
//            }
        } else if (request.getDealType() == 7) {
            list = kmtExerciseMapper.findCorrectedAnswerBooks(userId, request.getBookName());
        }else {
            list = kmtExerciseMapper.findAllExerciseBooks(request.getSubject(), request.getSemester(), request.getVersionType(),  request.getGrade(), request.getBookName());
        }
        if (list != null) {
            for (ExerciseBookDto bookDto : list) {
                ExerciseBookDto resultBookDto = result.stream().filter(x ->
                        bookDto.getId().equals(x.getId())).findAny().orElse(null);
                if (resultBookDto == null){
                    String versionStr = knowledgeVersion.getVersionNameBySubjectAndVersionNum(bookDto.getSubject(), bookDto.getVersionType());
                    StringBuilder bookName = new StringBuilder();
                    bookName.append(bookDto.getName()).append("(").append(versionStr.substring(0, 1)).append(")");
                    if (bookDto.getBookType() == 1){
                        bookName.append("(半)");
                    }
                    bookDto.setName(bookName.toString());
                    ExerciseBookBaseDto version = new ExerciseBookBaseDto(bookDto.getVersionType() + "", versionStr);
                    bookDto.setVersion(version);

                    ExerciseBookYearDto dto = new ExerciseBookYearDto(bookDto.getBookYear());
                    dto.addBookType(bookDto.getBookType(), bookDto.getExerciseBookId());
                    bookDto.getBookYearList().add(dto);
                    result.add(bookDto);
                } else {
                    ExerciseBookYearDto resultBookYearDto = resultBookDto.getBookYearList().stream().filter(x ->
                            x.getBookYear() == bookDto.getBookYear()).findAny().orElse(null);
                    if (resultBookYearDto == null){
                        //是新年份， 增加年份
                        resultBookDto.addBookYear(bookDto.getBookYear(), bookDto.getBookType(), bookDto.getExerciseBookId());
                    } else {
                        resultBookYearDto.addBookType(bookDto.getBookType(), bookDto.getExerciseBookId());
                    }
                }
            }
        }
        return result;
    }

    @Override
    public List<ExerciseBookUnitDto> findExerciseBookDetail(ExerciseBookIdDealTypeRequest request, String userId) {
        List<ExerciseUnitBookcourseDto> list;
        List<ExerciseBookUnitDto> result = new ArrayList<>();
        if (request.getDealType() != 3){
            list = kmtExerciseMapper.findUnHandleExerciseBookCourse(request.getExerciseBookId(), request.getDealType(), userId);
//        } else if (request.getDealType() > 3) {
//            list = kmtExerciseMapper.findAnalysisUnHandleExerciseBookCourse(request.getId(), request.getDealType());
        } else {
            KmtExerciseBook book = kmtExerciseBookService.getById(request.getExerciseBookId());
            if (book.getBookType() == 1 || book.getBookType() == 2){
                list = kmtExerciseMapper.findAllExerciseBookCourseByExerciseBookId(book.getId());
            } else {
                list = kmtExerciseMapper.findAllExerciseBookCourse(book.getBookId(), book.getId());
            }
        }
        if (CollectionUtils.isNotEmpty(list)){
            Map<String, List<ExerciseUnitBookcourseDto>> map = list.stream().collect(
                    Collectors.groupingBy(ExerciseUnitBookcourseDto::getId, LinkedHashMap::new, Collectors.toList()));
            for (String unitId : map.keySet()){
                ExerciseBookUnitDto bookUnitDto = new ExerciseBookUnitDto();
                bookUnitDto.setId(unitId);
                bookUnitDto.setName(map.get(unitId).get(0).getName());
                for (ExerciseUnitBookcourseDto exerciseUnitBookcourseDto : map.get(unitId)){
                    bookUnitDto.addPeriod(new ExerciseBookBaseDto(exerciseUnitBookcourseDto.getBookCourseId(), exerciseUnitBookcourseDto.getBookCourse()));
                }
                result.add(bookUnitDto);
            }
        }

        return result;
    }

    @Override
    public Map<String, Object> getKmtHandlingQuestions(KmtHandlingQuestionRequest request, String userId) {
        Page page = new Page(request.getPageNo(), request.getPageSize());
        List<ExerciseQuetionDto> questions;
        Map<String, Object> originQuestions = null;

        //模糊查询加工审核人
        List<String> userIdList = new ArrayList<>();
        if (StringUtil.isNotBlank(request.getName())) {
//            List<KmtSysUser> users = kmtSysUserService.findByName(request.getName().trim());
            List<TbLibManager> users = bookManagerService.findByNameAndType(request.getName().trim(), 17);
            users.forEach(e -> userIdList.add(e.getUserId()));
            if(userIdList.size()==0){
                userIdList.add("noquestion");
            }
        }
        if (StringUtils.isNotBlank(request.getQuestionId())){
            //如果是小题，查询大题id出来
            request.setQuestionId(request.getQuestionId().trim());
            questions = kmtExerciseMapper.findKmtQuestionsById(request.getQuestionId(), userId, request.getDealType(), page);
        } else if (StringUtils.isNotBlank(request.getDetailId())){
            //存在知识点id的
//            questions = kmtExerciseMapper.findKmtQuestionByDetailId(request.getDetailId(), request.getPointId(), userId, request.getDealType(),userIdList, page);
            originQuestions = this.findKmtQuestionByDetailId(request, userId, userIdList);
            questions = (List<ExerciseQuetionDto>)originQuestions.get("data");
            page.setTotal(Long.parseLong(originQuestions.get("total").toString()));
        } else if (StringUtils.isNotBlank(request.getGrade())){
//            questions = kmtExerciseMapper.findKmtQuestionByGradeSubjectVersionSemester(request.getGrade(),
//                    request.getSubject(), request.getSemester(), request.getVersionType(), userId, request.getDealType(),userIdList, page);
            originQuestions = this.findKmtQuestionByGradeSubjectVersionSemester(request, userId, userIdList);
            questions = (List<ExerciseQuetionDto>)originQuestions.get("data");
            page.setTotal(Long.parseLong(originQuestions.get("total").toString()));
        } else {
            originQuestions = this.findAllKmtQuestions(userIdList, userId, request.getDealType(), request.getPageNo(), request.getPageSize());
            questions = (List<ExerciseQuetionDto>)originQuestions.get("data");
            page.setTotal(Long.parseLong(originQuestions.get("total").toString()));
//            questions = kmtExerciseMapper.findAllKmtQuestions(userId, request.getDealType(), userIdList, page);
        }
        questions = this.findAndAppendBigQuestion2List(questions);
        Map<String, Object> data  = new HashMap<>();
        data.put("pageNo", page.getCurrent());
        data.put("pageSize", page.getSize());
        data.put("pages", page.getPages());
        data.put("total", page.getTotal());
        data.put("maxCreateTime", request.getMaxCreateTime());
        data.put("list", kmtExerciseQuestionService.getQuestionGroupList(questions, false));
        return data;
    }

    /**
     * 遍历列表，添加小题
     * @param questions
     * @return
     */
    private List<ExerciseQuetionDto> findAndAppendSmallQuestion2List (List<ExerciseQuetionDto> questions){
        List<ExerciseQuetionDto> result = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(questions)){
            List<ExerciseQuetionDto> smallQuestions = kmtExerciseMapper.findSmallQuestionByParentIds(questions.stream().map(ExerciseQuetionDto::getQuestionId).collect(Collectors.toList()));
            questions.stream().forEach(question -> {
                result.add(question);
                if (CollectionUtils.isNotEmpty(smallQuestions)){
                    List<ExerciseQuetionDto> target = smallQuestions.stream().filter(small ->
                            small.getParentId().equals(question.getQuestionId())).collect(Collectors.toList());
                    if (CollectionUtils.isNotEmpty(target)){
                        result.addAll(target);
                    }
                }
            });
        }
        return result;
    }

    /**
     * 遍历列表，添加大题
     * @param questions
     * @return
     */
    @Override
    public List<ExerciseQuetionDto> findAndAppendBigQuestion2List (List<ExerciseQuetionDto> questions){
        List<ExerciseQuetionDto> result = new ArrayList<>();
        List<String> parentIdList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(questions)){
            for (ExerciseQuetionDto question : questions){
                if (StringUtils.isNotBlank(question.getParentId()) && !parentIdList.contains(question.getParentId())){
                    ExerciseQuetionDto bigQuestion = kmtExerciseMapper.findBigQuestionById(question.getParentId());
                    parentIdList.add(question.getParentId());
                    if (bigQuestion != null){
                        result.add(bigQuestion);
                    }
                }
                result.add(question);
            }
        }
        return result;
    }

    /**
     * 查询kmt题目列表,废弃
     * @param findUserIds
     * @param userId
     * @param dealType
     * @param pageNo
     * @param pageSize
     * @return
     */
    private Map<String, Object> findAllKmtQuestions(List<String> findUserIds, String userId, int dealType, int pageNo, int pageSize){
//        Map<String, Object> map = exerciseQuestionSearchService.findAllKmtQuestions(findUserIds, userId, dealType, pageNo, pageSize);
        Map<String, Object> map = new HashMap<>();
        Map<String, Object> result = new HashMap<>();
        result.put("total", 0L);
        result.put("data", null);
        if (map.size() > 0){
            result.put("total", map.get("total"));
            result.put("data", this.parseMapToExerciseQuestionList((List<Map>)map.get("data")));
        }
        return result;
    }

    /**
     * es字段转成实体字段
     * @param list
     * @return
     */
    public List<ExerciseQuetionDto> parseMapToExerciseQuestionList (List<Map> list){
        List<ExerciseQuetionDto> result = new ArrayList<>();
        if (list != null){
            String bookCourseId;
            KmtExerciseBookCourse kmtExerciseBookCourse;
            for (Map map : list){
                ExerciseQuetionDto temp = new ExerciseQuetionDto();
                temp.setQuestionId(map.getOrDefault("id", "").toString());
                temp.setCourseName(map.getOrDefault("courseName", "").toString());
                temp.setHandleUserId(map.getOrDefault("handleUserId", "").toString());
                temp.setAuditingUserId(map.getOrDefault("auditingUserId", "").toString());
                temp.setAnalysisUserId(map.getOrDefault("analysisUserId", "").toString());
                temp.setAnalysisAuditerId(map.getOrDefault("analysisAuditerId", "").toString());
                bookCourseId = map.getOrDefault("bookCourseId", "").toString();
                temp.setCourseId(bookCourseId);
                if (StringUtils.isNotBlank(bookCourseId)) {
                    // 查询练习册单元课时信息
                    kmtExerciseBookCourse = kmtExerciseBookCourseService.getById(bookCourseId);
                    if (kmtExerciseBookCourse != null) {
                        temp.setBookName(kmtExerciseBookCourse.getBookName());
                        temp.setUnit(kmtExerciseBookCourse.getUnit());
                        temp.setPeriod(kmtExerciseBookCourse.getPeriod());
                        temp.setGrade(kmtExerciseBookCourse.getGrade());
                        temp.setSemester(kmtExerciseBookCourse.getSemester());
                        temp.setVersionName(knowledgeVersion.getVersionNameBySubjectAndVersionNum(temp.getCourseName(), kmtExerciseBookCourse.getVersion()));
                    }
                }
                temp.setBigQuestionIndex(map.getOrDefault("bigQuestionIndex", "").toString());
                temp.setSmallQuestionIndex(Integer.parseInt(map.getOrDefault("num", "0").toString()) + "");
                temp.setQuestion(map.getOrDefault("question", "").toString());
                temp.setQuestionText(map.getOrDefault("questionText", "").toString());
                temp.setAnswer(map.getOrDefault("optionAnswer", "").toString());
                temp.setAnswerJson(map.getOrDefault("answerJson", "").toString());
                temp.setQuestionStatus(Integer.parseInt(map.getOrDefault("dealStatus", "0").toString()));
                temp.setCreateTime(map.getOrDefault("createTime", "").toString());
                temp.setReason(map.getOrDefault("remark", "").toString());
                temp.setQuestionAnalysis(map.getOrDefault("analysis", "").toString());
                temp.setAnalysisJson(map.getOrDefault("analysisJson", "").toString());
                temp.setQuestionTypes(Integer.parseInt(map.getOrDefault("questionType", "0").toString()));
                temp.setDifficultyLevels(Integer.parseInt(map.getOrDefault("difficultyLevel", "0").toString()));
                temp.setRealExamTypes(map.getOrDefault("realExamType", "").toString());
                temp.setTrainingSkills(map.getOrDefault("trainingSkill", "").toString());
                temp.setParentId(map.getOrDefault("parentId", "").toString());
                temp.setQuestionImage(map.getOrDefault("image", "").toString());
                temp.setFromUserId(map.getOrDefault("fromUserId", "").toString());
                temp.setToUserId(map.getOrDefault("toUserId", "").toString());
                temp.setUpdateType(map.getOrDefault("updateType", "").toString());
                result.add(temp);
            }
        }
        return result;
    }

    /**
     * 根据科目年级版本上下册查询kmt题目列表
     * @param request
     * @param userId
     * @param userIdList
     * @return
     */
    private Map<String, Object> findKmtQuestionByGradeSubjectVersionSemester (KmtHandlingQuestionRequest request, String userId, List<String> userIdList){
        Map<String, String> param = new HashMap<>();
        param.put("dealType", request.getDealType() + "");
        param.put("pageNo", request.getPageNo() + "");
        param.put("pageSize", request.getPageSize() + "");
        param.put("courseName", request.getSubject());
        param.put("grade", request.getGrade());
        param.put("semester", request.getSemester() + "");
        param.put("versionType", request.getVersionType() + "");
        Map<String, Object> result;
        result = exerciseQuestionSearchService.findKmtQuestionByGradeSubjectVersionSemester(param, userId, userIdList);
        result.put("data", this.parseKnowMapToExerciseQuestionList((List)result.get("data")));
        return result;
    }

    /**
     * es kmt_exercise_question_know 索引的字段转成实体字段
     * @param list
     * @return
     */
    private List<ExerciseQuetionDto> parseKnowMapToExerciseQuestionList (List<Map> list){
        List<ExerciseQuetionDto> result = new ArrayList<>();
        if (list != null){
            for (Map map : list){
                ExerciseQuetionDto temp = new ExerciseQuetionDto();
                temp.setQuestionId(map.getOrDefault("question_id", "").toString());
                temp.setCourseName(map.getOrDefault("course_name", "").toString());
                temp.setHandleUserId(map.getOrDefault("handle_user_id", "").toString());
                temp.setAuditingUserId(map.getOrDefault("auditing_user_id", "").toString());
                temp.setAnalysisUserId(map.getOrDefault("analysis_user_id", "").toString());
                temp.setAnalysisAuditerId(map.getOrDefault("analysis_auditer_id", "").toString());
                temp.setCourseId(map.getOrDefault("book_course_id", "").toString());
                temp.setBigQuestionIndex(map.getOrDefault("bigQuestion_index", "").toString());
                temp.setSmallQuestionIndex(Integer.parseInt(map.getOrDefault("num", "0").toString()) + "");
                temp.setQuestion(map.getOrDefault("question", "").toString());
                temp.setQuestionText(map.getOrDefault("question_text", "").toString());
                temp.setAnswer(map.getOrDefault("option_answer", "").toString());
                temp.setAnswerJson(map.getOrDefault("answer_json", "").toString());
                temp.setQuestionStatus(Integer.parseInt(map.getOrDefault("deal_status", "0").toString()));
//                temp.setCreateTime(map.getOrDefault("create_time", "").toString());
                temp.setReason(map.getOrDefault("remark", "").toString());
                temp.setQuestionAnalysis(map.getOrDefault("analysis", "").toString());
                temp.setAnalysisJson(map.getOrDefault("analysis_json", "").toString());
                temp.setQuestionTypes(Integer.parseInt(map.getOrDefault("question_type", "0").toString()));
                temp.setDifficultyLevels(Integer.parseInt(map.getOrDefault("difficulty_level", "0").toString()));
                temp.setRealExamTypes(map.getOrDefault("real_exam_type", "").toString());
                temp.setTrainingSkills(map.getOrDefault("training_skill", "").toString());
                temp.setParentId(map.getOrDefault("parent_id", "").toString());
                temp.setQuestionImage(map.getOrDefault("image", "").toString());
                temp.setFromUserId(map.getOrDefault("from_user_id", "").toString());
                temp.setToUserId(map.getOrDefault("to_user_id", "").toString());
                temp.setUpdateType(map.getOrDefault("update_type", "").toString());
                result.add(temp);
            }
        }
        return result;
    }

    /**
     * 根据知识点考点查询kmt题目
     * @param request
     * @param userId
     * @param userIdList
     * @return
     */
    private Map<String, Object> findKmtQuestionByDetailId(KmtHandlingQuestionRequest request, String userId, List<String> userIdList){
        Map<String, String> param = new HashMap<>();
        param.put("dealType", request.getDealType() + "");
        param.put("pageNo", request.getPageNo() + "");
        param.put("pageSize", request.getPageSize() + "");
        param.put("detailId", request.getDetailId());
        param.put("pointId", request.getPointId());
        Map<String, Object> result;
        result = exerciseQuestionSearchService.findKmtQuestionByDetailId(param, userId, userIdList);
        result.put("data", this.parseKnowMapToExerciseQuestionList((List)result.get("data")));
        return result;
    }


    @Override
    public ResponseEntity findQuestionListByParentId(List<String> parentIds) {
        ResponseEntity responseEntity = new ResponseEntity();
        List<ExerciseQuetionDto> questions = new ArrayList<>();
        List<Map> questionTmps;
        List<ExerciseQuetionDto> exerciseQuetionDtos;
        if (CollectionUtils.isNotEmpty(parentIds)){
            for (String parentId : parentIds){
                questionTmps = exerciseQuestionSearchService.findKmtQuestionsByParentId(parentId);
                exerciseQuetionDtos = this.parseMapToExerciseQuestionList(questionTmps);
                if (CollectionUtils.isNotEmpty(exerciseQuetionDtos)){
                    questions.addAll(exerciseQuetionDtos);
                }
            }
        }
        Map<String, Object> data  = new HashMap<>();
        data.put("list", kmtExerciseQuestionService.getQuestionGroupList(questions, false));
        responseEntity.success(data, "查询成功");
        return responseEntity;
    }

    @Override
    public List<ExerciseBookUnitDto> findUnitAndPeriodList(UnitAndPeriodListRequest request) {
        List<ExerciseBookUnitDto> result = new ArrayList<>();
        List<ExerciseUnitBookcourseDto> list = kmtExerciseMapper.findUnitAndPeriodList(request);

        if (CollectionUtils.isNotEmpty(list)){
            Map<String, List<ExerciseUnitBookcourseDto>> map = list.stream().collect(
                    Collectors.groupingBy(ExerciseUnitBookcourseDto::getId, LinkedHashMap::new, Collectors.toList()));
            for (String unitId : map.keySet()){
                ExerciseBookUnitDto bookUnitDto = new ExerciseBookUnitDto();
                bookUnitDto.setId(unitId);
                bookUnitDto.setName(map.get(unitId).get(0).getName());
                for (ExerciseUnitBookcourseDto exerciseUnitBookcourseDto : map.get(unitId)){
                    bookUnitDto.addPeriod(new ExerciseBookBaseDto(exerciseUnitBookcourseDto.getBookCourseId(), exerciseUnitBookcourseDto.getBookCourse()));
                }
                result.add(bookUnitDto);
            }
        }

        return result;
    }

    @Override
    public List<ExerciseBookCourseClassDto> findClassifyQuestionsByIds(List<String> questionIds) {
        List<Map> tmpList = exerciseQuestionSearchService.findAllExerciseQuestionsByQuestionIds(questionIds);
        List<ExerciseQuetionDto> temps = this.parseMapToExerciseQuestionList(tmpList);
        List<ExerciseQuetionDto> questions = new ArrayList<>();
        for (String questionId : questionIds){
            for (ExerciseQuetionDto temp : temps){
                if (questionId.equals(temp.getQuestionId())){
                    questions.add(temp);
                    break;
                }
            }
        }
        return kmtExerciseQuestionService.getSimplifyQuestionGroupList(questions, false);
    }

    @Override
    public List<KmtExerciseBookLibDto> findOrgCount(String libId, String subject){
        return kmtExerciseMapper.findAllExerciseBook(libId,subject);
    }
}
