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

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ssj.bean.common.framework.core.domain.BaseEntity;
import com.ssj.bean.kmt.kmt.domain.*;
import com.ssj.bean.weixin.libmy.domain.TbLibManager;
import com.ssj.bean.weixin.push.domain.SendTemplateShort;
import com.ssj.bean.weixin.user.domain.User;
import com.ssj.bean.weixin.zyb.domain.ZuoybKnowHowDetailsSort;
import com.ssj.es.service.ExerciseQuestionSearchService;
import com.ssj.es.service.base.BaseSearchService;
import com.ssj.es.utils.ElasticUtil;
import com.ssj.framework.core.security.exception.CommonException;
import com.ssj.framework.core.security.manager.TokenManager;
import com.ssj.framework.core.util.*;
import com.ssj.framework.weixin.util.DateUtil;
import com.ssj.kmt.utils.JSONFileUtil;
import com.ssj.service.conch.common.request.PageReq;
import com.ssj.service.kmt.dto.*;
import com.ssj.service.kmt.dto.exercise.ExerciseQuestionRollbacks;
import com.ssj.service.kmt.exercise.request.SubmitAnswerProofreadResultReq;
import com.ssj.service.kmt.exercisesys.enums.ProofreadStatusEnum;
import com.ssj.service.kmt.request.*;
import com.ssj.service.kmt.service.*;
import com.ssj.service.mapper.KmtExerciseMapper;
import com.ssj.service.mapper.LibManagerMapper;
import com.ssj.service.task.SyncRefreshExerciseBookDistributionCountTask;
import com.ssj.service.task.SyncRefreshExerciseBookStatusTask;
import com.ssj.service.weixin.library.service.IBookManagerService;
import com.ssj.service.weixin.push.service.PushTemplateService;
import com.ssj.service.weixin.user.service.UserService;
import com.ssj.service.weixin.zuoyb.service.ZuoybKnowHowDetailsSortService;
import com.ssj.taskthread.ThreadPool;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Factory;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

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

@Transactional
@Service(version ="1.0")
public class KmtExerciseServiceImpl implements KmtExerciseService {

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

    @Autowired
    private KmtExerciseQuestionService kmtExerciseQuestionService;
    @Autowired
    private KmtExerciseMapperService kmtExerciseMapperService;
    @Autowired
    private KmtExerciseQuestionKnowService kmtExerciseQuestionKnowService;
    @Autowired
    private KmtExerciseBookCourseService kmtExerciseBookCourseService;
    @Autowired
    private KmtExerciseQuestionRollbackService kmtExerciseQuestionRollbackService;
    @Autowired
    private ZuoybKnowHowDetailsSortService zuoybKnowHowDetailsSortService;
    @Autowired
    private KmtExerciseMapper kmtExerciseMapper;
    @Autowired
    private BaseSearchService baseSearchService;
    @Autowired
    private ExerciseQuestionSearchService exerciseQuestionSearchService;
    @Autowired
    private IBookManagerService bookManagerService;
    @Autowired
    private KmtExerciseQuestionErrorsService kmtExerciseQuestionErrorsService;
    @Autowired
    private LibManagerMapper libManagerMapper;
    @Autowired
    private KmtExerciseBookService kmtExerciseBookService;
    @Autowired
    private UserService userService;
    @Autowired
    private PushTemplateService pushTemplateService;
    @Autowired
    private KmtQualityQuestionsService kmtQualityQuestionsService;


    @Autowired
    private TokenManager tokenManager;


    @Override
    public ResponseEntity updateQuestion(QuestionUpdateRequest request) {
        ResponseEntity responseEntity = new ResponseEntity();
        String questionId = request.getQuestionId();
        KmtExerciseQuestion kmtExerciseQuestion = kmtExerciseQuestionService.getById(questionId);

        if (kmtExerciseQuestion == null) {
            logger.warn(String.format("题目不存在（id=%s）", questionId));
            return responseEntity.failure("题目不存在");
        }
        if (StringUtils.isNotBlank(request.getQuestionText())){
            kmtExerciseQuestion.setUpdateType(1);
            kmtExerciseQuestion.setQuestionText(request.getQuestionText());
        } else {
            kmtExerciseQuestion.setAnswerJson(request.getAnswerJson());
        }
        kmtExerciseQuestionService.save(kmtExerciseQuestion);

        responseEntity.success("修改成功");
        return responseEntity;
    }

    @Override
    public ResponseEntity questionRollback(String userId, QuestionRollbackRequest request) throws CommonException {
        List<String> questionIdList = request.getQuestionIds();
        ResponseEntity responseEntity = new ResponseEntity();
        if (StringUtils.isBlank(request.getReason())){
            responseEntity.failure(ResponseConstant.CODE_000, "请输入打回理由");
            return responseEntity;
        } else if (request.getReason().length() > 100){
            responseEntity.failure(ResponseConstant.CODE_000, "打回理由过长，请精简");
            return responseEntity;
        }
        List<KmtExerciseQuestion> kmtExerciseQuestions = kmtExerciseMapperService.findKmtExerciseQuestionsByIdIn(questionIdList);
        if (CollectionUtils.isNotEmpty(kmtExerciseQuestions)){
            this.appendQuestionDataFromJSONFile(kmtExerciseQuestions);
        }

        if (!isAllQuestionsCaRollback(kmtExerciseQuestions, request.getDealType())){
            responseEntity.failure(ResponseConstant.CODE_000, "选中了不能打回的题目， 请检查题目状态");
            return responseEntity;
        }

        if (CollectionUtils.isNotEmpty(kmtExerciseQuestions)){
            //批量也是课时的批量
            this.updateQuestionRollbackData(request, userId, kmtExerciseQuestions, false);
            this.updateEsKmtExerciseQuestionKnow(kmtExerciseQuestions);
            responseEntity.success(ResponseConstant.CODE_999, "打回成功");

            String exerciseBookId = kmtExerciseQuestions.get(0).getExerciseBookId();  //练习册id
            if (StringUtils.isNotBlank(exerciseBookId)) {
                // 异步刷新练习册加工状态和题目状态统计
                ThreadPool.getInstance().addTask(new SyncRefreshExerciseBookStatusTask(Collections.singletonList(exerciseBookId), 2));
            }
        } else {
            responseEntity.failure(ResponseConstant.CODE_000, "请选择题目");
        }

        return responseEntity;
    }

