package cn.com.qmth.examcloud.core.questions.service;

import cn.com.qmth.examcloud.api.commons.security.bean.User;
import cn.com.qmth.examcloud.api.commons.security.bean.UserDataRule;
import cn.com.qmth.examcloud.commons.exception.StatusException;
import cn.com.qmth.examcloud.core.basic.api.CourseCloudService;
import cn.com.qmth.examcloud.core.basic.api.request.GetCourseReq;
import cn.com.qmth.examcloud.core.basic.api.response.GetCourseResp;
import cn.com.qmth.examcloud.core.questions.base.CommonUtils;
import cn.com.qmth.examcloud.core.questions.base.Model;
import cn.com.qmth.examcloud.core.questions.base.enums.PaperStructType;
import cn.com.qmth.examcloud.core.questions.base.enums.QuestionDifficulty;
import cn.com.qmth.examcloud.core.questions.base.question.enums.QuesStructType;
import cn.com.qmth.examcloud.core.questions.dao.PaperStructRepo;
import cn.com.qmth.examcloud.core.questions.dao.QuesTypeNameRepo;
import cn.com.qmth.examcloud.core.questions.dao.entity.*;
import cn.com.qmth.examcloud.core.questions.dao.entity.dto.CoursePropertyNumberDto;
import cn.com.qmth.examcloud.core.questions.dao.entity.dto.PaperDetailUnitStructDto;
import cn.com.qmth.examcloud.core.questions.service.bean.dto.QuesNameDto;
import cn.com.qmth.examcloud.core.questions.service.cache.PaperStructCache;
import cn.com.qmth.examcloud.support.CacheConstants;
import cn.com.qmth.examcloud.web.redis.RedisClient;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

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

/**
 * Created by songyue on 16/12/28.
 */
@Service
public class PaperStructService {

    private static final Logger log = LoggerFactory.getLogger(PaperStructService.class);

    private static Cache<String, PaperStructCache> localPaperStructCache = CacheBuilder.newBuilder().expireAfterWrite(3, TimeUnit.MINUTES).build();

    private static int cacheTimeOut = 2 * 60 * 60;

    @Autowired
    private RandomPaperService randomPaperService;

    @Autowired
    private PaperStructRepo paperStructRepo;

    @Autowired
    private QuesTypeNameRepo quesTypeNameRepo;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private CourseCloudService courseCloudService;

    @Autowired
    private RedisClient redisClient;

