package com.ssj.service.kmt.kmt.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.TypeReference;
import com.ssj.bean.kmt.kmt.domain.*;
import com.ssj.bean.kmt.kmt.dto.KmtSysUserAuthDto;
import com.ssj.bean.kmt.kmt.model.QuestionListKnowModel;
import com.ssj.bean.kmt.kmtsys.domain.KmtSysUser;
import com.ssj.bean.weixin.libmy.domain.TbLibManager;
import com.ssj.conch.constant.CourseConstant;
import com.ssj.dao.kmt.kmt.dao.KmtExerciseQueryDao;
import com.ssj.dao.kmt.kmt.dao.KmtExerciseQuestionDao;
import com.ssj.es.entiy.ElasticEntity;
import com.ssj.es.service.ExerciseQuestionSearchService;
import com.ssj.es.service.base.BaseSearchService;
import com.ssj.framework.core.common.service.BaseServiceImpl;
import com.ssj.framework.core.util.*;
import com.ssj.framework.weixin.util.DateUtil;
import com.ssj.service.conch.parents.v2.dto.TrainRecommendQuestionDTO;
import com.ssj.service.kmt.constant.KnowledgeVersion;
import com.ssj.service.kmt.dto.*;
import com.ssj.service.kmt.dto.exercise.ExerciseQuestionRollbacks;
import com.ssj.service.kmt.dto.exercise.QuestionAttributeFilterDto;
import com.ssj.service.kmt.dto.exercise.QuestionSubjectAttribute;
import com.ssj.service.kmt.exercisesys.request.ExerciseTeacherClassRequest;
import com.ssj.service.kmt.request.AnswerSearchRequest;
import com.ssj.service.kmt.request.AnswerSearchV1Request;
import com.ssj.service.kmt.request.AnswerSearchV2Request;
import com.ssj.service.kmt.request.ExerciseQuestionsRequest;
import com.ssj.service.kmt.service.*;
import com.ssj.service.mapper.KmtExerciseMapper;
import com.ssj.service.mapper.LibManagerMapper;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Transactional
@Service(version ="1.0")

public class KmtExerciseQuestionServiceImpl extends BaseServiceImpl<KmtExerciseQuestion, String> implements KmtExerciseQuestionService {

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

    @Autowired
    private KmtExerciseQuestionDao kmtExerciseQuestionDao;

    @Autowired
    private KmtExerciseQueryDao queryDao;

    @Autowired
    private KmtExerciseBookCourseService kmtExerciseBookCourseService;

    @Autowired
    private KmtSysUserService kmtSysUserService;

    @Autowired
    private KmtExerciseQuestionKnowService kmtExerciseQuestionKnowService;

    @Autowired
    private KmtHomeworkWrongQuestionService kmtHomeworkWrongQuestionService;
    @Autowired
    private KmtExerciseMapperService kmtExerciseMapperService;
    @Autowired
    private KmtExerciseMapper kmtExerciseMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private ExerciseQuestionSearchService exerciseQuestionSearchService;
    @Autowired
    private HomeworkPictureService homeworkPictureService;
    @Autowired
    private QuestionRecommendRecordService questionRecommendRecordService;
    @Autowired
    private KnowledgeVersion knowledgeVersion;
    @Autowired
    private BaseSearchService baseSearchService;
    @Autowired
    private LibManagerMapper libManagerMapper;
    @Autowired
    private KmtExerciseBookService kmtExerciseBookService;
    @Autowired
    private KmtExerciseService kmtExerciseService;

    @Override
    public PagingAndSortingRepository<KmtExerciseQuestion, String> getDao() {
        return kmtExerciseQuestionDao;
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<KmtExerciseQuestion> findByBookCourseId(String periodId) {
        return kmtExerciseQuestionDao.findByBookCourseIdOrderByNumAscCreateTimeAsc(periodId);
    }

    @Override
    public List<KmtExerciseQuestion> findByUnitId(String unitId) {
        return kmtExerciseQuestionDao.findByUnitId(unitId);
    }

    @Override
    public List<KmtExerciseQuestion> findByBookId(String bookId) {
        return kmtExerciseQuestionDao.findByBookId(bookId);
    }



    @Override
    public ResponseEntity findExerciseQuestions(String userId, ExerciseQuestionsRequest request) {
        long beginTime = System.currentTimeMillis();
        ResponseEntity responseEntity = new ResponseEntity();
        Map<String, Object> data = new HashMap<>();
        List<ExerciseBookCourseClassDto> list = new ArrayList<>();
        com.baomidou.mybatisplus.extension.plugins.pagination.Page page = new com.baomidou.mybatisplus.extension.plugins.pagination.Page(request.getPageNo(), request.getPageSize());


        if (StringUtils.isNotBlank(request.getPeriodId())){
            List<ExerciseQuetionDto> questions = kmtExerciseMapperService.findQuestionByBookCourseIdAndUserId(request, page,  userId);
            kmtExerciseService.appendQuestionDtoDataFromJSONFile(questions);
            list = this.getQuestionGroupList(questions, true);
        }
        data.put("list", list);
        data.put("pageNo", page.getCurrent());
        data.put("pageSize", page.getSize());
        data.put("pages", page.getPages());
        data.put("total", page.getTotal());
        responseEntity.success(data, "查询成功");
        logger.info("耗时" + (System.currentTimeMillis() - beginTime));
        return responseEntity;
    }

    @Override
    public List<ExerciseBookCourseClassDto> getQuestionGroupList (List<ExerciseQuetionDto> list, boolean hasBigQuestionIndex){
        List<ExerciseBookCourseClassDto> result = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(list)){
            List<String> questionIds = list.stream().map(ExerciseQuetionDto::getQuestionId).collect(Collectors.toList());
            List<QuestionListKnowModel> questionKnows = kmtExerciseMapper.findQuestionKnowByQuestionIds(questionIds);
            result = getCommonQuestionGroupList(list, questionKnows, hasBigQuestionIndex);
        }
        return  result;
    }