    /**
     * 题目是否可以打回
     * @param kmtExerciseQuestions
     * @param dealType
     * @return
     */
    private boolean isAllQuestionsCaRollback (List<KmtExerciseQuestion> kmtExerciseQuestions, int dealType){
        boolean result = true;
        if (CollectionUtils.isNotEmpty(kmtExerciseQuestions)) {
            for (KmtExerciseQuestion kmtExerciseQuestion : kmtExerciseQuestions){
                if (dealType == 1){
                    if (kmtExerciseQuestion.getDealStatus() == 2){
                        result = false;
                        break;
                    }
                } else if (dealType == 2){
                    if (kmtExerciseQuestion.getDealStatus() < 2){
                        result = false;
                        break;
                    }
                } else if (dealType == 3){
                    if (kmtExerciseQuestion.getDealStatus() <= 3 || kmtExerciseQuestion.getDealStatus() == 7){
                        result = false;
                        break;
                    }
                } else if (dealType == 4){
                    if (kmtExerciseQuestion.getDealStatus() <= 8){
                        result = false;
                        break;
                    }
                } else if (dealType == 5){
                    if (kmtExerciseQuestion.getDealStatus() <= 10){
                        result = false;
                        break;
                    }
                }
            }
        }
        return result;
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public ResponseEntity kmtQuestionRollback(String userId, KmtQuestionRollbackRequest request){
        ResponseEntity responseEntity = new ResponseEntity();
        if (StringUtils.isBlank(request.getReason())){
            responseEntity.failure(ResponseConstant.CODE_000, "请输入打回理由");
            return responseEntity;
        } else if (request.getReason().length() > 100){
            responseEntity.failure(ResponseConstant.CODE_000, "打回理由过长，请精简");
            return responseEntity;
        }
        List<KmtExerciseQuestion> kmtExerciseQuestions = kmtExerciseMapper.findQuestionByParentId(request.getParentIds());
        this.appendQuestionDataFromJSONFile(kmtExerciseQuestions);
        if (CollectionUtils.isNotEmpty(kmtExerciseQuestions)){
            //批量也是课时的批量
            QuestionRollbackRequest request1 = new QuestionRollbackRequest();
            request1.setDealType(request.getDealType());
            request1.setReason(request.getReason());
            this.updateQuestionRollbackData(request1, userId, kmtExerciseQuestions, true);
            this.updateEsKmtExerciseQuestionKnow(kmtExerciseQuestions);
            responseEntity.success(ResponseConstant.CODE_999, "打回成功");
        } else {
            responseEntity.failure(ResponseConstant.CODE_000, "请选择题目");
        }
        return responseEntity;
    }

    /**
     * 更新题目打回的数据
     * @param request
     * @param userId
     * @param kmtExerciseQuestions
     */
    public void updateQuestionRollbackData (QuestionRollbackRequest request, String userId,
                                            List<KmtExerciseQuestion> kmtExerciseQuestions,
                                            boolean immediate){
        KmtExerciseQuestion temp = kmtExerciseQuestions.get(0);
        int dealStatus = 0;
        switch (request.getDealType()){
            case 2: dealStatus = 1; break;
            case 1: dealStatus = 2; break;
            case 4: dealStatus = 8; break;
            case 5: dealStatus = 10; break;
            default: dealStatus = 7; break;
        }

        int fromType = 0;
        int originFromType = getFromTypeByDealStatus(temp.getBookId(), temp.getDealStatus());  //先获取没有改变deal_status前的题目在哪个角色下， 1加工，2审核，3解析加工，4解析审核
        TbLibManager manager = bookManagerService.findByUserIdAndType(userId, 18);

        for (KmtExerciseQuestion kmtExerciseQuestion : kmtExerciseQuestions) {
            if (manager == null){
                fromType = getFromTypeByDealStatus(kmtExerciseQuestion.getBookId(), kmtExerciseQuestion.getDealStatus());
            }
            kmtExerciseQuestion.setDealStatus(dealStatus);
            kmtExerciseQuestion.setRemark(request.getReason());
            kmtExerciseQuestion.setRepulseTime(new Date());
            this.saveKmtExerciseQuestionRollback(kmtExerciseQuestion, userId, fromType);
            kmtExerciseQuestionService.save(kmtExerciseQuestion);
            if (immediate){
                kmtExerciseQuestionService.save2EsImmediate(kmtExerciseQuestion);
            } else {
                kmtExerciseQuestionService.saveToEs(kmtExerciseQuestion);
            }
        }

        //如果是练习册，需要修改练习册状态
        if (StringUtils.isNotBlank(temp.getExerciseBookId())){
            KmtExerciseBook book =  kmtExerciseMapper.findExerciseBookById(temp.getExerciseBookId());
            int afterToType = getFromTypeByDealStatus(kmtExerciseQuestions.get(0).getBookId(), kmtExerciseQuestions.get(0).getDealStatus());
            this.updateRollbackKmtExerciseBookFinishStatus(kmtExerciseQuestions.size(), book, originFromType, afterToType);
        }
//        kmtExerciseQuestionService.save(kmtExerciseQuestions);
//        kmtExerciseQuestionRollbackService.save(exerciseQuestionRollbacks);
    }

    private int getFromTypeByDealStatus (String bookId, int dealStatus){
        int type = 0;
        if (StringUtil.isBlank(bookId)){
            switch (dealStatus){
                case 1: type = 5;break;
                case 3: type = 6; break;
                case 7: type = 6; break;
                default: type = 0; break;
            }
        } else {
            switch (dealStatus){
                case 1: type = 1;break;
                case 2: type = 9; break;
                case 3: type = 2; break;
                case 7: type = 2; break;
                case 5: type = 3; break;
                case 8: type = 3; break;
                case 9: type = 4; break;
                case 10: type = 4; break;
                default: type = 0; break;
            }
        }
        return type;
    }

    /**
     * 生成打回记录, 并往题目记录最新的打回人
     * @param userId
     * @return
     */
    private void saveKmtExerciseQuestionRollback (KmtExerciseQuestion kmtExerciseQuestion,  String userId, int fromType){
        KmtExerciseQuestionRollback kmtExerciseQuestionRollback = new KmtExerciseQuestionRollback();
        kmtExerciseQuestionRollback.setQuestionId(kmtExerciseQuestion.getId());
        kmtExerciseQuestionRollback.setReason(kmtExerciseQuestion.getRemark());
        kmtExerciseQuestionRollback.setType(kmtExerciseQuestion.getDealStatus());
        kmtExerciseQuestionRollback.setFromUserType(fromType);
        kmtExerciseQuestionRollback.setToUserType(getFromTypeByDealStatus(kmtExerciseQuestion.getBookId(), kmtExerciseQuestion.getDealStatus()));
        kmtExerciseQuestionRollback.setUserId(userId);
        kmtExerciseQuestion.setFromUserId(userId);
        kmtExerciseQuestionRollback.setCreateTime(new Date());
        if(StringUtils.isNotBlank(kmtExerciseQuestion.getBookId())){
            KmtExerciseBook kmtExerciseBook=kmtExerciseBookService.getById(kmtExerciseQuestion.getExerciseBookId());
            if (kmtExerciseQuestion.getDealStatus()  == 1){
                kmtExerciseQuestionRollback.setToUserId(kmtExerciseBook.getHandleUserId());
                kmtExerciseQuestion.setToUserId(kmtExerciseQuestion.getHandleUserId());
            } else if (kmtExerciseQuestion.getDealStatus()  == 7){
                kmtExerciseQuestionRollback.setToUserId(kmtExerciseBook.getAuditingUserId());
                kmtExerciseQuestion.setToUserId(kmtExerciseQuestion.getAuditingUserId());
            } else if (kmtExerciseQuestion.getDealStatus() == 8){
                kmtExerciseQuestionRollback.setToUserId(kmtExerciseBook.getAnalysisUserId());
                kmtExerciseQuestion.setToUserId(kmtExerciseQuestion.getAnalysisUserId());
            } else if (kmtExerciseQuestion.getDealStatus() == 10){
                kmtExerciseQuestionRollback.setToUserId(kmtExerciseBook.getAnalysisAuditerId());
                kmtExerciseQuestion.setToUserId(kmtExerciseQuestion.getAnalysisAuditerId());
            } else if (kmtExerciseQuestion.getDealStatus() == 2){
                kmtExerciseQuestion.setToUserId("1");
            }
        }


        kmtExerciseQuestionRollbackService.save(kmtExerciseQuestionRollback);
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public ResponseEntity publishQuestion(QuestionPublishRequest request, String userId) throws CommonException {
        ResponseEntity responseEntity = new ResponseEntity();
        responseEntity.success(ResponseConstant.CODE_999, "发布成功");
        List<KmtExerciseQuestion> kmtExerciseQuestions = kmtExerciseMapperService.findKmtExerciseQuestionsByIdIn(request.getQuestionIds());
        this.appendQuestionDataFromJSONFile(kmtExerciseQuestions);
        if (CollectionUtils.isNotEmpty(kmtExerciseQuestions)){
            String exerciseBookId = kmtExerciseQuestions.get(0).getExerciseBookId();  //练习册id
            KmtExerciseBook exerciseBook = kmtExerciseBookService.getById(exerciseBookId);
            int[] dealStatusArrays =  {3, 7, 9 ,10};  //题目发布前状态和解析发布前状态
            boolean flag = false;
            for (int i : dealStatusArrays){
                if (kmtExerciseQuestions.get(0).getDealStatus() == i){
                    flag = true;
                }
            }
            if (userId.equals(exerciseBook.getAuditingUserId()) && !flag){
                //用户是审核老师但题目不是审核中或者打回审核中
                responseEntity.failure(ResponseConstant.CODE_000, "题目非待发布状态，请刷新题目");
                return responseEntity;
            }
            this.updatePublishQuestionData(kmtExerciseQuestions, false);
            this.updateEsKmtExerciseQuestionKnow(kmtExerciseQuestions);

            if (StringUtils.isNotBlank(exerciseBookId)) {
                // 异步刷新练习册加工状态和题目状态统计
                ThreadPool.getInstance().addTask(new SyncRefreshExerciseBookStatusTask(Collections.singletonList(exerciseBookId), 2));
            }
        }
        return responseEntity;
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public ResponseEntity publishKmtQuestion(KmtQuestionPublishRequest request, String userId){
        ResponseEntity responseEntity = new ResponseEntity();
        List<KmtExerciseQuestion> kmtExerciseQuestions = kmtExerciseMapper.findQuestionByParentId(request.getParentIds());
        this.appendQuestionDataFromJSONFile(kmtExerciseQuestions);
        if (CollectionUtils.isNotEmpty(kmtExerciseQuestions)){
            this.updatePublishQuestionData(kmtExerciseQuestions, true);
            this.updateEsKmtExerciseQuestionKnow(kmtExerciseQuestions);
        }
        responseEntity.success(ResponseConstant.CODE_999, "发布成功");
        return responseEntity;
    }


    /**
     * 更新发布题目的数据
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void updatePublishQuestionData (List<KmtExerciseQuestion> kmtExerciseQuestions, boolean immediate){
        KmtExerciseQuestion firstQuestion = kmtExerciseQuestions.get(0);
        KmtExerciseBook book = null;
        if (StringUtils.isNotBlank(firstQuestion.getExerciseBookId())){
            book = kmtExerciseMapper.findExerciseBookById(firstQuestion.getExerciseBookId());
            if (firstQuestion.getDealStatus() == 0 || firstQuestion.getDealStatus() == 1){
                this.updateKmtExerciseBookFinishStatus(kmtExerciseQuestions.size(), book, 0);
            } else if (firstQuestion.getDealStatus() == 3 || firstQuestion.getDealStatus() == 7){
                this.updateKmtExerciseBookFinishStatus(kmtExerciseQuestions.size(), book, 1);
            } else if (firstQuestion.getDealStatus() == 5 || firstQuestion.getDealStatus() == 8){
                this.updateKmtExerciseBookFinishStatus(kmtExerciseQuestions.size(), book, 4);
            } else if (firstQuestion.getDealStatus() == 9 || firstQuestion.getDealStatus() == 10){
                this.updateKmtExerciseBookFinishStatus(kmtExerciseQuestions.size(), book, 5);
            }
        }

        for (KmtExerciseQuestion kmtExerciseQuestion : kmtExerciseQuestions) {
            if (StringUtils.isNotBlank(firstQuestion.getExerciseBookId())){
                kmtExerciseQuestion.setHandleUserId(book.getHandleUserId());
                kmtExerciseQuestion.setAuditingUserId(book.getAuditingUserId());
                kmtExerciseQuestion.setAnalysisUserId(book.getAnalysisUserId());
                kmtExerciseQuestion.setAnalysisAuditerId(book.getAnalysisAuditerId());
            }
            if (kmtExerciseQuestion == null) {
                logger.warn(String.format("题目不存在（id=%s）", kmtExerciseQuestion.getId()));
                throw new CommonException("题目不存在");
            }
            if (kmtExerciseQuestion.getDealStatus() == 3 || kmtExerciseQuestion.getDealStatus() == 7 || kmtExerciseQuestion.getDealStatus() == 4){
                //kmt的题目发布把题目字段替换成图片
                if (StringUtils.isBlank(kmtExerciseQuestion.getBookId())){
                    if (StringUtil.isBlank(kmtExerciseQuestion.getImage())) {
                        throw new CommonException("请先生成图片再发布");
                    }
                    kmtExerciseQuestion.setQuestion("<img src=\"" + PropertiesUtil.getValue("STATIC_FILE_URL") + kmtExerciseQuestion.getImage() + "\"/>");
                    kmtExerciseQuestion.setDealStatus(4);
                } else {
                    kmtExerciseQuestion.setDealStatus(5);
                }
                kmtExerciseQuestion.setPublishTime(new Date());
            } else if (kmtExerciseQuestion.getDealStatus() == 0 || kmtExerciseQuestion.getDealStatus() == 1){
                kmtExerciseQuestion.setDealStatus(3);
            } else if ((kmtExerciseQuestion.getDealStatus() == 10 || kmtExerciseQuestion.getDealStatus() == 9)
                    && StringUtils.isNotBlank(kmtExerciseQuestion.getExerciseBookId())){
                kmtExerciseQuestion.setDealStatus(11);
                kmtExerciseQuestion.setAnalysisSubmitTime(new Date());
            } else if (kmtExerciseQuestion.getDealStatus() == 5 || kmtExerciseQuestion.getDealStatus() == 8
                    && StringUtils.isNotBlank(kmtExerciseQuestion.getExerciseBookId())) {
                kmtExerciseQuestion.setDealStatus(9);
            } else {
                logger.warn("题目id={}不是可发布状态，不能发布", kmtExerciseQuestion.getId());
            }
            kmtExerciseQuestionService.save(kmtExerciseQuestion);
            if (immediate){
                kmtExerciseQuestionService.save2EsImmediate(kmtExerciseQuestion);
            } else {
                kmtExerciseQuestionService.saveToEs(kmtExerciseQuestion);
            }
        }
    }

    @Override
    public void submit2Auditing(List<String> questionIdList, List<HowDetailPointsRequest> detailIds, String userId) throws CommonException {
        Date now = new Date();
        List<KmtExerciseQuestionKnow> kmtExerciseQuestionKnowList = new LinkedList<>();
        List<KmtExerciseQuestion> kmtExerciseQuestionList = new LinkedList<>();

        questionIdList.forEach(questionId -> {
            KmtExerciseQuestion kmtExerciseQuestion = kmtExerciseQuestionService.getById(questionId);

            if (kmtExerciseQuestion == null) {
                logger.warn(String.format("题目不存在(id=%s)", questionId));
                throw new CommonException("题目不存在");
            }

            String handleUserId = kmtExerciseQuestion.getHandleUserId();
            if (!userId.equals(handleUserId) && !userId.equals(kmtExerciseQuestion.getAuditingUserId())) {
                logger.warn(String.format("题目：id=%s，题目加工人：userId=%s，操作人：userId=%s", questionId, handleUserId, userId));
                throw new CommonException("无权限操作");
            }

            List<KmtExerciseQuestionKnow> origin = kmtExerciseQuestionKnowService.findByQuestionId(questionId);
            if (origin != null) {
                for (KmtExerciseQuestionKnow know : origin){
                    kmtExerciseQuestionKnowService.delete(know.getId());
                }
            }
            detailIds.forEach(detail -> {
                if (detail.getPointIds() != null && detail.getPointIds().size() > 0){
                    //有考点的情况
                    detail.getPointIds().forEach(pointId -> {
                        //添加题目与考点的关联记录
                        KmtExerciseQuestionKnow  kmtExerciseQuestionKnow = new KmtExerciseQuestionKnow();
                        kmtExerciseQuestionKnow.setQuestionId(questionId);
                        kmtExerciseQuestionKnow.setHowDetailsId(detail.getDetailId());
                        kmtExerciseQuestionKnow.setHowDetailsKdId(pointId);
                        kmtExerciseQuestionKnow.setLoaded(0);
                        kmtExerciseQuestionKnow.setUpdateTime(now);
                        kmtExerciseQuestionKnow.setCreateTime(now);
                        kmtExerciseQuestionKnowList.add(kmtExerciseQuestionKnow);

                    });
                } else {
                    //没有考点的情况只记录知识点
                    KmtExerciseQuestionKnow  kmtExerciseQuestionKnow = new KmtExerciseQuestionKnow();
                    kmtExerciseQuestionKnow.setQuestionId(questionId);
                    kmtExerciseQuestionKnow.setHowDetailsId(detail.getDetailId());
                    kmtExerciseQuestionKnow.setLoaded(0);
                    kmtExerciseQuestionKnow.setUpdateTime(now);
                    kmtExerciseQuestionKnow.setCreateTime(now);
                    kmtExerciseQuestionKnowList.add(kmtExerciseQuestionKnow);
                }

            });

            //更新题目信息
            kmtExerciseQuestion.setDealStatus(3);
            kmtExerciseQuestionList.add(kmtExerciseQuestion);
        });
        if (detailIds ==null || detailIds.size() ==0){
            logger.warn("题目没有关联知识点，题目id={}", JSON.toJSON(questionIdList));
        }
        kmtExerciseQuestionKnowService.save(kmtExerciseQuestionKnowList);
        kmtExerciseQuestionService.save(kmtExerciseQuestionList);
    }

    @Override
    public ResponseEntity submit2AuditingV1(AuditingV1Request request, String userId) {
        long start = System.currentTimeMillis();
        ResponseEntity responseEntity = new ResponseEntity();

        // 答案校对修改提交
        boolean proofreadAnswerSubmit = false;
        if (Objects.equals(request.getType(), 6)) {
            proofreadAnswerSubmit = true;
        }

        TbLibManager manager = bookManagerService.findByUserIdAndType(userId, 18);
        if (manager != null) {
            //管理员把状态设置为3，不改任何状态
            request.setType(3);
        }

        responseEntity.success(ResponseConstant.CODE_999, "成功");
        if (CollectionUtils.isNotEmpty(request.getQuestions())) {
            List<String> questionIds = request.getQuestions().stream().map(QuestionUpdateRequest::getQuestionId).collect(Collectors.toList());
            List<KmtExerciseQuestion> questions = kmtExerciseMapperService.findKmtExerciseQuestionsByIdIn(questionIds);
            if (request.getType() == 4 && questions.stream().anyMatch(q -> q.getDealStatus() == 11)) {
                responseEntity.failure(ResponseConstant.CODE_000, "题目解析已发布，不能提交审核");
                return responseEntity;
            } else if (request.getType() == 0 && questions.stream().anyMatch(q -> q.getDealStatus() == 4 || q.getDealStatus() == 5 || q.getDealStatus() > 7)) {
                responseEntity.failure(ResponseConstant.CODE_000, "题目加工已发布，不能提交审核");
                return responseEntity;
            }
            this.appendQuestionDataFromJSONFile(questions);

            String exerciseBookId = questions.get(0).getExerciseBookId();
            KmtExerciseBook book = kmtExerciseMapper.findExerciseBookById(exerciseBookId);
            //判断练习册的状态是否更新book表字段
            this.updateKmtExerciseBookFinishStatus(questionIds.size(), book, request.getType());
            if (request.getType() == 4 || request.getType() == 5) {
                for (KmtExerciseQuestion question : questions) {
                    question.setQuestionPath(this.getQuestionJSONPath(book, question.getId()));
                    for (QuestionUpdateRequest updateRequest : request.getQuestions()) {
                        if (question.getId().equals(updateRequest.getQuestionId())) {
                            question.setAnalysis(updateRequest.getQuestionAnalysis());
                            question.setAnalysisJson(updateRequest.getAnalysisJson());
                            if (request.getType() == 4) {
                                if (question.getDealStatus() == 5 || question.getDealStatus() == 8) {
                                    question.setAnalysisHandlerSubmitTime(new Date());
                                }
                                question.setDealStatus(9);
                            } else {
                                question.setDealStatus(11);
                                question.setAnalysisSubmitTime(new Date());
                            }
                        }
                    }
                }
            } else {
                //循坏题目
                for (KmtExerciseQuestion question : questions) {
                    question.setQuestionPath(this.getQuestionJSONPath(book, question.getId()));
                    for (QuestionUpdateRequest updateRequest : request.getQuestions()) {
                        if (question.getId().equals(updateRequest.getQuestionId())) {
                            question.setQuestionText(updateRequest.getQuestionText());
                            question.setOptionAnswer(updateRequest.getAnswer());
                            question.setAnswerJson(updateRequest.getAnswerJson());
                            question.setAnalysis(updateRequest.getQuestionAnalysis());
                            question.setAnalysisJson(updateRequest.getAnalysisJson());

                            if (CollectionUtils.isNotEmpty(updateRequest.getQuestionTypes())) {
                                question.setQuestionType(updateRequest.getQuestionTypes().get(0).getType());
                            }

                            if (CollectionUtils.isNotEmpty(updateRequest.getDifficultyLevels())) {
                                question.setDifficultyLevel(updateRequest.getDifficultyLevels().get(0).getType());
                            }

                            if (CollectionUtils.isNotEmpty(updateRequest.getRealExamTypes())) {
                                List<Integer> types = updateRequest.getRealExamTypes().stream().map(KnowledgeBaseDto::getType).collect(Collectors.toList());
                                question.setRealExamType(StringUtils.join(types, ","));
                            }

                            if (CollectionUtils.isNotEmpty(updateRequest.getTrainingSkills())) {
                                List<String> names = updateRequest.getTrainingSkills().stream().map(KnowledgeBaseDto::getName).collect(Collectors.toList());
                                question.setTrainingSkill(StringUtils.join(names, ","));
                            }

                            if (StringUtils.isNotBlank(updateRequest.getQuestionText()) && !updateRequest.getQuestionText().equals(question.getQuestionText())) {
                                question.setUpdateType(1);
                            }
                            if (StringUtils.isNotBlank(updateRequest.getQuestionAnalysis())) {
                                question.setAnalysis(updateRequest.getQuestionAnalysis());
                                question.setAnalysisSubmitType(1);
                                question.setAnalysisSubmitTime(new Date());
                            }
                            this.deleteQuestionKnowByQuestionId(updateRequest.getQuestionId());
                            this.updateKmtQuestionKnow(updateRequest.getKnowledges(), question);
                        }
                    }
                    //发布改为4, 提交审核改为3
                    if (request.getType() == 1) {
                        question.setPublishTime(new Date());
                        question.setDealStatus(5);
                    } else if (request.getType() == 0) {
                        if (question.getDealStatus() == 0 || question.getDealStatus() == 1) {
                            question.setHandlerSubmitTime(new Date());
                        }
                        question.setDealStatus(3);
                    }

                    if (proofreadAnswerSubmit) {
                        // 修改练习册题目答案校对状态
                        question.setProofreadStatus(ProofreadStatusEnum.ManagerModified.getCode());
                    }
                }

                if (proofreadAnswerSubmit) {
                    // 如果已经没有需要修改答案的题目，则修改练习册的校对状态为已修改
                    int count = kmtExerciseMapper.countAnswerWrongQuestion(exerciseBookId, new HashSet<>(questionIds));
                    if (count < 1) {
                        kmtExerciseMapper.updateKmtExerciseBookProofreadStatus(exerciseBookId, ProofreadStatusEnum.ManagerModified.getCode());
                    }
                }
            }
            this.saveQuestionData2JSONFile(questions);
            kmtExerciseQuestionService.save(questions);
            for (KmtExerciseQuestion kmtExerciseQuestion : questions) {
                kmtExerciseQuestion.setHandleUserId(book.getHandleUserId());
                kmtExerciseQuestion.setAuditingUserId(book.getAuditingUserId());
                kmtExerciseQuestion.setAnalysisUserId(book.getAnalysisUserId());
                kmtExerciseQuestion.setAnalysisAuditerId(book.getAnalysisAuditerId());
                kmtExerciseQuestion.setAnswerCorrecterId(book.getAnswerCorrecterId());
                kmtExerciseQuestionService.saveToEs(kmtExerciseQuestion);
            }

            if (StringUtils.isNotBlank(exerciseBookId)) {
                // 异步刷新练习册加工状态和题目状态统计
                ThreadPool.getInstance().addTask(new SyncRefreshExerciseBookStatusTask(Collections.singletonList(exerciseBookId), 2));
            }
        }

        long end = System.currentTimeMillis();
        logger.error("submit2AuditingV1方法耗时:" + (end - start) + "ms");

        return responseEntity;
    }

    /**
     * 提交审核更新为未加工，未审核
     * @param questionCount
     * @param exerciseBook
     * @param dealType
     */
    private void updateKmtExerciseBookFinishStatus (int questionCount, KmtExerciseBook exerciseBook, int dealType){
        int count = 0;
        if (dealType == 0){
            //题目加工
            if (exerciseBook.getHadHandle() == 0){
                count = kmtExerciseMapper.countUnFinishQuestionsByExerciseBookId(exerciseBook.getId(), 1);
                if (count <= questionCount){
                    exerciseBook.setHadHandle(1);
                }
            }
            if (exerciseBook.getHadHandle() == 1 && StringUtil.isNotBlank(exerciseBook.getAuditingUserId())) {
                //加工完了通知加工审核老师
                this.push2ExerciseTeacher(exerciseBook.getAuditingUserId(),  exerciseBook, 2);
            }
            exerciseBook.setHadAuditing(0);
        } else if (dealType == 1) {
            //题目发布
            if (exerciseBook.getHadAuditing() == 0){
                count = kmtExerciseMapper.countUnFinishQuestionsByExerciseBookId(exerciseBook.getId(), 2);
                if (count <= questionCount){
                    exerciseBook.setHadAuditing(1);
                }
            }
            if (exerciseBook.getHadHandle() == 1 && exerciseBook.getHadAuditing() == 1){
                //加工完了通知加工审核老师
                exerciseBook.setProgress("已发布");
                if (StringUtil.isNotBlank(exerciseBook.getAnalysisUserId())){
                    this.push2ExerciseTeacher(exerciseBook.getAnalysisUserId(),exerciseBook, 3);
                }
            }
            exerciseBook.setAnalysisHandled(0);
        } else if (dealType == 4){
            //题目解析加工
            if (exerciseBook.getAnalysisHandled() == 0){
                count = kmtExerciseMapper.countUnFinishQuestionsByExerciseBookId(exerciseBook.getId(), 3);
                if (count <= questionCount){
                    exerciseBook.setAnalysisHandled(1);
                }
            }

            if (exerciseBook.getHadHandle() == 1 && exerciseBook.getHadAuditing() == 1
                    && exerciseBook.getAnalysisHandled() == 1 && StringUtil.isNotBlank(exerciseBook.getAnalysisAuditerId())){
                //加工完了通知加工审核老师
                this.push2ExerciseTeacher(exerciseBook.getAnalysisAuditerId(), exerciseBook, 4);
            }
            exerciseBook.setAnalysisAudited(0);
        } else if (dealType == 5 && exerciseBook.getAnalysisAudited() == 0){
            //题目解析发布
            count = kmtExerciseMapper.countUnFinishQuestionsByExerciseBookId(exerciseBook.getId(), 4);
            if (count <= questionCount){
                exerciseBook.setAnalysisAudited(1);
            }
        }
        kmtExerciseBookService.save(exerciseBook);
    }

    /**
     * 提交审核更新为未加工，未审核
     * @param questionCount
     * @param exerciseBook
     * @param fromType
     * @param toType
     */
    private void updateRollbackKmtExerciseBookFinishStatus (int questionCount, KmtExerciseBook exerciseBook, int fromType, int toType){
        int count = 0;
        //题目加工
        if (! this.isHandled(exerciseBook, fromType)){
            count = kmtExerciseMapper.countUnFinishQuestionsByExerciseBookId(exerciseBook.getId(), fromType);
            if (count <= questionCount){
                this.setExerciseAuthField(exerciseBook, fromType, 1);
            }
        }
        if (isAllHandled(exerciseBook, fromType) && fromType < 4){
            //加工完了通知加工审核老师, 解析审核提交不用推送
            this.pushNextUserMessage(this.getUserIdByFromType(exerciseBook, fromType), exerciseBook, fromType + 1);
        }

        this.setExerciseAuthField(exerciseBook, toType, 0);

        kmtExerciseBookService.save(exerciseBook);
    }

    /**
     * 是否已加工完
     * @param book
     * @param fromType
     * @return
     */
    private boolean isHandled (KmtExerciseBook book, int fromType){
        boolean success  = true;
        if (fromType == 1 && book.getHadHandle() == 0){
            success = false;
        } else if (fromType == 2 && book.getHadAuditing() == 0){
            success = false;
        } else if (fromType == 3 && book.getAnalysisHandled() == 0){
            success = false;
        } else if (fromType == 4 && book.getAnalysisAudited() == 0){
            success = false;
        }
        return success;
    }

    /**
     * 是否全部加工完，包括题目在上个角色那里
     * @param book
     * @param fromType
     * @return
     */
    private boolean isAllHandled (KmtExerciseBook book, int fromType){
        boolean success  = false;
        if (fromType == 1 && book.getHadHandle() == 1){
            success = true;
        } else if (fromType == 2 && book.getHadHandle() == 1 && book.getHadAuditing() == 1){
            success = true;
        } else if (fromType == 3 && book.getHadHandle() == 1 && book.getHadAuditing() == 1 && book.getAnalysisHandled() == 1){
            success = true;
        } else if (fromType == 4 && book.getHadHandle() == 1 && book.getHadAuditing() == 1
                && book.getAnalysisHandled() == 1 && book.getAnalysisAudited() == 1){
            success = true;
        }
        return success;
    }

    /**
     * 设置类型
     * @param book
     * @param fromType
     * @param flag
     */
    private void setExerciseAuthField (KmtExerciseBook book, int fromType, int flag){
        switch (fromType){
            case 1: book.setHadHandle(flag);break;
            case 2: book.setHadAuditing(flag);break;
            case 3: book.setAnalysisHandled(flag);break;
            case 4: book.setAnalysisAudited(flag);break;
            default:break;
        }
    }

    /**
     * 根据类型获取用户id
     * @param book
     * @param fromType
     * @return
     */
    private String getUserIdByFromType (KmtExerciseBook book, int fromType){
        String result = null;
        switch (fromType){
            case 1: result = book.getHandleUserId();break;
            case 2: result = book.getAuditingUserId();break;
            case 3: result = book.getAnalysisUserId();break;
            case 4: result = book.getAnalysisAuditerId();break;
            default:break;
        }
        return result;
    }

    /**
     * 推送下个角色已完成
     * @param userId
     * @param bookName
     * @param nextType
     */
    private void pushNextUserMessage (String userId, KmtExerciseBook exerciseBook, int nextType){
        if (StringUtil.isNotBlank(userId)){
            this.push2ExerciseTeacher(userId, exerciseBook, nextType);
        }
    }

    private void push2ExerciseTeacher (String userId, KmtExerciseBook exerciseBook,int type){
        String key = "push_bookId"+exerciseBook.getId()+userId;
        if(tokenManager.exists(key)){
            return ;
        }

            Map<String, String> data = new HashMap<>();
            String template_id_short = "OPENTM206165551";
            User user = userService.getById(userId);
            if  (user != null && StringUtils.isNotEmpty(user.getAccount()) ){
                try{
                    TbLibManager libTeacher = bookManagerService.findByUserIdAndType(userId, 17);
                    if (libTeacher != null){
                        String teacherName = null;
                        teacherName = libTeacher.getName();
                        if (StringUtils.isEmpty(teacherName)){
                            teacherName = user.getName();
                        }
                        String authName =  null;
                        switch (type){
                            case 1: authName="题目加工"; break;
                            case 2: authName="审核发布"; break;
                            case 3: authName="解析加工"; break;
                            case 4: authName="解析发布"; break;
                            default: authName="加工"; break;
                        }


                        String bookType =  null;
                        switch (exerciseBook.getBookType()){
                            case 0: bookType="整本"; break;
                            case 1: bookType="上半本"; break;
                            case 2: bookType="下半本"; break;
                            case 3: bookType="不同的页码的新版练习册"; break;
                            default: bookType=""; break;
                        }

                       // 你好，你有一本 数学人教版上册四年级 整本、半本,《我爱写作业(2020)》，

                        StringBuffer sb =new StringBuffer("你好，你有一本");
                        sb.append(exerciseBook.getCourseName()).append(exerciseBook.getVersionName()).append(exerciseBook.getSemester()==1?"上册":"下册");
                        sb.append(exerciseBook.getGrade()).append(bookType).append("《").append(exerciseBook.getBookName()).append("》,");
                        sb.append(authName+"请在规定时间内完成");
                        data.put("first", sb.toString());
                        data.put("keyword1", teacherName);
                        data.put("keyword2", DateUtil.format_yyyyMMddHHmmss(new Date()));
                        data.put("remark", "请及时登录处理，如有疑问请及时联系相关负责老师。");
                        SendTemplateShort sendTemplateShort = new SendTemplateShort(user.getAccount(), template_id_short, null, data);
                        pushTemplateService.saveAndSendPushWxTemplate(sendTemplateShort);
                        tokenManager.setString(key,authName,12*60*60);
                    } else {
                        logger.error("没有老师角色" + userId);
                    }
                } catch (Exception e){
                    logger.error("推送练习册老师失败：", e);
                }
            }
    }


    @Override
    public void distributeQuestions(QuestionDistributeRequest request) {
        List<KmtExerciseQuestion> kmtExerciseQuestionList;
        List<KmtExerciseBookCourse> bookCourseList;
        if (StringUtils.isNotBlank(request.getPeriodId())) {
            kmtExerciseQuestionList = kmtExerciseQuestionService.findByBookCourseId(request.getPeriodId());
            bookCourseList = new ArrayList<>();
            bookCourseList.add(kmtExerciseBookCourseService.getById(request.getPeriodId()));
        } else if (StringUtils.isNotBlank(request.getUnitId())) {
            kmtExerciseQuestionList = kmtExerciseQuestionService.findByUnitId(request.getUnitId());
            bookCourseList = kmtExerciseBookCourseService.findByUnitId(request.getUnitId());
        } else {
            kmtExerciseQuestionList = kmtExerciseQuestionService.findByBookId(request.getBookId());
            bookCourseList = kmtExerciseBookCourseService.findByBookId(request.getBookId());
        }

        kmtExerciseQuestionList.forEach(kmtExerciseQuestion -> {
            if (request.getDealType() == 1) {//分配加工员
                kmtExerciseQuestion.setHandleUserId(request.getUserId());
            } else {//dealType=2 分配审核员
                kmtExerciseQuestion.setAuditingUserId(request.getUserId());
            }
        });

        bookCourseList.forEach(kmtExerciseBookCourse -> {
            if (request.getDealType() == 1){
                kmtExerciseBookCourse.setHandleUserId(request.getUserId());
            } else if (request.getDealType() == 2){
                kmtExerciseBookCourse.setAuditingUserId(request.getUserId());
            }
        });

        kmtExerciseQuestionService.save(kmtExerciseQuestionList);
        kmtExerciseBookCourseService.save(bookCourseList);
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<ExerciseBookCourseDTO> getBookExerciseList(QuestionDistributeRequest request) {
        List<ExerciseBookCourseDTO> result = new ArrayList<>();
        if (StringUtils.isNotBlank(request.getBookId())){
            result = kmtExerciseBookCourseService.getBookExerciseList(request);
        }
        return result;
    }

    @Override
    public ResponseEntity submitKmtQuestions2Auditing(AuditingRequest request, String userId) {
        ResponseEntity responseEntity = new ResponseEntity();
        if (CollectionUtils.isEmpty(request.getList())){
            responseEntity.success(ResponseConstant.CODE_999, "没有选择题目");
        } else {
            int[] types = {17, 18};
            TbLibManager manager = bookManagerService.findTopByUserIdAndTypeIn (userId, types);
            if (manager != null && manager.getType() == 18){
                request.setType(3);
            }
            for (AuditingBigQuestionRequest bigQuestionRequest : request.getList()){
                //只有管理员和题目录入老师能录入题目, isNewAdd 并且 （deal_type =3 或者 authority 有7）,则有录入权限
                boolean  isNewAdd = isAllQuestionNoId(bigQuestionRequest);
                if (isNewAdd && (request.getType() != 3 && StringUtil.isNotBlank(manager.getAuthority()) && manager.getAuthority().indexOf("7") == -1)){
                    responseEntity.failure(ResponseConstant.CODE_000,  "没有录入权限");
                    return responseEntity;
                }
                if (CollectionUtils.isNotEmpty(bigQuestionRequest.getQuestions())) {
                    //如果有大小题的情况，需要获取第一道题的题目id作为父id和科目
                    String[] conciseIdAndSubject = this.getDetailSortId(bigQuestionRequest);
                    QuestionUpdateRequest questionTmp;
                    if ((isNewAdd && StringUtil.isBlank(conciseIdAndSubject[0])) || (request.getType() == 1 && StringUtil.isBlank(conciseIdAndSubject[0]))){
                        responseEntity.failure(ResponseConstant.CODE_000, "必须选择知识点");
                        break;
                    }
                    if  (bigQuestionRequest.getQuestions().size() == 1){
                        //如果是单独一道题，不是大小题一起提交的话
                        questionTmp = bigQuestionRequest.getQuestions().get(0);
                        questionTmp.setSubject(StringUtil.isBlank(conciseIdAndSubject[1]) ? questionTmp.getSubject() : conciseIdAndSubject[1]);
                        submitOneQuestion(bigQuestionRequest.getQuestions().get(0), request.getType(), conciseIdAndSubject[0], userId);
                    } else {
                        //大小题
                        questionTmp = bigQuestionRequest.getQuestions().get(0);
                        questionTmp.setSubject(StringUtil.isBlank(conciseIdAndSubject[1]) ? questionTmp.getSubject() : conciseIdAndSubject[1]);
                        KmtExerciseQuestion parentQuestion = updateBigQuestion(questionTmp, request.getType(), conciseIdAndSubject[0], userId, isNewAdd);
                        //处理小题的情况
                        for (int i = 1; i < bigQuestionRequest.getQuestions().size(); i++) {
                            questionTmp = bigQuestionRequest.getQuestions().get(i);
                            questionTmp.setSubject(StringUtil.isBlank(conciseIdAndSubject[1]) ? questionTmp.getSubject() : conciseIdAndSubject[1]);
                            this.submitSmallQuestions2Auditing(questionTmp,
                                    conciseIdAndSubject[0], userId, request.getType(), parentQuestion, i, isNewAdd);
                        }
                    }
                    responseEntity.success(ResponseConstant.CODE_999, "提交成功");
                } else {
                    responseEntity.success(ResponseConstant.CODE_999, "成功");
                }
            }
        }
        return responseEntity;
    }

    /**
     * 是否所有题目都没有题目id,没有表示是新录入的题
     * @param bigQuestionRequest
     * @return
     */
    private boolean isAllQuestionNoId (AuditingBigQuestionRequest bigQuestionRequest){
        boolean result = true;
        if (CollectionUtils.isNotEmpty(bigQuestionRequest.getQuestions())) {
            for (int i = 0; i < bigQuestionRequest.getQuestions().size(); i++) {
                if (StringUtils.isNotBlank(bigQuestionRequest.getQuestions().get(i).getQuestionId())){
                    return false;
                }
            }
        }
        return result;
    }

    /**
     * 提交审核的是单独一道题
     */
    private void submitOneQuestion (QuestionUpdateRequest request, int type,
                                    String conciseId, String userId){
        KmtExerciseQuestion question;
        if (StringUtils.isNotEmpty(request.getQuestionId())){
            question = updateExistQuestion(request, type, conciseId);
            this.deleteQuestionKnowByQuestionId(request.getQuestionId());
        } else {
            question = new KmtExerciseQuestion();
            question.setParentId("");
            question.setHandleUserId(userId);
            TbLibManager manager = bookManagerService.findOneManagerBySubject(StringUtils.isNotEmpty(request.getSubject()) ? request.getSubject() : this.getDetailSortCourseName(conciseId));
            if (manager != null){
                question.setAuditingUserId(manager.getUserId());
            }
            question.setCreateTime(new Date());
            question.setUpdateType(4); //单题的新增就是录入
            question.setConciseBakId(conciseId);
            question = updateCommonQuestion(request, type, conciseId, new Date(), question, true);
        }
        this.updateKmtQuestionKnow(request.getKnowledges(), question);
    }

    /**
     * 获取题目中的一个知识点的sortId作为整个大小题的conciseId， 可以通过这个id查询题目的年级科目版本上下册
     * @param request
     * @return
     */
    private String[] getDetailSortId (AuditingBigQuestionRequest request){
        String[] result = new String[2];
        for (QuestionUpdateRequest questionUpdateRequest: request.getQuestions()){
            if (CollectionUtils.isNotEmpty(questionUpdateRequest.getKnowledges())){
                result[0] = questionUpdateRequest.getKnowledges().get(0).getId();
                result[1] = StringUtils.isNotEmpty(questionUpdateRequest.getSubject()) ? questionUpdateRequest.getSubject() : this.getDetailSortCourseName(result[0]);
                break;
            }
        }
        return result;
    }

    /**
     * 获取题目的科目
     * @param id
     * @return
     */
    private String getDetailSortCourseName (String id){
        String courseName = "";
        if (StringUtils.isNotEmpty(id)){
            ZuoybKnowHowDetailsSort sort = zuoybKnowHowDetailsSortService.getById(id);
            if (sort != null){
                courseName = sort.getCourseName();
            }
        }
        return courseName;
    }

    /**
     * 单独提交一个题目
     * @param updateRequest
     * @param type
     * @param parentQuestion
     * @param num 排序字段
     * @param isNewAdd 是否是新录入的题
     */
    private KmtExerciseQuestion submitSmallQuestions2Auditing (QuestionUpdateRequest updateRequest,
                                                               String conciseId, String userId,
                                                               int type, KmtExerciseQuestion parentQuestion, int num,
                                                               boolean isNewAdd){
        KmtExerciseQuestion question = null;
        if (StringUtils.isBlank(updateRequest.getQuestionId())){
            question = new KmtExerciseQuestion();
            question.setCreateTime(new Date());
            question.setDealStatus(parentQuestion.getDealStatus());
            if (isNewAdd) {
                question.setUpdateType(4);
                question.setConciseBakId(parentQuestion.getConciseBakId());
            } else {
                question.setUpdateType(3);
            }
            if (StringUtils.isBlank(parentQuestion.getHandleUserId()) && StringUtils.isBlank(parentQuestion.getAuditingUserId())){
                List<Map> list = exerciseQuestionSearchService.findHandleUserIdAndAuditingUserId(parentQuestion.getId());
                if (list != null && list.size() > 0){
                    question.setHandleUserId((String)list.get(0).get("handleUserId"));
                    question.setAuditingUserId((String)list.get(0).get("auditingUserId"));
                } else {
                    question.setHandleUserId(userId);
                    TbLibManager manager = bookManagerService.findOneManagerBySubject(StringUtils.isNotEmpty(updateRequest.getSubject()) ? updateRequest.getSubject() : this.getDetailSortCourseName(conciseId));
                    if (manager != null){
                        question.setAuditingUserId(manager.getUserId());
                    }
                }
            } else {
                question.setHandleUserId(parentQuestion.getHandleUserId());
                question.setAuditingUserId(parentQuestion.getAuditingUserId());
            }
        } else {
            isNewAdd =false;
            question = kmtExerciseQuestionService.getById(updateRequest.getQuestionId());
            this.deleteQuestionKnowByQuestionId(updateRequest.getQuestionId());
        }
        question.setParentId(parentQuestion.getId());
        question.setQuestionClassType(2);
        question.setNum(num);
        question.setIsCommonFlag(parentQuestion.getIsCommonFlag());
        question.setConciseBakId(parentQuestion.getConciseBakId());
        question = this.updateCommonQuestion(updateRequest, type, conciseId, parentQuestion.getHandlerSubmitTime(),question, isNewAdd);
        this.updateKmtQuestionKnow(updateRequest.getKnowledges(), question);
        return question;
    }

    /**
     * 删除旧关联的知识点
     * @param questionId
     */
    private void deleteQuestionKnowByQuestionId (String questionId){
        List<KmtExerciseQuestionKnow> questionKnowsTmp = kmtExerciseQuestionKnowService.findByQuestionId(questionId);
        //先把之前提交的知识点删除
        if (CollectionUtils.isNotEmpty(questionKnowsTmp)){
            for (KmtExerciseQuestionKnow questionKnow : questionKnowsTmp){
                kmtExerciseQuestionKnowService.delete(questionKnow);
            }
            this.deleteEsKmtExerciseQuestionKnow(questionKnowsTmp);
        }
    }

    /**
     * kmt题目提交更新已存在的题目
     * @param updateRequest
     * @param type
     */
    private KmtExerciseQuestion updateExistQuestion (QuestionUpdateRequest updateRequest, int type, String conciseId){
        KmtExerciseQuestion question = null;
        if  (StringUtils.isNotEmpty(updateRequest.getQuestionId())){
            question = kmtExerciseQuestionService.getById(updateRequest.getQuestionId());
            question = updateCommonQuestion(updateRequest, type, conciseId, new Date(), question, false);
        }
        return question;
    }

    /**
     * 更新公共内容
     * @param updateRequest
     * @param type
     * @param conciseId
     * @param handleSubmitTime
     * @param question
     * @param isNewAdd 是否是新录入的题目
     * @return
     */
    private KmtExerciseQuestion updateCommonQuestion (QuestionUpdateRequest updateRequest, int type, String conciseId,
                                                      Date handleSubmitTime, KmtExerciseQuestion question, boolean isNewAdd){
        question.setCourseName(StringUtils.isNotEmpty(updateRequest.getSubject()) ? updateRequest.getSubject() : this.getDetailSortCourseName(conciseId));
        question.setConciseId(conciseId);
        question.setQuestionText(updateRequest.getQuestionText());
        question.setAnswerJson(updateRequest.getAnswerJson());
        question.setAnalysisJson(updateRequest.getAnalysisJson());
        //如果是加工人提交要记录提交时间
        if (type == 0 && (question.getDealStatus() == null || question.getDealStatus() < 2)){
            question.setHandlerSubmitTime(handleSubmitTime);
        }
        question.setImage(updateRequest.getQuestionImage());
        //发布时把题目图片赋值给question
        if (type == 1 || (type == 3 && isNewAdd)){
            question.setQuestion("<img src=\"" + PropertiesUtil.getValue("STATIC_FILE_URL") + question.getImage() + "\"/>");
            question.setPublishTime(new Date());
            question.setDealStatus(4);
        } else if (type == 0){
            question.setDealStatus(3);
        }
        if (CollectionUtils.isNotEmpty(updateRequest.getQuestionTypes())){
            question.setQuestionType(updateRequest.getQuestionTypes().get(0).getType());
        }

        if (CollectionUtils.isNotEmpty(updateRequest.getDifficultyLevels())){
            question.setDifficultyLevel(updateRequest.getDifficultyLevels().get(0).getType());
        }

        if (CollectionUtils.isNotEmpty(updateRequest.getRealExamTypes())){
            List<Integer> types = updateRequest.getRealExamTypes().stream().map(KnowledgeBaseDto::getType).collect(Collectors.toList());
            question.setRealExamType(StringUtils.join(types, ","));
        }

        if (CollectionUtils.isNotEmpty(updateRequest.getTrainingSkills())){
            List<String> names = updateRequest.getTrainingSkills().stream().map(KnowledgeBaseDto::getName).collect(Collectors.toList());
            question.setTrainingSkill(StringUtils.join(names, ","));
        }
        if (StringUtils.isNotBlank(updateRequest.getQuestionAnalysis())){
            question.setAnalysis(updateRequest.getQuestionAnalysis());
            question.setAnalysisSubmitType(1);
            question.setAnalysisSubmitTime(new Date());
        }
        question.setQuestionPath(this.getKmtQuestionJSONPath(question.getCourseName(), question.getId()));
        this.saveQuestionData2JSONFile(question.getQuestionPath(), question);
        question = kmtExerciseQuestionService.save(question);
        kmtExerciseQuestionService.save2EsImmediate(question);
        return  question;
    }

    /**
     * 更新大标题
     * @param request
     * @return
     */
    private KmtExerciseQuestion updateBigQuestion (QuestionUpdateRequest request, int type, String conciseId, String userId, boolean isNewAdd){
        KmtExerciseQuestion question;
        if (StringUtils.isNotEmpty(request.getQuestionId())){
            question = kmtExerciseQuestionService.getById(request.getQuestionId());
            isNewAdd = false;
            this.deleteQuestionKnowByQuestionId(request.getQuestionId());
        } else {
            question = new KmtExerciseQuestion();
            question.setHandleUserId(userId);
            TbLibManager manager = bookManagerService.findOneManagerBySubject(StringUtils.isNotEmpty(request.getSubject()) ? request.getSubject() : this.getDetailSortCourseName(conciseId));
            if (manager != null){
                question.setAuditingUserId(manager.getUserId());
            }
            question.setCreateTime(new Date());
            if (isNewAdd){
                question.setUpdateType(4);
                question.setConciseBakId(conciseId);
            } else {
                question.setUpdateType(3);
            }
        }
        question.setParentId("");
        question.setQuestionClassType(1);
        question.setNum(0);
        question = updateCommonQuestion(request, type, conciseId, new Date() , question, isNewAdd);
        this.updateKmtQuestionKnow(request.getKnowledges(), question);
        return question;
    }

    /**
     * 添加题目关联的知识点 kmt_exercise_question_know， zyb_know_how_details_sort
     * @param knowledges
     * @param question
     */
    private void updateKmtQuestionKnow (List<KnowHowDetailsDTO> knowledges, KmtExerciseQuestion question){
        //知识点不为空添加知识点
        if (CollectionUtils.isNotEmpty(knowledges)){
            List<KmtExerciseQuestionKnow> questionKnows = new ArrayList<>();
            for (KnowHowDetailsDTO detail : knowledges){
                ZuoybKnowHowDetailsSort detailsSort = zuoybKnowHowDetailsSortService.getById(detail.getId());
                if (CollectionUtils.isNotEmpty(detail.getPoints())){
                    //有考点的情况
                    detail.getPoints().forEach(point -> {
                        //添加题目与考点的关联记录
                        KmtExerciseQuestionKnow  kmtExerciseQuestionKnow = new KmtExerciseQuestionKnow();
                        ZuoybKnowHowDetailsSort pointSort = zuoybKnowHowDetailsSortService.getById(point.getId());
                        kmtExerciseQuestionKnow.setQuestionId(question.getId());
                        kmtExerciseQuestionKnow.setQuestionParentId(question.getParentId());
                        kmtExerciseQuestionKnow.setHowDetailsId(detailsSort.getHowDetailsId());
                        kmtExerciseQuestionKnow.setHowDetailsKdId(pointSort.getHowDetailsKdId());
                        kmtExerciseQuestionKnow.setVersion(detailsSort.getType());
                        kmtExerciseQuestionKnow.setLoaded(0);
                        kmtExerciseQuestionKnow.setCreateTime(new Date());
                        kmtExerciseQuestionKnow.setUpdateTime(new Date());
                        kmtExerciseQuestionKnow.setHowDetailSortId(detailsSort.getId());
                        kmtExerciseQuestionKnow.setHowDetailKdSortId(pointSort.getId());
                        questionKnows.add(kmtExerciseQuestionKnow);

                    });
                } else {
                    //没有考点的情况只记录知识点
                    KmtExerciseQuestionKnow  kmtExerciseQuestionKnow = new KmtExerciseQuestionKnow();
                    kmtExerciseQuestionKnow.setQuestionId(question.getId());
                    kmtExerciseQuestionKnow.setQuestionParentId(question.getParentId());
                    kmtExerciseQuestionKnow.setHowDetailsId(detailsSort.getHowDetailsId());
                    kmtExerciseQuestionKnow.setHowDetailSortId(detailsSort.getId());
                    kmtExerciseQuestionKnow.setVersion(detailsSort.getType());
                    kmtExerciseQuestionKnow.setLoaded(0);
                    kmtExerciseQuestionKnow.setCreateTime(new Date());
                    kmtExerciseQuestionKnow.setUpdateTime(new Date());
                    questionKnows.add(kmtExerciseQuestionKnow);
                }
            }
            kmtExerciseQuestionKnowService.save(questionKnows);
            addEsKmtExerciseQuestionKnow(questionKnows, question.getId());
        }
    }

    /**
     * 删除es中的记录
     * @param questionKnows
     */
    private void deleteEsKmtExerciseQuestionKnow (List<KmtExerciseQuestionKnow> questionKnows) {
        if (CollectionUtils.isNotEmpty(questionKnows)) {
            //删除es的数据
            List<String> kmtExerciseQuestionKnowIdList = questionKnows.stream().map(KmtExerciseQuestionKnow::getId).collect(Collectors.toList());
            baseSearchService.deleteByIdList("kmt_exercise_question_know", kmtExerciseQuestionKnowIdList);
        }
    }

    /**
     * 添加es记录
     * @param questionKnows
     * @param questionId
     */
    private void addEsKmtExerciseQuestionKnow(List<KmtExerciseQuestionKnow> questionKnows, String questionId){
        if (CollectionUtils.isNotEmpty(questionKnows)) {
            //添加新数据至es
            try {
                kmtExerciseQuestionKnowService.flush();
            } catch (Exception e) {
                logger.warn("kmtExerciseQuestionKnowService.flush()异常", e);
            }
            List<Map<String, Object>> dataMapList2Es = kmtExerciseMapperService.findData2EsByQuestionList(Collections.singletonList(questionId));
            this.appendQuestionMapFromJSONFile(dataMapList2Es);
            if (CollectionUtils.isNotEmpty(dataMapList2Es)) {
                baseSearchService.insertBatch("kmt_exercise_question_know", dataMapList2Es, true);
            }
        }
    }

    @Override
    public void updateEsKmtExerciseQuestionKnow(List<KmtExerciseQuestion> questions){
        //添加新数据至es
        List<String> questionId = questions.stream().map(BaseEntity::getId).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(questionId)){
            try {
                kmtExerciseQuestionKnowService.flush();
            } catch (Exception e) {
                logger.warn("kmtExerciseQuestionKnowService.flush()异常", e);
            }
            List<Map<String, Object>> dataMapList2Es = kmtExerciseMapperService.findData2EsByQuestionList(questionId);
            this.appendQuestionMapFromJSONFile(dataMapList2Es);
            if (CollectionUtils.isNotEmpty(dataMapList2Es)) {
                baseSearchService.insertBatch("kmt_exercise_question_know", dataMapList2Es, true);
            }
        }
    }

    @Override
    public void deleteKmtQuestion(String questionId, String userId) {
        KmtExerciseQuestion kmtExerciseQuestion = kmtExerciseQuestionService.getById(questionId);
        this.appendQuestionDataFromJSONFile(Collections.singletonList(kmtExerciseQuestion));
        if (kmtExerciseQuestion != null){
            kmtExerciseQuestion.setDealStatus(6);
            kmtExerciseQuestion.setPublishTime(new Date());
            kmtExerciseQuestion.setRemark(userId);
            kmtExerciseQuestionService.save(kmtExerciseQuestion);
            kmtExerciseQuestionService.save2EsImmediate(kmtExerciseQuestion);
            //删除题目关联的知识点
            this.deleteQuestionKnowByQuestionId(questionId);
        }
    }

    @Override
    public ResponseEntity submitAnswerProofreadResult(SubmitAnswerProofreadResultReq req) {
        ResponseEntity responseEntity = new ResponseEntity();
        responseEntity.success(ResponseConstant.CODE_999, "成功");
        if (CollectionUtils.isEmpty(req.getQuestionIds())){
            return responseEntity;
        }

        List<KmtExerciseQuestion> questions = kmtExerciseMapper.findExerciseQuestionByIds(req.getQuestionIds());
        this.appendQuestionDataFromJSONFile(questions);
        if (CollectionUtils.isEmpty(questions) || !isCanUpdateProofreadResult(questions)){
            responseEntity.failure(ResponseConstant.CODE_000, "答案校对结果已锁定，请刷新题目");
        }

        String exerciseBookId = questions.get(0).getExerciseBookId();
        KmtExerciseBook exerciseBook = kmtExerciseMapper.findExerciseBookById(exerciseBookId);
        if (exerciseBook == null) {
            logger.error("练习册(id=[{}])不存在", exerciseBookId);
            return responseEntity.failure("练习册不存在");
        }

        //查询未校对题目数量, 如果只剩当前题数未校对，则该练习册可以设置为校对完成
        int uncheckCount = kmtExerciseMapper.countNotCheckAnswerCount(exerciseBookId);
        if (uncheckCount <= req.getQuestionIds().size()){
            exerciseBook.setAnswerCorrectedStatus(1);
            exerciseBook.setCheckTime(new Date());
            if (exerciseBook.getAiRollbackImport() == 1) {
                exerciseBook.setAiRollbackImport(0);
            }
            kmtExerciseBookService.save(exerciseBook);
        }

        //判断是否检查练习册校对状态，更新题目校对状态
        boolean needCheckKmtExerciseBookProofreadStatus = false;
        for (KmtExerciseQuestion kmtExerciseQuestion : questions){
            kmtExerciseQuestion.setHandleUserId(exerciseBook.getHandleUserId());
            kmtExerciseQuestion.setAuditingUserId(exerciseBook.getAuditingUserId());
            kmtExerciseQuestion.setAnalysisUserId(exerciseBook.getAnalysisUserId());
            kmtExerciseQuestion.setAnalysisAuditerId(exerciseBook.getAnalysisAuditerId());
            kmtExerciseQuestion.setAnswerCorrecterId(exerciseBook.getAnswerCorrecterId());
            if (!needCheckKmtExerciseBookProofreadStatus &&
                    Objects.equals(req.getAnswerProofreadResult(), ProofreadStatusEnum.AnswerRight.getCode()) &&
                    Objects.equals(kmtExerciseQuestion.getProofreadStatus(), ProofreadStatusEnum.AnswerWrong.getCode())) {
                needCheckKmtExerciseBookProofreadStatus = true;
            }
            kmtExerciseQuestion.setProofreadStatus(req.getAnswerProofreadResult());
        }
        kmtExerciseQuestionService.save(questions);


        if (req.getAnswerProofreadResult() == 2){
            kmtExerciseMapper.updateExerciseBookProofreadResult(2, exerciseBook.getId());
        } else if (exerciseBook.getProofreadStatus() == 0) {
            kmtExerciseMapper.updateExerciseBookProofreadResult(1, exerciseBook.getId());
        } else if (needCheckKmtExerciseBookProofreadStatus) {
            int answerWrongQuestionCount = kmtExerciseMapper.countAnswerWrongQuestion(exerciseBook.getId(), new HashSet<>(req.getQuestionIds()));
            if (answerWrongQuestionCount < 1) {
                kmtExerciseMapper.updateExerciseBookProofreadResult(1, exerciseBookId);
            }
        }
        kmtExerciseQuestionService.bulkKmtExerciseQuestions(questions);

        return responseEntity;
    }

    /**
     * 是否能更新答案校对结果
     * @param questions
     */
    private boolean isCanUpdateProofreadResult (List<KmtExerciseQuestion> questions){
        boolean result = true;
        if (CollectionUtils.isNotEmpty(questions)){
            for (KmtExerciseQuestion kmtExerciseQuestion :  questions){
                if (kmtExerciseQuestion.getDealStatus() < 4 || kmtExerciseQuestion.getDealStatus() == 7 || kmtExerciseQuestion.getProofreadStatus() == 3) {
                    result = false;
                    break;
                }
            }
        }
        return result;
    }

    @Override
    public ResponseEntity answerProofreadSubmitAnswer(AnswerProofreadSubmitAnswerRequest request) {
        ResponseEntity responseEntity = new ResponseEntity();

        // 根据id查询需要修改答案的练习册题目
        Set<String> questionIdSet = request.getAnswerList().stream()
                .map(QuestionUpdateRequest::getQuestionId)
                .collect(Collectors.toSet());
        List<KmtExerciseQuestion> kmtExerciseQuestionList =
                kmtExerciseQuestionService.findByIdIn(new ArrayList<>(questionIdSet));
        if (CollectionUtils.isEmpty(kmtExerciseQuestionList)) {
            return responseEntity.failure("题目不存在");
        }

        // 根据题目id分组，便于更新答案
        Map<String, List<QuestionUpdateRequest>> questionUpdateRequestListMap = request.getAnswerList().stream()
                .collect(Collectors.groupingBy(QuestionUpdateRequest::getQuestionId));
        // 遍历练习册题目更新答案
        QuestionUpdateRequest questionUpdateRequest;
        List<QuestionUpdateRequest> questionUpdateRequestList;
        String exerciseBookId = kmtExerciseQuestionList.get(0).getExerciseBookId();
        KmtExerciseBook exerciseBook = kmtExerciseBookService.getById(exerciseBookId);

        for (KmtExerciseQuestion kmtExerciseQuestion : kmtExerciseQuestionList) {
            kmtExerciseQuestion.setHandleUserId(exerciseBook.getHandleUserId());
            kmtExerciseQuestion.setAuditingUserId(exerciseBook.getAuditingUserId());
            kmtExerciseQuestion.setAnalysisUserId(exerciseBook.getAnalysisUserId());
            kmtExerciseQuestion.setAnalysisAuditerId(exerciseBook.getAnalysisAuditerId());
            questionUpdateRequestList = questionUpdateRequestListMap.get(kmtExerciseQuestion.getId());
            if (CollectionUtils.isEmpty(questionUpdateRequestList)) {
                continue;
            }
            questionUpdateRequest = questionUpdateRequestList.get(0);
            kmtExerciseQuestion.setAnswerJson(questionUpdateRequest.getAnswerJson());
            kmtExerciseQuestion.setAnalysisJson(questionUpdateRequest.getAnalysisJson());
            kmtExerciseQuestion.setProofreadStatus(3);
        }
        // 保存答案至数据库
        this.saveQuestionData2JSONFile(kmtExerciseQuestionList);
        kmtExerciseQuestionService.save(kmtExerciseQuestionList);

        // 如果已经没有需要修改答案的题目，则修改练习册的校对状态为已修改
        int count = kmtExerciseMapper.countAnswerWrongQuestion(exerciseBookId, questionIdSet);
        if (count < 1) {
            kmtExerciseMapper.updateKmtExerciseBookProofreadStatus(exerciseBookId, 3);
        }

        // 保存答案至es
        kmtExerciseQuestionService.save2EsBatch(kmtExerciseQuestionList);

        return responseEntity.success("成功");
    }

    @Override
    public ResponseEntity teacherAnswerProofreadDetail(String userId) {
        ResponseEntity responseEntity = new ResponseEntity();
        Map<String, Object> data = kmtExerciseMapper.teacherAnswerProofreadDetail(userId);
        MapGetterTool mapTool = new MapGetterTool(data);
        BigDecimal finishedNums = mapTool.getBigDecimal("finishedNums");
        long unfinishedNums = mapTool.getLong("total") - finishedNums.longValue();
        data.put("unfinishedNums", unfinishedNums);
        return responseEntity.success(data, "成功");
    }

    @Override
    public ResponseEntity questionsError(String userId, QuestionRollbackRequest request) {
        ResponseEntity responseEntity = new ResponseEntity();
        responseEntity.success("成功");
        if (CollectionUtils.isNotEmpty(request.getQuestionIds())){
            //报错类型，和被报错类型，管理员是0 ， 加工审核是1,2,3,4
            int[] fromAuthAndToAuth = getFromAuthAndToAuth(request.getDealType());
            //题目报错记录
            List<KmtExerciseQuestionErrors> questionErrors = kmtExerciseMapper.findKmtExerciseQuestionErrorsByQuestionIds(request.getQuestionIds(), fromAuthAndToAuth[1]);
            if (CollectionUtils.isEmpty(questionErrors)) {
                List<Map> questions = exerciseQuestionSearchService.findAllExerciseQuestionsByQuestionIds(request.getQuestionIds());
                KmtExerciseQuestionErrors questionErrorTmp = null;
                Date now = new Date();
                String toUserKey = getQuestionKeyByAuth(fromAuthAndToAuth[1]);


                //先更新正确率, 错误数等于库里计数加上题目总数
                String exerciseBookId = questions.get(0).getOrDefault("exerciseBookId", "").toString();
                String errorUserId = questions.get(0).getOrDefault(toUserKey, "").toString();
                updateBookCountAccuracy(exerciseBookId, request.getQuestionIds(), errorUserId, fromAuthAndToAuth[1]);

                for (Map map : questions) {
                    questionErrorTmp = new KmtExerciseQuestionErrors();
                    questionErrorTmp.setQuestionId(map.get("id").toString());
                    exerciseBookId = map.getOrDefault("exerciseBookId", "").toString();
                    questionErrorTmp.setExerciseBookId(exerciseBookId);
                    questionErrorTmp.setErrorReason(request.getReason());
                    questionErrorTmp.setCreateTime(now);
                    questionErrorTmp.setSetErrorUserAuth(fromAuthAndToAuth[0]);
                    questionErrorTmp.setSetErrorUserId(userId);
                    questionErrorTmp.setErrorUserAuth(fromAuthAndToAuth[1]);
                    questionErrorTmp.setErrorUserId(errorUserId);
                    questionErrorTmp.setErrorReasonImage(request.getErrorReasonImage());
                    kmtExerciseQuestionErrorsService.save(questionErrorTmp);
                }
            } else {
                responseEntity.failure(ResponseConstant.CODE_000, "请勿重复报错");
            }
        }
        return responseEntity;
    }


    /**
     * 更新被报错人的正确率
     * @param exerciseBookId
     * @param type
     */
    private void updateBookCountAccuracy (String exerciseBookId, List<String> questionIds, String userId,  int type){
        KmtExerciseBookCount kmtExerciseBookCount = kmtExerciseMapper.findBookCountByExerciseBookIdAndType(exerciseBookId, type);
        if (kmtExerciseBookCount != null){
            //正确率计算，百分比的整数部分
            int errorCount = kmtExerciseMapper.countQuestionErrorCountByExerciseBookId(userId, exerciseBookId, type);
            errorCount += questionIds.size();
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.termQuery("exerciseBookId.keyword", exerciseBookId));
            SearchSourceBuilder searchSourceBuilder = ElasticUtil.initSearchSourceBuilder(queryBuilder);
            long totalQuestions = exerciseQuestionSearchService.count("kmt_exercise_questions", searchSourceBuilder);
            if (totalQuestions > 0){
                int accuracy = Math.round((totalQuestions - errorCount) * 10000 / (float)totalQuestions);
                kmtExerciseMapper.updateKmtExerciseBookCountById(kmtExerciseBookCount.getId(), accuracy);

                ThreadPool.getInstance().addTask(new SyncRefreshExerciseBookDistributionCountTask(Collections.singletonList(exerciseBookId), 4));
            }
        } else {
            ThreadPool.getInstance().addTask(new SyncRefreshExerciseBookStatusTask(Collections.singletonList(exerciseBookId), 4));
        }
    }

    /***
     * type 转成报错人类型 和被报错人类型， 对应manager表的authority字段中的数字
     * @param type
     * @return
     */
    private int[] getFromAuthAndToAuth (int type){
        int[] fromAutToAuth = new int[2];
        switch (type){
            case 2 : fromAutToAuth[0] = 2; fromAutToAuth[1] = 1; break;
            case 3 : fromAutToAuth[0] = 0; fromAutToAuth[1] = 2; break;
            case 4 : fromAutToAuth[0] = 4; fromAutToAuth[1] = 3; break;
            case 5 : fromAutToAuth[0] = 0; fromAutToAuth[1] = 4; break;
            default: fromAutToAuth[0] = 0; fromAutToAuth[1] = 0; break;
        }
        return fromAutToAuth;
    }

    /**
     * 根据角色获取题目实体中的key
     * @param auth
     * @return
     */
    private String getQuestionKeyByAuth (int auth){
        String result = null;
        switch (auth){
            case 1 : result = "handleUserId";break;
            case 2 : result = "auditingUserId";break;
            case 3 : result = "analysisUserId";break;
            case 4 : result = "analysisAuditerId";break;
            default: result = "handleUserId"; break;
        }
        return  result;
    }

    @Override
    public Map<String, Object> findExerciseErrorQuestions(PageReq req, String userId) {
        Map<String, Object> data = new HashMap<>();
        Page page = new Page(req.getPageNo(), req.getPageSize());
        List<KmtExerciseQuestionErrors> questionErrors = kmtExerciseMapper.findKmtExerciseQuestionByErrorUserId(userId, page);
        if (CollectionUtils.isNotEmpty(questionErrors)){
            List<String> userIds = this.findUserIdsInExerciseQuestionList(questionErrors);
            List<TbLibManager> users = null;
            if (CollectionUtils.isNotEmpty(userIds)){
                Integer[] types = {17, 18};
                users = libManagerMapper.findTbLibManagerByUserIdsAndType(userIds, Arrays.asList(types));
            }

            List<ExerciseBookCourseClassDto> list = kmtExerciseMapperService.findClassifyQuestionsByIds(questionErrors.stream().map(question -> question.getQuestionId()).collect(Collectors.toList()));
            if  (list != null){
                for (ExerciseBookCourseClassDto parentQuetion : list){
                    for (ExerciseQuetionDto childQuestion : parentQuetion.getList()){
                        for (KmtExerciseQuestionErrors qe : questionErrors){
                            if (qe.getQuestionId().equals(childQuestion.getQuestionId())){
                                childQuestion.setFromUserId(qe.getSetErrorUserId());
                                childQuestion.setToUserId(qe.getErrorUserId());
                                childQuestion.appendUserNameByIds(users);
                                childQuestion.setFromUser(kmtExerciseQuestionService.getAuthorityByType(qe.getSetErrorUserAuth()) + childQuestion.getFromUser());
                                childQuestion.setToUser(kmtExerciseQuestionService.getAuthorityByType(qe.getErrorUserAuth()) + childQuestion.getToUser());
                                childQuestion.setReason(qe.getErrorReason());
                                childQuestion.setErrorReasonImage(qe.getErrorReasonImage());
                                break;
                            }
                        }
                    }
                }
                data.put("list", list);
            }
        }
        data.put("pageNo", page.getCurrent());
        data.put("pageSize", page.getSize());
        data.put("pages", page.getPages());
        data.put("total", page.getTotal());
        return data;
    }

    /**
     * 从题目列表中提取四个用户的id
     * @param list
     * @return
     */
    private List<String> findUserIdsInExerciseQuestionList (List<KmtExerciseQuestionErrors> list){
        Set<String> result = new HashSet<>();
        if (list != null) {
            list.stream().forEach(item -> {
                if (StringUtils.isNotBlank(item.getSetErrorUserId())) {
                    result.add(item.getSetErrorUserId());
                }
                if (StringUtils.isNotBlank(item.getErrorUserId())) {
                    result.add(item.getErrorUserId());
                }
            });
        }
        return new ArrayList<>(result);
    }

    @Override
    public void appendQuestionDataFromJSONFile(List<KmtExerciseQuestion> kmtExerciseQuestions) {
        for (KmtExerciseQuestion kmtExerciseQuestion : kmtExerciseQuestions){
            //读取大字段文件
            if (StringUtil.isNotBlank(kmtExerciseQuestion.getQuestionPath())){
                String content = JSONFileUtil.readJSONFile(PropertiesUtil.getValue("EXERCISE_JSON_FILE_PATH") + kmtExerciseQuestion.getQuestionPath());
                if (StringUtils.isNotBlank(content)){
                    JSONObject jsonObject = JSONObject.parseObject(content);
                    kmtExerciseQuestion.setQuestion(jsonObject.getString("question"));
                    kmtExerciseQuestion.setQuestionText(jsonObject.getString("question_text"));
                    kmtExerciseQuestion.setQuestionJson(jsonObject.getString("question_json"));
                    kmtExerciseQuestion.setOptionAnswer(jsonObject.getString("option_answer"));
                    kmtExerciseQuestion.setOptionAnswerText(jsonObject.getString("option_answer_text"));
                    kmtExerciseQuestion.setAnswerJson(jsonObject.getString("answer_json"));
                    kmtExerciseQuestion.setAnalysis(jsonObject.getString("analysis"));
                    kmtExerciseQuestion.setAnalysisJson(jsonObject.getString("analysis_json"));
                }
            }
        }
    }

    @Override
    public void appendQuestionDtoDataFromJSONFile(List<ExerciseQuetionDto> kmtExerciseQuestions) {
        for (ExerciseQuetionDto kmtExerciseQuestion : kmtExerciseQuestions){
            //读取大字段文件
            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.setQuestionText(jsonObject.getString("question_text"));
                    kmtExerciseQuestion.setAnswer(jsonObject.getString("option_answer"));
                    kmtExerciseQuestion.setAnswerJson(jsonObject.getString("answer_json"));
                    kmtExerciseQuestion.setQuestionAnalysis(jsonObject.getString("analysis"));
                    kmtExerciseQuestion.setAnalysisJson(jsonObject.getString("analysis_json"));
                    kmtExerciseQuestion.setOriginAnswer(jsonObject.getString("question_answer"));
                }
            }
        }
    }