    /**
     * 获取所有试卷结构(分页)
     *
     * @param searchInfo
     * @param curPage
     * @param pageSize
     * @return
     */
    public Page<PaperStruct> getPaperStructs(PaperStructSearchInfo searchInfo, int curPage, int pageSize,
                                             UserDataRule userDataRule) {
        if (userDataRule.assertEmptyQueryResult()) {
            return Page.empty();
        }

        Query query = new Query();
        query.addCriteria(Criteria.where("orgId").is(searchInfo.getOrgId()));
        if (userDataRule.assertNeedQueryRefIds()) {
            Criteria c1 = Criteria.where("courseId").in(userDataRule.getRefIds());
            Criteria c2 = Criteria.where("courseId").exists(false);
            Criteria cr = new Criteria();
            query.addCriteria(cr.orOperator(c1, c2));
        }
        query.addCriteria(Criteria.where("type").is(searchInfo.getType()));

        // 判断试卷结构
        if (PaperStructType.EXACT.name().equals(searchInfo.getType())) {
            if (StringUtils.isNotBlank(searchInfo.getCourseNo())) {
                if (!"ALL".equals(searchInfo.getCourseNo())) {
                    query.addCriteria(Criteria.where("courseNo").is(searchInfo.getCourseNo()));
                }
            } else {
                // “公用”情况
                query.addCriteria(Criteria.where("courseNo").is(""));
            }
        } else {
            if (StringUtils.isNotBlank(searchInfo.getCourseNo())) {
                query.addCriteria(Criteria.where("courseNo").is(searchInfo.getCourseNo()));
            }
        }

        if (StringUtils.isNotBlank(searchInfo.getName())) {
            String paperStructName = CommonUtils.escapeExprSpecialWord(searchInfo.getName());
            query.addCriteria(Criteria.where("name").regex(".*?" + paperStructName + ".*"));
        }

        if (StringUtils.isNotBlank(searchInfo.getCreator())) {
            String userName = CommonUtils.escapeExprSpecialWord(searchInfo.getCreator());
            query.addCriteria(Criteria.where("creator").regex(".*?" + userName + ".*"));
        }

        long total = this.mongoTemplate.count(query, PaperStruct.class);
        if (total == 0) {
            return Page.empty();
        }

        PageRequest pageable = PageRequest.of(curPage - 1, pageSize);
        query.with(Sort.by(Sort.Order.desc("createTime")));
        query.skip(pageable.getOffset());
        query.limit(pageable.getPageSize());

        List<PaperStruct> paperStructs = this.mongoTemplate.find(query, PaperStruct.class);
        if (CollectionUtils.isEmpty(paperStructs)) {
            return Page.empty();
        }

        Map<String, String> courseNameMaps = new HashMap<>();

        for (PaperStruct paperStruct : paperStructs) {
            if (StringUtils.isBlank(paperStruct.getCourseNo())) {
                paperStruct.setCourseName("公用");
            } else {
                String courseName = courseNameMaps.get(paperStruct.getCourseNo());

                if (StringUtils.isEmpty(courseName)) {
                    GetCourseReq req = new GetCourseReq();
                    req.setRootOrgId(Long.valueOf(paperStruct.getOrgId()));
                    req.setCode(paperStruct.getCourseNo());
                    GetCourseResp resp = courseCloudService.getCourse(req);
                    courseName = resp.getCourseBean().getName();
                    courseNameMaps.put(paperStruct.getCourseNo(), courseName);
                }

                paperStruct.setCourseName(courseName);
            }
        }

        return new PageImpl<>(paperStructs, pageable, total);
    }

    /**
     * 获取所有试卷结构(分页)
     *
     * @param searchInfo
     * @return
     */
    public List<PaperStruct> getPaperStructs(PaperStructSearchInfo searchInfo, UserDataRule ud) {
        if (ud.assertEmptyQueryResult()) {
            return new ArrayList<>();
        }
        Query query = new Query();
        if (StringUtils.isNotBlank(searchInfo.getCourseNo())) {
            query.addCriteria(Criteria.where("courseNo").in("", searchInfo.getCourseNo()));
        }
        query.addCriteria(Criteria.where("orgId").is(searchInfo.getOrgId()));
        if (ud.assertNeedQueryRefIds()) {
            Criteria c1 = Criteria.where("courseId").in(ud.getRefIds());
            Criteria c2 = Criteria.where("courseId").exists(false);
            Criteria cr = new Criteria();
            cr.orOperator(c1, c2);
        }
        if (StringUtils.isNotBlank(searchInfo.getType())) {
            query.addCriteria(Criteria.where("type").is(searchInfo.getType()));
        }
        query.with(Sort.by(Sort.Order.desc("createTime")));
        List<PaperStruct> paperList = this.mongoTemplate.find(query, PaperStruct.class);
        return paperList;
    }

    public void formatSearchInfo(PaperStructSearchInfo searchInfo) {
        if (StringUtils.isEmpty(searchInfo.getName())) {
            searchInfo.setName(null);
        }
        if (StringUtils.isEmpty(searchInfo.getCreator())) {
            searchInfo.setCreator(null);
        }
        if (StringUtils.isEmpty(searchInfo.getCourseNo())) {
            searchInfo.setCourseNo(null);
        }
    }

    public void formatPaperStruct(PaperStruct paperStruct) {
        paperStruct.setCreateTime(null);
    }