    @Override
    public List<ExerciseBookCourseClassDto> getSimplifyQuestionGroupList (List<ExerciseQuetionDto> list, boolean hasBigQuestionIndex){
        List<ExerciseBookCourseClassDto> result = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(list)){
            List<String> questionIds = list.stream().map(ExerciseQuetionDto::getQuestionId).collect(Collectors.toList());
            List<QuestionListKnowModel> questionKnows = kmtExerciseMapper.findQuestionKnowByQuestionIds(questionIds);

            for (ExerciseQuetionDto exerciseQuestionDto : list){
                this.setQuestionStatus(exerciseQuestionDto);
                exerciseQuestionDto.setParentId(StringUtil.isBlank(exerciseQuestionDto.getParentId()) ?
                        exerciseQuestionDto.getQuestionId() : exerciseQuestionDto.getParentId());
                if (questionKnows != null){
                    this.setQuestionKnowledge(exerciseQuestionDto, questionKnows.stream().filter(map ->
                            exerciseQuestionDto.getQuestionId().equals(map.getQuestionId())).collect(Collectors.toList()));
                }
                if (hasBigQuestionIndex){
                    this.getBigQuestionClassList(result, exerciseQuestionDto).getList().add(exerciseQuestionDto);
                } else {
                    this.getBigQuestionClassListByParentId(result, exerciseQuestionDto).getList().add(exerciseQuestionDto);
                }
            }
            Collections.reverse(result);
        }
        return  result;
    }


    @Override
    public List<ExerciseBookCourseClassDto> getKmtQualityQuestionGroupList (List<ExerciseQuetionDto> list){
        List<ExerciseBookCourseClassDto> result = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(list)){
            List<String> questionIds = list.stream().map(ExerciseQuetionDto::getQuestionId).collect(Collectors.toList());
            List<QuestionListKnowModel> questionKnows = kmtExerciseMapper.findKmtQuestionKnowByQuestionIds(questionIds);
            result = getCommonQuestionGroupList(list, questionKnows, false);
        }
        return  result;
    }

    /**
     * 题目转成二级结构
     * @param list
     * @param questionKnows
     * @param hasBigQuestionIndex
     * @return
     */
    private List<ExerciseBookCourseClassDto> getCommonQuestionGroupList (List<ExerciseQuetionDto> list, List<QuestionListKnowModel> questionKnows, boolean hasBigQuestionIndex){
        List<ExerciseBookCourseClassDto> result = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(list)){
            List<String> userIds = this.findUserIdsInExerciseQuestionList(list);
            List<TbLibManager> users = null;
            if (CollectionUtils.isNotEmpty(userIds)){
                Integer[] types = {17, 18};
                users = libManagerMapper.findTbLibManagerByUserIdsAndType(userIds, Arrays.asList(types));
            }
            for (ExerciseQuetionDto exerciseQuestionDto : list){
                this.setQuestionStatus(exerciseQuestionDto);
                exerciseQuestionDto.setParentId(StringUtil.isBlank(exerciseQuestionDto.getParentId()) ?
                        exerciseQuestionDto.getQuestionId() : exerciseQuestionDto.getParentId());
                exerciseQuestionDto.appendUserNameByIds(users);
                //如果用户记录没有，查询老的kmtSysUser表
                if (StringUtils.isBlank(exerciseQuestionDto.getDealUser())){
                    List<KmtSysUser> kmtSysUsers = kmtSysUserService.findKmtSysUserByIds(this.findUserIdsInExerciseQuestionList(list));
                    exerciseQuestionDto.appendKmtSysUserNameByIds(kmtSysUsers);
                }
                //有打回理由查询理由的最新记录
                if (StringUtils.isNotBlank(exerciseQuestionDto.getReason())){
                    KmtExerciseQuestionRollback rollback = kmtExerciseMapper.findLastExerciseRollbackByQuestionId(exerciseQuestionDto.getQuestionId());
                    if (rollback != null){
                        List<KmtSysUserAuthDto> authDtos = JSONArray.parseArray(PropertiesUtil.getValue("KMT_SYS_USER_AUTH"), KmtSysUserAuthDto.class);
                        String fromUserId=rollback.getUserId();
                        TbLibManager tbLibManager=kmtExerciseMapper.findByUserIdAndTypeIn(fromUserId);
                        if(null==tbLibManager){
                            //老用户
                            exerciseQuestionDto.setFromUser(this.getOldName(fromUserId,authDtos));
                        }else {
                            //新用户
                            exerciseQuestionDto.setFromUser(getAuthorityByType(rollback.getFromUserType()) + exerciseQuestionDto.getFromUser());
                        }
                        if(StringUtils.isBlank(rollback.getToUserId())){
                            exerciseQuestionDto.setToUser("AI");
                        }else {
                            TbLibManager tbLibManager2=kmtExerciseMapper.findByUserIdAndTypeIn(rollback.getToUserId());
                            if(null==tbLibManager2){
                                //老
                                exerciseQuestionDto.setToUser(this.getOldName(rollback.getToUserId(),authDtos));
                            }else {
                                //新
                                exerciseQuestionDto.setToUser(getAuthorityByType(rollback.getToUserType()) + exerciseQuestionDto.getToUser());
                            }
                        }
                    }
                }

                //update_type=4表示是新录入的题， handle_user_id是录入员
                if ("4".equals(exerciseQuestionDto.getUpdateType())){
                    exerciseQuestionDto.setAddUser(exerciseQuestionDto.getDealUser());
                    exerciseQuestionDto.setDealUser("");
                }


                if (questionKnows != null){
                    this.setQuestionKnowledge(exerciseQuestionDto, questionKnows.stream().filter(map ->
                            exerciseQuestionDto.getQuestionId().equals(map.getQuestionId())).collect(Collectors.toList()));
                }
                if (hasBigQuestionIndex){
                    this.getBigQuestionClassList(result, exerciseQuestionDto).getList().add(exerciseQuestionDto);
                } else {
                    this.getBigQuestionClassListByParentId(result, exerciseQuestionDto).getList().add(exerciseQuestionDto);
                }
            }
            Collections.reverse(result);
        }
        return  result;
    }


    /**
     * 类型获取名称
     * @param type
     * @return
     */
    @Override
    public String getAuthorityByType (int type){
        String result = "管理员";
        if (type == 9){
            result = "";
        } else {
            switch (type){
                case 1: result = "题目加工人";break;
                case 2: result = "题目审核人";break;
                case 3: result = "解析加工人";break;
                case 4: result = "解析审核人";break;
                case 5: result = "题库迁移人";break;
                case 6: result = "题库审核人";break;
                default: result = "管理员"; break;
            }
        }
        return result;
    }


    private String getUser(ExerciseQuestionRollbacks exerciseQuestionRollbacks,List<KmtSysUserAuthDto> authDtos,int type){
        String user=null;
        String prefix = "AI";
        if(1==type){
            if (StringUtils.isNotBlank(exerciseQuestionRollbacks.getFromType())){
                for (KmtSysUserAuthDto authDto : authDtos){
                    if (exerciseQuestionRollbacks.getFromType().equals(authDto.getType())){
                        prefix = "(" + authDto.getName() + ")";
                    }
                }
            }
            user=prefix + StringUtil.defaultIfEmpty(exerciseQuestionRollbacks.getFromUser(), "");
        }else {
            prefix = "AI";
            if (StringUtils.isNotBlank(exerciseQuestionRollbacks.getToType())){
                for (KmtSysUserAuthDto authDto : authDtos){
                    if (exerciseQuestionRollbacks.getToType().equals(authDto.getType())){
                        prefix = "(" + authDto.getName() + ")";
                    }
                }
            }
            user=prefix + StringUtil.defaultIfEmpty(exerciseQuestionRollbacks.getToUser(), "");
        }
        return user;
    }
    /**
     * 获取大题对象，如果列表中没有就往列表中添加
     * @param result
     * @param exerciseQuestionDto
     * @return
     */
    private ExerciseBookCourseClassDto getBigQuestionClassList (List<ExerciseBookCourseClassDto> result, ExerciseQuetionDto exerciseQuestionDto){
        ExerciseBookCourseClassDto bookCourseClass = this.isBookCourseClassExist(result, exerciseQuestionDto.getCourseId(),
                exerciseQuestionDto.getBigQuestionIndex());
        if (bookCourseClass == null){
            bookCourseClass = new ExerciseBookCourseClassDto(exerciseQuestionDto.getCourseId(), exerciseQuestionDto.getBigQuestionIndex());
            //加入列表的第一个，方便搜索查询， 后续会反转排序
            result.add(0, bookCourseClass);
        }
        return bookCourseClass;
    }

    private ExerciseBookCourseClassDto getBigQuestionClassListByParentId (List<ExerciseBookCourseClassDto> result, ExerciseQuetionDto exerciseQuestionDto){
        ExerciseBookCourseClassDto bookCourseClass = this.isParentIdExist(result, exerciseQuestionDto.getParentId());
        if (bookCourseClass == null){
            bookCourseClass = new ExerciseBookCourseClassDto();
            bookCourseClass.setParentId(exerciseQuestionDto.getParentId());
            //加入列表的第一个，方便搜索查询， 后续会反转排序
            result.add(0, bookCourseClass);
        }
        return bookCourseClass;
    }

    /**
     * 加工的状态包含打回和初始加工，需要都设置未加工中
     * @param exerciseQuestionDto
     */
    private void setQuestionStatus (ExerciseQuetionDto exerciseQuestionDto){
        if (StringUtil.isNotBlank(exerciseQuestionDto.getDealUser())){
            if (exerciseQuestionDto.getQuestionStatus() < 2){
                exerciseQuestionDto.setQuestionStatus(1);
            }
        }
    }

    /**
     * 设置知识点列表
     * @param exerciseQuestionDto
     * @param questionKnowList
     */
    private void setQuestionKnowledge (ExerciseQuetionDto exerciseQuestionDto, List<QuestionListKnowModel> questionKnowList){
        List<KnowHowDetailsDTO> knowHowDTOList = new ArrayList<>();
        if  (CollectionUtils.isNotEmpty(questionKnowList)){
            questionKnowList.forEach(map -> {
                if (map.getHowDetailsId() == null) return;
                boolean exists = false;
                //创建考点对象
                TestPointDTO point = new TestPointDTO(map.getHowDetailsKdId(), map.getKdName());
                //判断已有数据结构中是否
                for (KnowHowDetailsDTO knowHowDetailsDTO : knowHowDTOList) {
                    if (knowHowDetailsDTO.getId().equals(map.getHowDetailsId())) {
                        exists = true;
                        if (StringUtils.isNotBlank(map.getHowDetailsKdId())) {
                            knowHowDetailsDTO.addPoint(point);
                        }
                        break;
                    }
                }
                if (!exists) {
                    KnowHowDetailsDTO knowHowDetailsDTO = new KnowHowDetailsDTO(map.getHowDetailsId(), map.getDetailName());
                    knowHowDetailsDTO.setGrade(map.getGrade());
                    knowHowDetailsDTO.setSemester(map.getSemester());
                    knowHowDetailsDTO.setVersionName(knowledgeVersion.getVersionNameBySubjectAndVersionNum(map.getCourseName(), map.getVersionType()));
                    knowHowDetailsDTO.setHowName(map.getHowName());
                    if (StringUtils.isNotBlank(map.getHowDetailsKdId())) {
                        knowHowDetailsDTO.addPoint(point);
                    }
                    knowHowDTOList.add(knowHowDetailsDTO);
                }


                exerciseQuestionDto.setGrade(map.getGrade());
                exerciseQuestionDto.setVersionType(map.getVersionType());
                exerciseQuestionDto.setSemester(map.getSemester());
                exerciseQuestionDto.setSubject(map.getCourseName());
                exerciseQuestionDto.setModuleType(map.getModuleType() == 1 ? 2 : 1);
            });
            exerciseQuestionDto.setKnowledges(knowHowDTOList);
        }
    }

    /**
     * 从题目列表中提取四个用户的id
     * @param list
     * @return
     */
    private List<String> findUserIdsInExerciseQuestionList (List<ExerciseQuetionDto> list){
        Set<String> result = new HashSet<>();
        if (list != null) {
            list.stream().forEach(item -> {
                if (StringUtils.isNotBlank(item.getHandleUserId())) {
                    result.add(item.getHandleUserId());
                }
                if (StringUtils.isNotBlank(item.getAuditingUserId())) {
                    result.add(item.getAuditingUserId());
                }
                if (StringUtils.isNotBlank(item.getAnalysisUserId())) {
                    result.add(item.getAnalysisUserId());
                }
                if (StringUtils.isNotBlank(item.getAnalysisAuditerId())) {
                    result.add(item.getAnalysisAuditerId());
                }
                if (StringUtils.isNotBlank(item.getFromUserId())) {
                    result.add(item.getFromUserId());
                }
                if (StringUtils.isNotBlank(item.getToUserId()) && !"1".equals(item.getToUserId())) {
                    result.add(item.getToUserId());
                }
            });
        }
        return new ArrayList<>(result);
    }

    /**
     * 把数据库实体题目列表封装成前端对应字段返回
     * @param list
     * @return
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<ExerciseBookCourseClassDto> changeEntityToQuestionList(List<KmtExerciseQuestion> list, KmtExerciseBookCourse bookCourse){
        List<ExerciseBookCourseClassDto> result = new ArrayList<>();
        if (list != null && list.size() > 0) {
            Set<String> dealUserIds = new HashSet<>();
            Set<String> auditingUserIds = new HashSet<>();
            Set<String> analysisHandlerIds = new HashSet<>();
            Set<String> analysisAuditerIds = new HashSet<>();
            for (KmtExerciseQuestion question : list){
                if (question.getHandleUserId() != null){
                    dealUserIds.add(question.getHandleUserId());
                }
                if (question.getAuditingUserId() != null){
                    auditingUserIds.add(question.getAuditingUserId());
                }
                if (question.getAnalysisUserId() != null){
                    analysisHandlerIds.add(question.getAnalysisUserId());
                }
                if (question.getAnalysisAuditerId() != null){
                    analysisAuditerIds.add(question.getAnalysisAuditerId());
                }
            }
            List<String> questionIds = list.stream().map(KmtExerciseQuestion::getId).collect(Collectors.toList());
            List<KmtSysUser> users = kmtSysUserService.findKmtSysUserByIds(new ArrayList(dealUserIds));
            List<KmtSysUser> auditingUsers = kmtSysUserService.findKmtSysUserByIds(new ArrayList(auditingUserIds));
            List<KmtSysUser> analysisHandlers = kmtSysUserService.findKmtSysUserByIds(new ArrayList(analysisHandlerIds));
            List<KmtSysUser> analysisAuditers = kmtSysUserService.findKmtSysUserByIds(new ArrayList(analysisAuditerIds));

            List<QuestionListKnowModel> questionKnows =  kmtExerciseMapper.findQuestionKnowByQuestionIds(questionIds);

            list.forEach(kmtExerciseQuestion -> {
                ExerciseBookCourseClassDto bookCourseClass = this.isBookCourseClassExist(result, kmtExerciseQuestion.getBookCourseId(),
                        kmtExerciseQuestion.getBigQuestionIndex());
                if (bookCourseClass == null){
                    bookCourseClass = new ExerciseBookCourseClassDto(kmtExerciseQuestion.getBookCourseId(), kmtExerciseQuestion.getBigQuestionIndex());
                    result.add(0, bookCourseClass);
                }

                ExerciseQuetionDto temp = new ExerciseQuetionDto();
                temp.setQuestionId(kmtExerciseQuestion.getId());
                temp.setBookName(bookCourse.getBookName());
                temp.setCourseName(kmtExerciseQuestion.getCourseName());
                temp.setSmallQuestionIndex(kmtExerciseQuestion.getSmallQuestionName());
                temp.setQuestion(kmtExerciseQuestion.getQuestion());
                temp.setAnswer(kmtExerciseQuestion.getOptionAnswer());
                temp.setAnswerJson(kmtExerciseQuestion.getAnswerJson());
                temp.setQuestionText(kmtExerciseQuestion.getQuestionText());
                temp.setCreateTime(DateUtil.format_yyyyMMddHHmmss(kmtExerciseQuestion.getCreateTime()));
                temp.setQuestionAnalysis(kmtExerciseQuestion.getAnalysis());
                temp.setAnalysisJson(kmtExerciseQuestion.getAnalysisJson());
                temp.setQuestionTypes(kmtExerciseQuestion.getQuestionType() == null ? 0 : kmtExerciseQuestion.getQuestionType());
                temp.setDifficultyLevels(kmtExerciseQuestion.getDifficultyLevel() == null ? 0 : kmtExerciseQuestion.getDifficultyLevel());
                temp.setRealExamTypes(kmtExerciseQuestion.getRealExamType());
                temp.setTrainingSkills(kmtExerciseQuestion.getTrainingSkill());
                temp.setQuestionStatus(kmtExerciseQuestion.getDealStatus());

                if (StringUtils.isNotBlank(kmtExerciseQuestion.getRemark())){
                    temp.setReason(kmtExerciseQuestion.getRemark());
                }

                //用户名称
                if (users != null) {
                    for (KmtSysUser u : users) {
                        if (u.getId().equals(kmtExerciseQuestion.getHandleUserId())){
                            temp.setDealUser(u.getName());
                            break;
                        }
                    }
                }
                //用户名称
                if (auditingUsers != null) {
                    for (KmtSysUser u : auditingUsers) {
                        if (u.getId().equals(kmtExerciseQuestion.getAuditingUserId())){
                            temp.setAuditingUser(u.getName());
                            break;
                        }
                    }
                }

                //用户名称
                if (analysisHandlers != null) {
                    for (KmtSysUser u : analysisHandlers) {
                        if (u.getId().equals(kmtExerciseQuestion.getAnalysisUserId())){
                            temp.setAnalysisDealUser(u.getName());
                            break;
                        }
                    }
                }

                //用户名称
                if (analysisAuditers != null) {
                    for (KmtSysUser u : analysisAuditers) {
                        if (u.getId().equals(kmtExerciseQuestion.getAnalysisAuditerId())){
                            temp.setAnalysisAuditingUser(u.getName());
                            break;
                        }
                    }
                }
                //知识点
                if (questionKnows != null) {
                    List<QuestionListKnowModel> questionKnowList = questionKnows.stream().filter(map ->
                            kmtExerciseQuestion.getId().equals(map.getQuestionId())).collect(Collectors.toList());
                    List<KnowHowDetailsDTO> knowHowDTOList = new ArrayList<>();
                    questionKnowList.forEach(map -> {
                        if (map.getHowDetailsId() == null) return;
                        boolean exists = false;
                        //创建考点对象
                        TestPointDTO point = new TestPointDTO(map.getHowDetailsKdId(), map.getKdName());
                        //判断已有数据结构中是否
                        for (KnowHowDetailsDTO knowHowDetailsDTO : knowHowDTOList){
                            if (knowHowDetailsDTO.getId().equals(map.getHowDetailsId())){
                                exists = true;
                                if (StringUtils.isNotBlank(map.getHowDetailsKdId())) {
                                    knowHowDetailsDTO.addPoint(point);
                                }
                                break;
                            }
                        }
                        if (!exists) {
                            KnowHowDetailsDTO knowHowDetailsDTO  = new KnowHowDetailsDTO(map.getHowDetailsId(), map.getDetailName());
                            if (StringUtils.isNotBlank(map.getHowDetailsKdId())) {
                                knowHowDetailsDTO.addPoint(point);
                            }
                            knowHowDTOList.add(knowHowDetailsDTO);
                        }
                    });
                    temp.setKnowledges(knowHowDTOList);
                }
                bookCourseClass.getList().add(temp);
            });
            Collections.reverse(result);
        }
        return result;
    }

    /**
     * 该课时的大题是否存在
     * @param list
     * @param courseId 课时id
     * @param className  大题名称
     * @return
     */
    private ExerciseBookCourseClassDto isBookCourseClassExist (List<ExerciseBookCourseClassDto> list, String courseId, String className){
        ExerciseBookCourseClassDto result = null;
        for (ExerciseBookCourseClassDto courseClass : list){
            if (courseClass.getCourseId().equals(courseId) && courseClass.getName().equals(className)){
                result = courseClass;
                break;
            }
        }
        return result;
    }

    /**
     * 大题是否存在
     * @param list
     * @param parentId 大题id
     * @return
     */
    private ExerciseBookCourseClassDto isParentIdExist (List<ExerciseBookCourseClassDto> list, String parentId){
        ExerciseBookCourseClassDto result = null;
        for (ExerciseBookCourseClassDto courseClass : list){
            if (courseClass.getParentId().equals(parentId)){
                result = courseClass;
                break;
            }
        }
        return result;
    }


    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<ExerciseBookCourseClassDto> findQusetionsByCourseId(String courseId) {
        List<ExerciseBookCourseClassDto> result = new ArrayList<>();
//        List<KmtExerciseQuestion> list = this.findByBookCourseId(courseId);
        List<ExerciseQuetionDto> list = kmtExerciseMapper.findQuestionByBookCourseId(courseId);
        if (list != null) {
//            KmtExerciseBookCourse bookCourse = kmtExerciseBookCourseService.getById(courseId);
            result = this.getQuestionGroupList(list, true);
        }
        return result;
    }

    @Override
    public Map<String, List<ExerciseQuestionDto>> findByExerciseBookCourseId(AnswerSearchRequest request) {
        List<ExerciseQuestionDto> exerciseQuestionDtoList = null;
        Map<String, List<ExerciseQuestionDto>> temp = null;
        if (request.getPageIndex() > 0){
            exerciseQuestionDtoList = queryDao.findQuestionByBookIdAndPage(request.getBookId(), "", "",
                    new ArrayList<>(request.getPageIndex()), 2019);
        } else {
            exerciseQuestionDtoList = queryDao.findAnswerByExerciseBookCourseId(request.getExerciseBookCourseId(), 2019);
        }

        if (StringUtils.isNotBlank(request.getHomeworkId())){
            List<KmtHomeworkWrongQuestion> list = kmtHomeworkWrongQuestionService.findByHomeworkId(request.getHomeworkId());
            if (list != null){
                for (KmtHomeworkWrongQuestion wq : list){
                    for (ExerciseQuestionDto answer :  exerciseQuestionDtoList){
                        //对错记录与答案记录匹配
                        if (wq.getQuestionId().equals(answer.getQuestionId())){
                            if (StringUtils.isBlank(wq.getSpaceIndex())){
                                for (ExerciseQuestionAnswerDto  dto: answer.getAnswers()) {
                                    dto.setSelectedType(wq.getType());
                                }
                            } else {
                                String[] answerArray = wq.getSpaceIndex().split("、");
                                //所有答案先设置为对的
                                for (ExerciseQuestionAnswerDto  dto: answer.getAnswers()) {
                                    dto.setSelectedType(2);
                                }
                                for (String index : answerArray){
                                    ExerciseQuestionAnswerDto dto = answer.getAnswers().get(Integer.parseInt(index) - 1);
                                    dto.setSelectedType(1);
                                }
                            }
                            break;
                        }
                    }
                }
            }
        }
        temp = exerciseQuestionDtoList.stream().collect(Collectors.groupingBy(ExerciseQuestionDto::getBigQuestionIndex, LinkedHashMap::new, Collectors.toList()));
        return temp;
    }

    @Override
    public List<ExerciseQuestionAnswer4CorrectDTO> findByExerciseBookCourseIdV2(AnswerSearchRequest request) {
        List<ExerciseQuestionDto> exerciseQuestionDtoList;
        if (request.getPageIndex() > 0){
            exerciseQuestionDtoList = queryDao.findQuestionByBookIdAndPage(request.getBookId(),"", "",
                    new ArrayList<>(request.getPageIndex()), 2019);
        } else {
            exerciseQuestionDtoList = queryDao.findAnswerByExerciseBookCourseId(request.getExerciseBookCourseId(), 2019);
        }

        if (StringUtils.isNotBlank(request.getHomeworkId())){
            List<KmtHomeworkWrongQuestion> list = kmtHomeworkWrongQuestionService.findByHomeworkId(request.getHomeworkId());
            if (list != null){
                for (KmtHomeworkWrongQuestion wq : list){
                    for (ExerciseQuestionDto answer :  exerciseQuestionDtoList){
                        //对错记录与答案记录匹配
                        if (wq.getQuestionId().equals(answer.getQuestionId())){
                            if (StringUtils.isBlank(wq.getSpaceIndex())){
                                for (ExerciseQuestionAnswerDto  dto: answer.getAnswers()) {
                                    dto.setSelectedType(wq.getType());
                                }
                            } else {
                                String[] answerArray = wq.getSpaceIndex().split("、");
                                //所有答案先设置为对的
                                for (ExerciseQuestionAnswerDto  dto: answer.getAnswers()) {
                                    dto.setSelectedType(2);
                                }
                                for (String index : answerArray){
                                    ExerciseQuestionAnswerDto dto = answer.getAnswers().get(Integer.parseInt(index) - 1);
                                    dto.setSelectedType(1);
                                }
                            }
                            break;
                        }
                    }
                }
            }
        }
        Map<String, List<ExerciseQuestionDto>> temp = exerciseQuestionDtoList.stream().collect(Collectors.groupingBy(ExerciseQuestionDto::getBigQuestionIndex, LinkedHashMap::new, Collectors.toList()));
        List<ExerciseQuestionAnswer4CorrectDTO> exerciseQuestionAnswer4CorrectDTOList = new ArrayList<>(temp.size());
        temp.forEach((bigQuestionIndex, questionList) ->{
            ExerciseQuestionAnswer4CorrectDTO exerciseQuestionAnswer4CorrectDTO = new ExerciseQuestionAnswer4CorrectDTO();
            exerciseQuestionAnswer4CorrectDTO.setBigQuestionIndex(bigQuestionIndex);
            exerciseQuestionAnswer4CorrectDTO.setQuestionList(questionList);
            exerciseQuestionAnswer4CorrectDTOList.add(exerciseQuestionAnswer4CorrectDTO);
        });

        return exerciseQuestionAnswer4CorrectDTOList;
    }

    @Override
    public List<ExerciseQuestionAnswer4CorrectDTO> findByExerciseBookCourseIdV3(AnswerSearchV1Request request) {
        AnswerSearchV2Request request2 = new AnswerSearchV2Request();
        request2.setBookId(request.getBookId());
        request2.setHomeworkPictureId(request.getHomeworkPictureId());
        request2.setPeriodId(request.getExerciseBookCourseId());
        List<Integer> pageIndexs = new ArrayList<>();
        if (request.getPageIndex() > 0) {
            pageIndexs.add(request.getPageIndex());
        }
        request2.setPageIndexs(pageIndexs);
        return (List)this.findByExerciseBookCourseIdV4(request2).get("list");
    }


    private boolean isBigQuestionExists (List<String> questionIds, List<ExerciseQuestionDto> questionDtoList){
        boolean result = false;
        for (ExerciseQuestionDto question : questionDtoList){
            if (questionIds.contains(question.getQuestionId())){
                result = true;
                break;
            }
        }
        return result;
    }

    /**
     * 如果是练习册，获取的单元id为空，如果是测试卷，返回入参的单元id
     * @param bookId
     * @param unitId
     * @return
     */
    private String getAnswerListQueryUnitId(String bookId, String unitId){
        //调用es前的方法，2020年2月19日17:0:19
//    	int unitCount = kmtExerciseQuestionDao.countByBookIdAndPageIndex(bookId, 1);
//        // 一个页码出现在多个单元,说明是试卷，单元筛选生效
//        if (unitCount > 1){
//           return unitId;
//        }
//        return "";

        //-------------以下修改为调用es的方法，2020年2月19日17:0:19----------
        int unitCount = exerciseQuestionSearchService.countByBookIdAndPageIndex(bookId, 1);
        //一个页码出现在多个单元,说明是试卷，单元筛选生效
        if (unitCount > 1){
            return unitId;
        }
        return "";
    }


    @Override
    public List<ExerciseQuestionAnswer4CorrectDTO> findByExerciseBookPeriodId(AnswerSearchV2Request request) {
        AnswerSearchV1Request request1 = new AnswerSearchV1Request();
        request1.setBookId(request.getBookId());
        request1.setExerciseBookCourseId(request.getPeriodId());
        request1.setHomeworkPictureId(request.getHomeworkPictureId());
        if (request.getPageIndexs() != null && request.getPageIndexs().size() > 0){
            request1.setPageIndex(request.getPageIndexs().get(0));
        }
        return this.findByExerciseBookCourseIdV3(request1);
    }

    @Override
    public List<KmtExerciseQuestion> findByIdIn(List<String> wrongQuestionIdList) {
        return kmtExerciseQuestionDao.findByIdIn(wrongQuestionIdList);
    }

    @Override
    public Integer findKnowledgeVersionById(String questionId) {
        return queryDao.findKnowledgeVersionById(questionId);
    }

    @Override
    public List<String> findListAndParentByParentId(List<String> parentQuestionIdList) {
        return queryDao.findListAndParentByParentId(parentQuestionIdList);
    }

    @Override
    @Cacheable(value = "key", keyGenerator = "keyGenerator_ExerciseQuestion" , cacheManager="cacheManager")
    public List<ExerciseQuestionDto> findQuestionByBookIdAndPage(String bookId, String unitId, String bookCourseId,
                                                                 List<Integer> pageIndex, int bookYear) {
        //调用es前的方法，2020年2月19日16:58:53
        //unitId = this.getAnswerListQueryUnitId(bookId, unitId);
        //return queryDao.findQuestionByBookIdAndPage(bookId, unitId, bookCourseId, pageIndex, bookYear);



        //-------------以下修改为调用es的方法，2020年2月19日17:0:19----------
        unitId = this.getAnswerListQueryUnitId(bookId, unitId);

        List<ExerciseQuestionDto> exerciseQuestionDtoList=new ArrayList<ExerciseQuestionDto>();
        ExerciseQuestionDto exerciseQuestionDto=null;
        List<Map> list=exerciseQuestionSearchService.findQuestionByBookIdAndPage(bookId, unitId, bookCourseId, pageIndex, bookYear);
        if(list!=null) {
            for (Map map : list) {
                exerciseQuestionDto=new ExerciseQuestionDto();
                exerciseQuestionDto.setQuestionId(map.getOrDefault("id","").toString());
                exerciseQuestionDto.setBigQuestionIndex(map.getOrDefault("bigQuestionIndex","").toString());
                exerciseQuestionDto.setSmallQuestionIndex(map.getOrDefault("smallQuestionName","").toString());
                exerciseQuestionDto.setOptionAnswer(map.getOrDefault("optionAnswer","").toString());
                exerciseQuestionDto.setAnswerJson(map.getOrDefault("answerJson","").toString());
                exerciseQuestionDto.setBookCourseId(map.getOrDefault("bookCourseId","").toString());
                exerciseQuestionDtoList.add(exerciseQuestionDto);
            }
        }
        return exerciseQuestionDtoList;
    }

    @Override
    public List<ExerciseQuestionDto> findQuestionByBookIdAndPageByAll(String bookId,List<Integer> pageIndex) {
        return queryDao.findQuestionByBookIdAndPageByAll( bookId, pageIndex) ;
    }

    @Override
    @Cacheable(value = "key", keyGenerator = "keyGenerator_ExerciseQuestion" , cacheManager="cacheManager")
    public List<ExerciseQuestionDto> findAnswerByExerciseBookCourseId(
            String exerciseBookCourseId, int bookYear) {
        //调用es前的方法，2020年2月19日16:46:55
        //return queryDao.findAnswerByExerciseBookCourseId(exerciseBookCourseId, bookYear) ;


        //-------------以下修改为调用es的方法，2020年2月19日17:0:19----------
        List<ExerciseQuestionDto> exerciseQuestionDtoList=new ArrayList<ExerciseQuestionDto>();
        ExerciseQuestionDto exerciseQuestionDto=null;
        List<Map> list=exerciseQuestionSearchService.findAnswerByExerciseBookCourseId(exerciseBookCourseId, bookYear) ;
        if(list!=null) {
            for (Map map : list) {
                exerciseQuestionDto=new ExerciseQuestionDto();
                exerciseQuestionDto.setQuestionId(map.getOrDefault("id","").toString());
                exerciseQuestionDto.setBigQuestionIndex(map.getOrDefault("bigQuestionIndex","").toString());
                exerciseQuestionDto.setSmallQuestionIndex(map.getOrDefault("smallQuestionName","").toString());
                exerciseQuestionDto.setOptionAnswer(map.getOrDefault("optionAnswer","").toString());
                exerciseQuestionDto.setAnswerJson(map.getOrDefault("answerJson","").toString());
                exerciseQuestionDto.setBookCourseId(map.getOrDefault("bookCourseId","").toString());
                exerciseQuestionDtoList.add(exerciseQuestionDto);
            }
        }
        return exerciseQuestionDtoList;
    }

    @Override
    public boolean findIsNotPublish(AnswerSearchV2Request data) {
        boolean result = true;
        if (StringUtil.isNotBlank(data.getBookId())){
            int notPublishCount = 1;
            if (data.getPageIndexs() != null && data.getPageIndexs().size() > 0){
                notPublishCount = kmtExerciseQuestionDao.countByBookIdAndPageIndexIn(data.getBookId(), data.getPageIndexs());
            } else {
                notPublishCount = kmtExerciseQuestionDao.countByBookCourseId(data.getPeriodId());
            }
            if (notPublishCount == 0){
                result = false;
            }
        }
        return result;
    }

    @Override
    public List<ExerciseQuestionRollbacks> findQuestionRollbackRecord (String questionId){
        List<KmtExerciseQuestionRollback> list = kmtExerciseMapper.findKmtExerciseQuestionRollbackListByQuestionId(questionId);
        List<ExerciseQuestionRollbacks> list1=new ArrayList<>();
        List<KmtSysUserAuthDto> authDtos = JSONArray.parseArray(PropertiesUtil.getValue("KMT_SYS_USER_AUTH"), KmtSysUserAuthDto.class);
        list.stream().forEach(a->{
            ExerciseQuestionRollbacks exerciseQuestionRollbacks=new ExerciseQuestionRollbacks();
            String fromUser="";
            String toUser="";
            String fromUserId=a.getUserId();
            TbLibManager tbLibManager=kmtExerciseMapper.findByUserIdAndTypeIn(fromUserId);
            if(null==tbLibManager){
                //来向老用户
                fromUser=this.getOldName(fromUserId,authDtos);
            }else {
                //来向新用户
                fromUser=this.getNewName(tbLibManager,1,a);
            }
            if(null==a.getToUserId()){
                //去向为ai
                toUser="AI";
            }else {
                TbLibManager tbLibManager1=kmtExerciseMapper.findByUserIdAndTypeIn(a.getToUserId());
                if(null==tbLibManager1){
                    //去向老用户
                    toUser=this.getOldName(a.getToUserId(),authDtos);
                }else {
                    //去向新用户
                    toUser=this.getNewName(tbLibManager1,2,a);
                }
            }
            exerciseQuestionRollbacks.setFromUser(fromUser);
            exerciseQuestionRollbacks.setToUser(toUser);
            exerciseQuestionRollbacks.setCreateTime(a.getCreateTime());
            exerciseQuestionRollbacks.setReason(a.getReason());
            exerciseQuestionRollbacks.setId(a.getId());
            list1.add(exerciseQuestionRollbacks);
        });
        Collections.reverse(list1);
        return list1;
    }
    //查询老用户
    private  String getOldName(String userId, List<KmtSysUserAuthDto> authDtos){
        String name="AI";
        //查询老用户
        KmtSysUser user = kmtSysUserService.findKmtSysUserById(userId);
        //老用户里能查到的情况
        if(null!=user){
            if(StringUtils.isNotBlank(user.getType())){
                for(KmtSysUserAuthDto authDto : authDtos){
                    if (user.getType().equals(authDto.getType())){
                        name = "(" + authDto.getName() + ")"+StringUtil.defaultIfEmpty(user.getName(), "");
                    }
                }
            }

        }


        return name;
    }

    //查询新用户
    private String getNewName(TbLibManager tbLibManager,int type,KmtExerciseQuestionRollback kmt){
        String name="";
        String prefex="";
        if(1==type){
            prefex=this.getName(kmt.getFromUserType());
        }else {
            prefex=this.getName(kmt.getToUserType());
        }
        name=prefex+StringUtil.defaultIfEmpty(tbLibManager.getName(), "");
        return name;

    }

    private String getName(int type){
        Map<Integer,Object> hashMap=new HashMap<>();
        hashMap.put(0,"管理员");
        hashMap.put(1,"练习册加工员");
        hashMap.put(2,"练习册审核员");
        hashMap.put(3,"练习册解析员");
        hashMap.put(4,"练习册解审员");
        hashMap.put(5,"题库迁移员");
        hashMap.put(6,"题库审核员");
        hashMap.put(7,"题库录入员");
        hashMap.put(9,"AI");
        String typeName=hashMap.get(type).toString();
        return typeName;
    }

    @Override
    public List<QuestionAttributeFilterDto> findQuestionAttributeFilter() {
        List<QuestionAttributeFilterDto> result = new ArrayList<>();
        QuestionAttributeFilterDto temp = null;
        for (String subject : CourseConstant.MAIN_SUBJECT_LIST){
            temp = new QuestionAttributeFilterDto();
            temp.setSubject(subject);
            temp.setQuestionTypes(this.getQuestionAttributeBySubject(subject, JSONArray.parseArray(PropertiesUtil.getValue("QUESTION_TYPES"), QuestionSubjectAttribute.class)));
            temp.setTrainingSkills(this.getQuestionAttributeBySubject(subject, JSONArray.parseArray(PropertiesUtil.getValue("TRAINING_SKILL"), QuestionSubjectAttribute.class)));
            temp.setDifficultyLevels(JSONArray.parseArray(PropertiesUtil.getValue("DIFFICULTY_LEVELS"), KnowledgeBaseDto.class));
            temp.setRealExamTypes(JSONArray.parseArray(PropertiesUtil.getValue("REAL_EXAM_TYPE"), KnowledgeBaseDto.class));
            result.add(temp);
        }
        return result;
    }

    /**
     * 查询科目的难题属性筛选项
     * @param subject
     * @param list
     * @return
     */
    private List<KnowledgeBaseDto> getQuestionAttributeBySubject (String subject, List<QuestionSubjectAttribute> list){
        List<KnowledgeBaseDto> result = null;
        for (QuestionSubjectAttribute attribute : list){
            if (subject.equals(attribute.getSubject())){
                result = attribute.getList();
            }
        }
        return result;
    }

    @Override
    public List<ExerciseQuestionDto> findQuestionByQuestionIds(List<String> questionIds) {
        //调用es前的方法，2020年2月19日16:46:55
        //return queryDao.findQuestionByQuestionIds(questionIds);


        //-------------以下修改为调用es的方法，2020年2月19日17:0:19----------
        List<ExerciseQuestionDto> exerciseQuestionDtoList=new ArrayList<ExerciseQuestionDto>();
        ExerciseQuestionDto exerciseQuestionDto=null;
        List<Map> list=exerciseQuestionSearchService.findQuestionByQuestionIds(questionIds);
        if(list!=null) {
            for (Map map : list) {
                exerciseQuestionDto=new ExerciseQuestionDto();
                exerciseQuestionDto.setQuestionId(map.getOrDefault("id","").toString());
                exerciseQuestionDto.setBigQuestionIndex(map.getOrDefault("bigQuestionIndex","").toString());
                exerciseQuestionDto.setSmallQuestionIndex(map.getOrDefault("smallQuestionName","").toString());
                exerciseQuestionDto.setOptionAnswer(map.getOrDefault("optionAnswer","").toString());
                exerciseQuestionDto.setAnswerJson(map.getOrDefault("answerJson","").toString());
                exerciseQuestionDto.setBookCourseId(map.getOrDefault("bookCourseId","").toString());
                exerciseQuestionDtoList.add(exerciseQuestionDto);
            }
        }
        return exerciseQuestionDtoList;
    }

    @Override
    public void refreshAllToEs(String date) {
        int pageNo=0;
        int totalPages=-1;
        Pageable pageable =null;
        Page<KmtExerciseQuestion> page=null;
        List<KmtExerciseQuestion> list=null;

        while (true) {
            if(totalPages==-1 || totalPages>pageNo) {
                pageable = new PageRequest(pageNo, 1000);
                page=queryDao.findKmtExerciseQuestionsByPage(date,pageable);
                totalPages=page.getTotalPages();

                list=page.getContent();
                for (KmtExerciseQuestion kmtExerciseQuestion : list) {
                    exerciseQuestionSearchService.save(JSON.parseObject(JSON.toJSONString(kmtExerciseQuestion), new TypeReference<Map<String, Object>>() {}));
                }
                logger.info("全量加载kmt_exercise_questions到ES："+totalPages+"-->"+pageNo+"-->已完成。");
                pageNo=pageNo+1;
                page=null;
                list=null;
            }else {
                break;
            }
        }

    }

    @Override
    public boolean saveToEs(KmtExerciseQuestion kmtExerciseQuestion) {
        try {
            exerciseQuestionSearchService.save(JSON.parseObject(JSON.toJSONString(kmtExerciseQuestion), new TypeReference<Map<String, Object>>() {}));
            logger.info("保存kmt_exercise_questions到ES：->已完成。");
            return true;
        } catch (Exception e) {
            redisUtil.lpush(Constant.ES_SAVE_ERROR_QUESTIONS, kmtExerciseQuestion.getId());
            logger.error("保存kmt_exercise_questions到ES异常", e);
        }
        return false;
    }

    @Override
    public void bulkKmtExerciseQuestions(List<KmtExerciseQuestion> kmtExerciseQuestions) {
        if (CollectionUtils.isNotEmpty(kmtExerciseQuestions)){
            String[] questionIds = new String[kmtExerciseQuestions.size()];
            try {
                KmtExerciseQuestion exerciseQuestion;
                ElasticEntity elasticEntity;
                List<ElasticEntity> list = new LinkedList<>();
                for (int i = 0; i < kmtExerciseQuestions.size(); i++){
                    exerciseQuestion = kmtExerciseQuestions.get(i);
                    questionIds[i] = exerciseQuestion.getId();
                    elasticEntity = new ElasticEntity();
                    elasticEntity.setId(exerciseQuestion.getId());
                    elasticEntity.setData(JSON.parseObject(JSON.toJSONString(exerciseQuestion), new TypeReference<Map<String, Object>>() {}));
                    list.add(elasticEntity);
                }
                exerciseQuestionSearchService.insertBatch("kmt_exercise_questions", list);
                logger.info("保存kmt_exercise_questions到ES：->已完成。");
            } catch (Exception e) {
                redisUtil.lpush(Constant.ES_SAVE_ERROR_QUESTIONS, questionIds);
                logger.error("保存kmt_exercise_questions到ES异常", e);
            }
        }
    }

    @Override
    public void bulkBookExerciseQuestions(List<String> kmtExerciseBookIds) {
        if (CollectionUtils.isNotEmpty(kmtExerciseBookIds)){
            List<KmtExerciseQuestion> questionList;
            KmtExerciseBook exerciseBook = null;
            for (String exerciseBookId : kmtExerciseBookIds){
                exerciseBook = kmtExerciseBookService.getById(exerciseBookId);
                questionList = kmtExerciseMapper.findExerciseQuestionByExerciseBookId(exerciseBookId);
                kmtExerciseService.appendQuestionDataFromJSONFile(questionList);
                if (CollectionUtils.isNotEmpty(questionList)){
                    for (KmtExerciseQuestion kmtExerciseQuestion : questionList){
                        kmtExerciseQuestion.setHandleUserId(exerciseBook.getHandleUserId());
                        kmtExerciseQuestion.setAuditingUserId(exerciseBook.getAuditingUserId());
                        kmtExerciseQuestion.setAnalysisUserId(exerciseBook.getAnalysisUserId());
                        kmtExerciseQuestion.setAnalysisAuditerId(exerciseBook.getAnalysisAuditerId());
                    }
                    this.bulkKmtExerciseQuestions(questionList);
                }
            }
        }
    }

    @Override
    public void updateEsQuestionHandler(List<String> kmtExerciseBookIds, String teacherId, int type) {
        if (CollectionUtils.isNotEmpty(kmtExerciseBookIds)){
            QueryBuilder queryBuilder = QueryBuilders.termsQuery("exerciseBookId.keyword", kmtExerciseBookIds);
            Script script = new Script(ScriptType.INLINE, "painless",
                    this.getUpdateDSL(teacherId, type),
                    Collections.emptyMap());
            exerciseQuestionSearchService.updteByQuery("kmt_exercise_questions", queryBuilder, script);
        }
    }

    @Override
    public void updateEsQuestionHandlers(List<String> kmtExerciseBookIds, List<ExerciseTeacherClassRequest> teachers) {
        if (CollectionUtils.isNotEmpty(kmtExerciseBookIds) && CollectionUtils.isNotEmpty(teachers)){
            QueryBuilder queryBuilder = QueryBuilders.termsQuery("exerciseBookId.keyword", kmtExerciseBookIds);
            StringBuilder sb = new StringBuilder();
            for (ExerciseTeacherClassRequest request : teachers){
                sb.append(this.getUpdateDSL(request.getTeacherId(), request.getType()));
            }
            Script script = new Script(ScriptType.INLINE, "painless",
                    sb.toString(),
                    Collections.emptyMap());
            exerciseQuestionSearchService.updteByQuery("kmt_exercise_questions", queryBuilder, script);
        }
    }

    /**
     * es更新语句
     * @param teacherId
     * @param type
     * @return
     */
    private String getUpdateDSL (String teacherId, int type){
        StringBuilder sb = new StringBuilder();
        switch (type){
            case 1: sb.append("ctx._source['handleUserId']='").append(teacherId).append("';");break;
            case 2: sb.append("ctx._source['auditingUserId']='").append(teacherId).append("';");break;
            case 3: sb.append("ctx._source['analysisUserId']='").append(teacherId).append("';");break;
            case 4: sb.append("ctx._source['analysisAuditerId']='").append(teacherId).append("';");break;
            case 8: sb.append("ctx._source['answerCorrecterId']='").append(teacherId).append("';"); break;
            default: break;
        }
        return sb.toString();
    }


    @Override
    public void save2EsImmediate(KmtExerciseQuestion kmtExerciseQuestion) {
        try {
            exerciseQuestionSearchService.saveImmediate(JSON.parseObject(JSON.toJSONString(kmtExerciseQuestion), new TypeReference<Map<String, Object>>() {}));
        } catch (Exception e) {
            redisUtil.lpush(Constant.ES_SAVE_ERROR_QUESTIONS, kmtExerciseQuestion.getId());
            logger.error("保存kmt_exercise_questions到ES异常", e);
        }
    }


    @Override
    public List<TrainRecommendQuestionDTO> findChildTrainRecommendQuestionDTO(String parentId, int quantity) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                .filter(QueryBuilders.queryStringQuery(parentId).field("parentId.keyword"));

        String [] includeColumns ={"id", "question", "questionJson", "analysis", "analysisJson", "optionAnswer",
                "answerJson", "difficultyLevel", "questionType", "courseName", "num"};
        SearchSourceBuilder searchSourceBuilder = SearchSourceBuilder.searchSource()
                .query(boolQueryBuilder)
                .sort("num", SortOrder.ASC)
                .fetchSource(includeColumns, ArrayUtils.EMPTY_STRING_ARRAY)
                .size(quantity);

        SearchRequest searchRequest = new SearchRequest("kmt_exercise_questions");
        searchRequest.source(searchSourceBuilder);

        SearchResponse searchResponse = baseSearchService.search(searchRequest, null);
        if (searchResponse == null) {
            return Collections.emptyList();
        }
        SearchHit[] searchHits = searchResponse.getHits().getHits();
        List<TrainRecommendQuestionDTO> trainRecommendQuestionDTOList = new ArrayList<>(searchHits.length);
        Map<String, Object> hitSourceAsMap;
        TrainRecommendQuestionDTO trainRecommendQuestionDTO;
        for (SearchHit searchHit : searchHits) {
            hitSourceAsMap = searchHit.getSourceAsMap();
            trainRecommendQuestionDTO = new TrainRecommendQuestionDTO();
            trainRecommendQuestionDTO.setId(Optional.ofNullable(hitSourceAsMap.get("id")).orElse("").toString());
            trainRecommendQuestionDTO.setQuestion(Optional.ofNullable(hitSourceAsMap.get("question")).orElse("").toString());
            trainRecommendQuestionDTO.setQuestionJsonStr(Optional.ofNullable(hitSourceAsMap.get("questionJson")).orElse("[]").toString());
            trainRecommendQuestionDTO.setAnalysis(Optional.ofNullable(hitSourceAsMap.get("analysis")).orElse("").toString());
            trainRecommendQuestionDTO.setAnalysisJsonStr(Optional.ofNullable(hitSourceAsMap.get("analysisJson")).orElse("[]").toString());
            trainRecommendQuestionDTO.setOptionAnswer(Optional.ofNullable(hitSourceAsMap.get("optionAnswer")).orElse("").toString());
            trainRecommendQuestionDTO.setAnswerJsonStr(Optional.ofNullable(hitSourceAsMap.get("answerJson")).orElse("").toString());
            trainRecommendQuestionDTO.setDifficulty(Integer.valueOf(Optional.ofNullable(hitSourceAsMap.get("difficultyLevel")).orElse(-1).toString()));
            trainRecommendQuestionDTO.setOptionTypeInt(Integer.valueOf(Optional.ofNullable(hitSourceAsMap.get("questionType")).orElse(-1).toString()));
            trainRecommendQuestionDTO.setCourseName(Optional.ofNullable(hitSourceAsMap.get("courseName")).orElse("").toString());
            trainRecommendQuestionDTO.setNum(Integer.valueOf(Optional.ofNullable(hitSourceAsMap.get("num")).orElse(-1).toString()));
            trainRecommendQuestionDTOList.add(trainRecommendQuestionDTO);
        }

        return trainRecommendQuestionDTOList;
    }

    @Override
    public void save2EsBatch(List<KmtExerciseQuestion> kmtExerciseQuestionList) {
        if (CollectionUtils.isEmpty(kmtExerciseQuestionList)) {
            return;
        }

        int remainTimes = 5;
        boolean updateResult;

        List<ElasticEntity> elasticEntityList = new ArrayList<>(kmtExerciseQuestionList.size());
        ElasticEntity elasticEntity;
        List<String> kmtExerciseQuestionIdList = new ArrayList<>(kmtExerciseQuestionList.size());
        for (KmtExerciseQuestion kmtExerciseQuestion : kmtExerciseQuestionList) {
            if (StringUtils.isBlank(kmtExerciseQuestion.getId())) {
                continue;
            }
            elasticEntity = new ElasticEntity();
            elasticEntity.setId(kmtExerciseQuestion.getId());
            elasticEntity.setData(JSON.parseObject(JSON.toJSONString(kmtExerciseQuestion), new TypeReference<Map<String, Object>>() {}));
            elasticEntityList.add(elasticEntity);

            kmtExerciseQuestionIdList.add(kmtExerciseQuestion.getId());
        }

        // 更新kmt_exercise_questions索引
        do {
            updateResult = exerciseQuestionSearchService.insertOrUpdateBatch(elasticEntityList);

            remainTimes --;
        } while (remainTimes > 0 && !updateResult);
        if (!updateResult) {
            logger.error("更新练习册题目数据到es失败，共尝试5次");
        }

        // 更新kmt_exercise_question_know索引
        remainTimes = 5;
        List<Map<String, Object>> kmtExerciseQuestionKnowData2EsList = kmtExerciseMapper.findData2EsByQuestionList(kmtExerciseQuestionIdList);
        if (CollectionUtils.isEmpty(kmtExerciseQuestionKnowData2EsList)) {
            return;
        }

        // 获取题目扩展信息
        kmtExerciseService.appendQuestionMapFromJSONFile(kmtExerciseQuestionKnowData2EsList);

        do {
            updateResult = baseSearchService.updateOrInsertBatch("kmt_exercise_question_know",
                    kmtExerciseQuestionKnowData2EsList);
            remainTimes --;
        } while (remainTimes > 0 && !updateResult);
        if (!updateResult) {
            logger.error("更新练习册题目知识点关联数据到es失败，共尝试5次");
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public KmtExerciseQuestion getEsById(String id) {
        List<KmtExerciseQuestion> list=exerciseQuestionSearchService.getById(id,KmtExerciseQuestion.class);
        if (list == null || list.size()==0) {
            return null;
        }
        try {
            return list.get(0);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void updateAnswerCorrecterIdByExerciseBookId(String teacherId, String exerciseBookId) {
        kmtExerciseQuestionDao.updateAnswerCorrecterIdByExerciseBookId(teacherId, exerciseBookId);
    }

    @Override
    public void updateAnswerCorrecterIdByExerciseBookIds(String teacherId, List<String> exerciseBookIds){
        //kmtExerciseQuestionDao.updateAnswerCorrecterIdByExerciseBookIds(teacherId, exerciseBookIds);
        kmtExerciseMapper.updateAnswerCorrecterIdByExerciseBookIds(teacherId, exerciseBookIds);
    }

    @Override
    public void updateHandleUserIdByExerciseBookIds(String teacherId, List<String> exerciseBookIds) {
        kmtExerciseQuestionDao.updateHandleUserIdByExerciseBookIds(teacherId, exerciseBookIds);
    }

    @Override
    public void updateAuditingUserIdByExerciseBookIds(String teacherId, List<String> exerciseBookIds) {
        kmtExerciseQuestionDao.updateAuditingUserIdByExerciseBookIds(teacherId, exerciseBookIds);
    }

    @Override
    public void updateAnalysisUserIdByExerciseBookIds(String teacherId, List<String> exerciseBookIds) {
        kmtExerciseQuestionDao.updateAnalysisUserIdByExerciseBookIds(teacherId, exerciseBookIds);
    }

    @Override
    public void updateAnalysisAuditerIdByExerciseBookIds(String teacherId, List<String> exerciseBookIds) {
        kmtExerciseQuestionDao.updateAnalysisAuditerIdByExerciseBookIds(teacherId, exerciseBookIds);
    }
}