    @Override
    public void appendQuestionMapFromJSONFile(List<Map<String, Object>> questions) {
        for (Map<String, Object> map : questions){
            //读取大字段文件
            if (StringUtil.isNotBlank(map.get("question_path") + "")){
                String content = JSONFileUtil.readJSONFile(PropertiesUtil.getValue("EXERCISE_JSON_FILE_PATH") + map.get("question_path"));
                if (StringUtils.isNotBlank(content)){
                    JSONObject jsonObject = JSONObject.parseObject(content);
                    map.put("question",jsonObject.getString("question"));
                    map.put("question_text",jsonObject.getString("question_text"));
                    map.put("question_json",jsonObject.getString("question_json"));
                    map.put("option_answer",jsonObject.getString("option_answer"));
                    map.put("option_answer_text",jsonObject.getString("option_answer_text"));
                    map.put("answer_json",jsonObject.getString("answer_json"));
                    map.put("analysis",jsonObject.getString("analysis"));
                    map.put("analysis_json",jsonObject.getString("analysis_json"));
                }
            }
        }
    }

    @Override
    public void saveQuestionData2JSONFile(List<KmtExerciseQuestion> kmtExerciseQuestions) {
        for (KmtExerciseQuestion kmtExerciseQuestion : kmtExerciseQuestions) {
            saveQuestionData2JSONFile(PropertiesUtil.getValue("EXERCISE_JSON_FILE_PATH") + kmtExerciseQuestion.getQuestionPath(), kmtExerciseQuestion);
        }
    }