    /**
     * 保存试卷结构
     *
     * @param paperStruct
     * @return
     */
    public PaperStruct save(PaperStruct paperStruct, User user) {
        if (StringUtils.isNotBlank(paperStruct.getCourseNo())) {
            GetCourseReq req = new GetCourseReq();
            req.setRootOrgId(Long.valueOf(paperStruct.getOrgId()));
            req.setCode(paperStruct.getCourseNo());
            GetCourseResp resp = courseCloudService.getCourse(req);
            if (resp.getCourseBean() == null) {
                throw new StatusException("500", "课程不存在");
            }
            paperStruct.setCourseId(resp.getCourseBean().getId());
        } else {
            paperStruct.setCourseId(null);
        }
        if (StringUtils.isNotBlank(paperStruct.getId())) {
            PaperStruct oldPaperStruct = Model.of(paperStructRepo.findById(paperStruct.getId()));
            PaperStruct rps = null;
            if (oldPaperStruct != null && !paperStruct.getName().equals(oldPaperStruct.getName())) {// 那么就是更新操作
                rps = this.checkNameUnique(paperStruct.getName(), user.getRootOrgId().toString(),
                        oldPaperStruct.getType());
            }
            if (rps != null) {
                return null;
            }
        }
        List<PaperDetailStruct> paperDetailStructs = paperStruct.getPaperDetailStructs();
        int number = 0;
        // 新增精确试卷结构
        if (paperStruct.getType().equals("EXACT")) {
            for (PaperDetailStruct paperDetailStruct : paperDetailStructs) {
                List<PaperDetailUnitStruct> oldStructs = paperDetailStruct.getPaperDetailUnitStructs();
                if (oldStructs != null && oldStructs.size() > 0) {
                    oldStructs.clear();
                }
                List<PaperDetailUnitStruct> unitStructs = new ArrayList<>();
                for (PaperDetailUnitStructDto unitStructDto : paperDetailStruct.getUnitStructs()) {
                    // 公开简单总数
                    for (int i = 0; i < unitStructDto.getPublicSimple(); i++) {
                        ++number;
                        PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
                        unitStruct.setDifficulty("易");
                        unitStruct.setPublicity(true);
                        unitStruct.setId(String.valueOf(number));
                        unitStruct.setNumber(number);
                        unitStruct.setScore(unitStructDto.getScore());
                        unitStruct.setQuestionType(unitStructDto.getQuestionType());
                        unitStruct.setQuesNames(unitStructDto.getQuesNames());
                        unitStruct.setPropertyGroup(buildGroup(unitStruct));
                        unitStructs.add(unitStruct);
                    }
                    // 公开中等总数
                    for (int i = 0; i < unitStructDto.getPublicMedium(); i++) {
                        ++number;
                        PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
                        unitStruct.setDifficulty("中");
                        unitStruct.setPublicity(true);
                        unitStruct.setId(String.valueOf(number));
                        unitStruct.setNumber(number);
                        unitStruct.setScore(unitStructDto.getScore());
                        unitStruct.setQuestionType(unitStructDto.getQuestionType());
                        unitStruct.setQuesNames(unitStructDto.getQuesNames());
                        unitStruct.setPropertyGroup(buildGroup(unitStruct));
                        unitStructs.add(unitStruct);
                    }
                    // 公开困难总数
                    for (int i = 0; i < unitStructDto.getPublicDifficulty(); i++) {
                        ++number;
                        PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
                        unitStruct.setDifficulty("难");
                        unitStruct.setPublicity(true);
                        unitStruct.setId(String.valueOf(number));
                        unitStruct.setNumber(number);
                        unitStruct.setScore(unitStructDto.getScore());
                        unitStruct.setQuestionType(unitStructDto.getQuestionType());
                        unitStruct.setQuesNames(unitStructDto.getQuesNames());
                        unitStruct.setPropertyGroup(buildGroup(unitStruct));
                        unitStructs.add(unitStruct);
                    }
                    // 非公开简单总数
                    for (int i = 0; i < unitStructDto.getNoPublicSimple(); i++) {
                        ++number;
                        PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
                        unitStruct.setDifficulty("易");
                        unitStruct.setPublicity(false);
                        unitStruct.setId(String.valueOf(number));
                        unitStruct.setNumber(number);
                        unitStruct.setScore(unitStructDto.getScore());
                        unitStruct.setQuestionType(unitStructDto.getQuestionType());
                        unitStruct.setQuesNames(unitStructDto.getQuesNames());
                        unitStruct.setPropertyGroup(buildGroup(unitStruct));
                        unitStructs.add(unitStruct);
                    }
                    // 非公开中等总数
                    for (int i = 0; i < unitStructDto.getNoPublicMedium(); i++) {
                        ++number;
                        PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
                        unitStruct.setDifficulty("中");
                        unitStruct.setPublicity(false);
                        unitStruct.setId(String.valueOf(number));
                        unitStruct.setNumber(number);
                        unitStruct.setScore(unitStructDto.getScore());
                        unitStruct.setQuestionType(unitStructDto.getQuestionType());
                        unitStruct.setQuesNames(unitStructDto.getQuesNames());
                        unitStruct.setPropertyGroup(buildGroup(unitStruct));
                        unitStructs.add(unitStruct);
                    }
                    // 非公开困难总数
                    for (int i = 0; i < unitStructDto.getNoPublicDifficulty(); i++) {
                        ++number;
                        PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
                        unitStruct.setDifficulty("难");
                        unitStruct.setPublicity(false);
                        unitStruct.setId(String.valueOf(number));
                        unitStruct.setNumber(number);
                        unitStruct.setScore(unitStructDto.getScore());
                        unitStruct.setQuestionType(unitStructDto.getQuestionType());
                        unitStruct.setQuesNames(unitStructDto.getQuesNames());
                        unitStruct.setPropertyGroup(buildGroup(unitStruct));
                        unitStructs.add(unitStruct);
                    }
                    //公开难度不限
                    for (int i = 0; i < unitStructDto.getPublicAnyDifficulty(); i++) {
                        ++number;
                        PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
                        unitStruct.setDifficulty(QuestionDifficulty.ANY.getName());
                        unitStruct.setPublicity(true);
                        unitStruct.setId(String.valueOf(number));
                        unitStruct.setNumber(number);
                        unitStruct.setScore(unitStructDto.getScore());
                        unitStruct.setQuestionType(unitStructDto.getQuestionType());
                        unitStruct.setQuesNames(unitStructDto.getQuesNames());
                        unitStruct.setPropertyGroup(buildGroup(unitStruct));
                        unitStructs.add(unitStruct);
                    }
                    
                    //非公开难度不限
                    for (int i = 0; i < unitStructDto.getNoPublicAnyDifficulty(); i++) {
                        ++number;
                        PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
                        unitStruct.setDifficulty(QuestionDifficulty.ANY.getName());
                        unitStruct.setPublicity(false);
                        unitStruct.setId(String.valueOf(number));
                        unitStruct.setNumber(number);
                        unitStruct.setScore(unitStructDto.getScore());
                        unitStruct.setQuestionType(unitStructDto.getQuestionType());
                        unitStruct.setQuesNames(unitStructDto.getQuesNames());
                        unitStruct.setPropertyGroup(buildGroup(unitStruct));
                        unitStructs.add(unitStruct);
                    }
                }
                paperDetailStruct.setPaperDetailUnitStructs(unitStructs);
            }
            paperStruct.setPaperStrucType(PaperStructType.EXACT);
            paperStruct
                    .setDetailUnitCount(paperDetailStructs.stream().mapToInt(PaperDetailStruct::getDetailCount).sum());
        } else {
            // 新增蓝图试卷结构
            for (PaperDetailStruct paperDetailStruct : paperDetailStructs) {
                List<PaperDetailUnitStruct> oldStructs = paperDetailStruct.getPaperDetailUnitStructs();
                if (oldStructs != null && oldStructs.size() > 0) {
                    oldStructs.clear();
                }
                List<PaperDetailUnitStruct> unitStructs = new ArrayList<>();
                for (CoursePropertyNumberDto coursePropertyNumberDto : paperDetailStruct
                        .getCoursePropertyNumberDtos()) {
                    // 取到子节点上的题目
                    if (!coursePropertyNumberDto.getDisable()) {
                        // 公开简单数量
                        for (int i = 0; i < coursePropertyNumberDto.getPublicSimple(); i++) {
                            ++number;
                            PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct(paperDetailStruct, number,
                                    coursePropertyNumberDto);
                            unitStruct.setDifficulty("易");
                            unitStruct.setPublicity(true);
                            unitStruct.setPropertyGroup(buildPropertyGroup(unitStruct));
                            unitStructs.add(unitStruct);
                        }
                        // 公开中等数量
                        for (int i = 0; i < coursePropertyNumberDto.getPublicMedium(); i++) {
                            ++number;
                            PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct(paperDetailStruct, number,
                                    coursePropertyNumberDto);
                            unitStruct.setDifficulty("中");
                            unitStruct.setPublicity(true);
                            unitStruct.setPropertyGroup(buildPropertyGroup(unitStruct));
                            unitStructs.add(unitStruct);
                        }
                        // 公开困难数量
                        for (int i = 0; i < coursePropertyNumberDto.getPublicDifficulty(); i++) {
                            ++number;
                            PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct(paperDetailStruct, number,
                                    coursePropertyNumberDto);
                            unitStruct.setDifficulty("难");
                            unitStruct.setPublicity(true);
                            unitStruct.setPropertyGroup(buildPropertyGroup(unitStruct));
                            unitStructs.add(unitStruct);
                        }
                        // 非公开简单数量
                        for (int i = 0; i < coursePropertyNumberDto.getNoPublicSimple(); i++) {
                            ++number;
                            PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct(paperDetailStruct, number,
                                    coursePropertyNumberDto);
                            unitStruct.setDifficulty("易");
                            unitStruct.setPublicity(false);
                            unitStruct.setPropertyGroup(buildPropertyGroup(unitStruct));
                            unitStructs.add(unitStruct);
                        }
                        // 非公开中等数量
                        for (int i = 0; i < coursePropertyNumberDto.getNoPublicMedium(); i++) {
                            ++number;
                            PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct(paperDetailStruct, number,
                                    coursePropertyNumberDto);
                            unitStruct.setDifficulty("中");
                            unitStruct.setPublicity(false);
                            unitStruct.setPropertyGroup(buildPropertyGroup(unitStruct));
                            unitStructs.add(unitStruct);
                        }
                        // 非公开困难
                        for (int i = 0; i < coursePropertyNumberDto.getNoPublicDifficulty(); i++) {
                            ++number;
                            PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct(paperDetailStruct, number,
                                    coursePropertyNumberDto);
                            unitStruct.setDifficulty("难");
                            unitStruct.setPublicity(false);
                            unitStruct.setPropertyGroup(buildPropertyGroup(unitStruct));
                            unitStructs.add(unitStruct);
                        }
                    }
                }
                paperDetailStruct.setPaperDetailUnitStructs(unitStructs);
            }
            paperStruct.setPaperStrucType(PaperStructType.BLUEPRINT);
            // 计算试卷结构难度
            Double difficulty = getDifficulty(paperDetailStructs, paperStruct.getTotalScore());
            paperStruct.setDifficulty(difficulty);
        }
        paperStruct.setOrgId(user.getRootOrgId().toString());
        paperStruct.setCreator(user.getDisplayName());
        paperStruct.setCreateTime(CommonUtils.getCurDateTime());
        paperStruct.setDetailCount(paperDetailStructs.size());
        PaperStruct ret = paperStructRepo.save(paperStruct);
        String key = CacheConstants.CACHE_Q_PAPER_STRUCT + paperStruct.getId();
        redisClient.delete(key);
        return ret;
    }

    /**
     * 构建精确组建筛选条件
     *
     * @param unitStruct
     * @return
     */
    private String buildGroup(PaperDetailUnitStruct unitStruct) {
        return String.valueOf(unitStruct.getPublicity()) + "-" + unitStruct.getDifficulty();
    }

    /**
     * 构建单个属性组（用来筛选题目）
     *
     * @param unitStruct
     */
    private String buildPropertyGroup(PaperDetailUnitStruct unitStruct) {
        return unitStruct.getPropertyId() + "-" + String.valueOf(unitStruct.getPublicity()) + "-"
                + unitStruct.getDifficulty();
    }

    public Double getDifficulty(List<PaperDetailStruct> paperDetailStructs, Double totalScore) {
        Double sum = 0.0;
        if (paperDetailStructs != null && paperDetailStructs.size() > 0) {
            Integer simpleCount = 0;
            Integer mediumCount = 0;
            Integer difficultyCount = 0;
            for (PaperDetailStruct paperDetailStruct : paperDetailStructs) {
                simpleCount = paperDetailStruct.getPublicSimpleCount() + paperDetailStruct.getNoPublicSimpleCount();
                mediumCount = paperDetailStruct.getPublicMediumCount() + paperDetailStruct.getNoPublicMediumCount();
                difficultyCount = paperDetailStruct.getPublicDifficultyCount()
                        + paperDetailStruct.getNoPublicDifficultyCount();
                sum = simpleCount * paperDetailStruct.getScore() * 0.8
                        + mediumCount * paperDetailStruct.getScore() * 0.5
                        + difficultyCount * paperDetailStruct.getScore() * 0.2 + sum;
            }

            Double dif = sum / totalScore;
            BigDecimal b = BigDecimal.valueOf(dif);
            Double difficulty = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            return difficulty;
        }
        return (double) 0;
    }