    /**
     * 生成题目json文件路径
     * @param exerciseBook
     * @return
     */
    public String getQuestionJSONPath (KmtExerciseBook exerciseBook, String id){
        StringBuilder path = new StringBuilder();
        path.append("/exercise/").append(exerciseBook.getGrade()).append("/").append(exerciseBook.getCourseName()).append("/")
                .append(exerciseBook.getVersion()).append("/").append(exerciseBook.getSemester()).append("/")
                .append(exerciseBook.getId()).append("/").append(id).append(".json");
        return path.toString();
    }

    public String getKmtQuestionJSONPath (String courseName, String id){
        StringBuilder path = new StringBuilder();
        path.append("/kmt_questions/").append(courseName).append("/").append(id).append(".json");
        return path.toString();
    }

    /**
     * 获取图片的文件夹路径
     * @param exerciseBook
     * @return
     */
    private String getQuestionJSONFilePrefix (KmtExerciseBook exerciseBook){
        StringBuilder path = new StringBuilder();
        if (exerciseBook != null){
            path.append(PropertiesUtil.getValue("EXERCISE_JSON_FILE_PATH"));
            path.append("/exercise/").append(exerciseBook.getGrade()).append("/").append(exerciseBook.getCourseName()).append("/")
                    .append(exerciseBook.getVersion()).append("/").append(exerciseBook.getSemester()).append("/")
                    .append(exerciseBook.getId()).append("/");
        }
        return path.toString();
    }

    /**
     * 保存单个题目文件
     * @param path
     * @param kmtExerciseQuestion
     */
    private void saveQuestionData2JSONFile (String path, KmtExerciseQuestion kmtExerciseQuestion){
        if  (kmtExerciseQuestion != null){
            Map<String, Object> content = new HashMap<>();
            content.put("id", kmtExerciseQuestion.getId());
            content.put("question", kmtExerciseQuestion.getQuestion());
            content.put("question_text", kmtExerciseQuestion.getQuestionText());
            content.put("question_json", kmtExerciseQuestion.getQuestionJson());
            content.put("option_answer", kmtExerciseQuestion.getOptionAnswer());
            content.put("option_answer_text", kmtExerciseQuestion.getOptionAnswerText());
            content.put("answer_json", kmtExerciseQuestion.getAnswerJson());
            content.put("analysis", kmtExerciseQuestion.getAnalysis());
            content.put("analysis_json", kmtExerciseQuestion.getAnalysisJson());
            JSONFileUtil.saveJSONFile(path, JSON.toJSONString(content));
        }
    }
    @Override
    public ResponseEntity updateRollbackUserId(){
        ResponseEntity responseEntity=new ResponseEntity();
        List<KmtExerciseQuestionRollback> list=kmtExerciseQuestionRollbackService.findAllTouserId();
        list.forEach(a->{
            String questionId=a.getQuestionId();
            int toUserType=a.getToUserType();
            String bookId=kmtExerciseQuestionService.getById(questionId).getBookId();
            KmtExerciseBook book=kmtExerciseBookService.getById(bookId);
              if(1==toUserType){
                  a.setToUserId(book.getHandleUserId());
              }else if(2==toUserType){
                  a.setToUserId(book.getAuditingUserId());
              }else if(3==toUserType){
                  a.setToUserId(book.getAnalysisUserId());
              }else if(4==toUserType){
                  a.setToUserId(book.getAnalysisAuditerId());
              }
         kmtExerciseQuestionRollbackService.save(a);
        });
        return responseEntity.success("成功");
    }

    @Override
    public List<ExerciseQuestionRollbacks> findQuestionRollbackRecord(String questionId) {
        List<Map> questions = exerciseQuestionSearchService.getById(questionId, Map.class);
        if (CollectionUtils.isNotEmpty(questions) && StringUtils.isBlank((String)questions.get(0).get("bookId"))){
            //题目没有bookId, 是kmt题库的题目
            return kmtQualityQuestionsService.findQuestionRollbackRecord(questionId);
        } else {
            return kmtExerciseQuestionService.findQuestionRollbackRecord(questionId);
        }
    }
}