    public PaperStruct checkNameUnique(String name, String orgId, String type) {
        Query query = new Query();
        query.addCriteria(Criteria.where("orgId").is(orgId));
        query.addCriteria(Criteria.where("name").is(name.trim()));
        query.addCriteria(Criteria.where("type").is(type));
        PaperStruct paperStruct = this.mongoTemplate.findOne(query, PaperStruct.class);
        return paperStruct;
    }

    public List<QuesNameDto> getQuesNameList(String orgId, String courseNo, QuesStructType quesType) {
        List<QuesNameDto> quesNameList = new ArrayList<>();
        List<QuesTypeName> quesTypeNames = new ArrayList<>();
        if (StringUtils.isEmpty(courseNo)) {
            quesTypeNames = quesTypeNameRepo.findQuesName(orgId, quesType);
        } else {
            quesTypeNames = quesTypeNameRepo.findQuesName(orgId, courseNo, quesType);
        }
        quesNameList = quesTypeNames.stream().map(QuesTypeName::getQuesNames).flatMap(Collection::stream).distinct()
                .map(this::getQuesName).collect(Collectors.toList());
        return quesNameList;
    }

    private QuesNameDto getQuesName(String name) {
        return new QuesNameDto(name, name);
    }

    public PaperStructCache getPaperStructCacheById(String paperStructId) {
        // 组卷结构 优先从本地缓存中获取
        String key = CacheConstants.CACHE_Q_PAPER_STRUCT + paperStructId;
        PaperStructCache ps = localPaperStructCache.getIfPresent(key);
        if (ps != null) {
            log.warn("从【本地缓存】中获取组卷结构！ key:{}", key);
            return ps;
        }

        // 从redis缓存中获取
        ps = redisClient.get(key, PaperStructCache.class, cacheTimeOut);
        if (ps != null) {
            localPaperStructCache.put(key, ps);
            log.warn("从【Redis缓存】中获取抽卷模板！ key:{}", key);
            return ps;
        }

        // 从数据库中获取
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(new ObjectId(paperStructId)));
        ps = this.mongoTemplate.findOne(query, PaperStructCache.class, "paperStruct");
        if (ps == null) {
            throw new StatusException("未找到试卷结构:" + paperStructId);
        }

        log.warn("从【数据库】中获取抽卷模板！ key:{}", key);
        redisClient.set(key, ps, cacheTimeOut);
        localPaperStructCache.put(key, ps);
        return ps;
    }

    public void removePaperStruct(List<String> ids) {
        for (String id : ids) {
            if (randomPaperService.existStruct(id)) {
                PaperStruct ps = Model.of(paperStructRepo.findById(id));
                throw new StatusException(ps.getName() + "已被抽题模板使用，不能删除");
            }
            paperStructRepo.deleteById(id);
            String key = CacheConstants.CACHE_Q_PAPER_STRUCT + id;
            redisClient.delete(key);
        }
    }

}
