package cn.com.qmth.stmms.ms.marking.service;

import cn.com.qmth.stmms.ms.commons.config.ScoreConfig;
import cn.com.qmth.stmms.ms.commons.utils.SqlUtil;
import cn.com.qmth.stmms.ms.core.domain.*;
import cn.com.qmth.stmms.ms.core.domain.enums.TrialEnum;
import cn.com.qmth.stmms.ms.core.domain.user.MarkRight;
import cn.com.qmth.stmms.ms.core.domain.user.MarkUser;
import cn.com.qmth.stmms.ms.core.domain.user.MarkerGroup;
import cn.com.qmth.stmms.ms.core.domain.user.Role;
import cn.com.qmth.stmms.ms.core.repository.*;
import cn.com.qmth.stmms.ms.core.vo.Subject;
import cn.com.qmth.stmms.ms.marking.dto.LevleProgressDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.naming.event.ObjectChangeListener;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 评卷阶段控制服务
 * Created by zhengmin on 2016/9/24.
 */
@Service
public class StageControlService {

    @Autowired
    private MarkSubjectRepo markSubjectRepo;

    @Autowired
    private MarkTaskRepo markTaskRepo;

    @Autowired
    private LevelRepo levelRepo;

    @Autowired
    private PaperRepo paperRepo;

    @Autowired
    private MarkUserRepo markUserRepo;

    @Autowired
    private AssignTaskService assignTaskService;

    @Autowired
    private ExamQuestionRepo examQuestionRepo;

    @Autowired
    private MarkerGroupRepo markerGroupRepo;

    @Autowired
    private TaskPublishSettingRepo taskPublishSettingRepo;

    @Autowired
    ScoreConfig scoreConfig;

    @Autowired
    SqlUtil sqlUtil;

    public static volatile Map<String, Boolean> statusMap = new Hashtable<>();

    /**
     * 进入下一阶段
     *
     * @param markSubject
     */
    @Transactional
    public void goNext(MarkSubject markSubject, Map map) throws Exception {
        if (statusMap.get(markSubject.getId()) != null && statusMap.get(markSubject.getId())) {
            return;
        }
        statusMap.put(markSubject.getId(), true);
        MarkStage markStage = markSubject.getStage();
        //是否还有未投放的试卷
        int waitCount = paperRepo.countByWorkIdAndSubjectAndIsMissingFalseAndActiveFalseAndBatchNoIsNullAndTest(markSubject.getWorkId(), markSubject.getSubject(), 0);
        if (waitCount > 0 && markStage.equals(MarkStage.LEVEL)) {
            markStage = MarkStage.INIT;
        }
        switch (markStage) {
            case INIT:
                markSubject.setStage(MarkStage.LEVEL);
                int taskCount = (int) map.get("taskCount");
                Object questionId = map.get("questionId");
                enterLevelStage(markSubject, taskCount, questionId);
                break;
            case LEVEL:
                markSubject.setStage(MarkStage.SCORE);
//                enterScoreStage(markSubject);
                enterToScoreStage(markSubject);
                break;
            case SCORE:
                //TODO 进入抽查阶段
                if (!markSubject.isAllLevel()) {
                    markSubject.setStage(MarkStage.SCORE);
                    enterScoreStage(markSubject);
                } else {
                    markSubject.setStage(MarkStage.INSPECT);
                    enterInspectStage(markSubject);
                }
                break;
            case INSPECT:
                //TODO 结束评卷
                markSubject.setStage(MarkStage.END);
                break;
        }
        markSubjectRepo.save(markSubject);
        statusMap.put(markSubject.getId(), false);
    }

    /**
     * 进入分档阶段
     * 1.检查是否有设定档位，如果有，将所有level设置连续的levelValue值，用于仲裁误差判定
     * 2.检查有无可分档的评卷员，没有则终止
     * 3.给所有能够分档的评卷员分配任务
     *
     * @param markSubject
     */
    private void enterLevelStage(MarkSubject markSubject, int taskCount, Object questionId) throws Exception {
        Long workId = markSubject.getWorkId();
        Subject subject = markSubject.getSubject();
        List<Level> levels = levelRepo.findByWorkId(workId);
        if (levels.size() == 0) {
            statusMap.put(markSubject.getId(), false);
            throw new RuntimeException("没有设定档位");
        }

        List<MarkUser> markers = markUserRepo.findByWorkIdAndSubjectAndRole(workId, subject, Role.MARKER);
        List<MarkUser> levelMarkers = markers.stream().filter(m -> m.getMarkRight() == MarkRight.ALLOW_ALL || m.getMarkRight() == MarkRight.ALLOW_LEVELING).collect(Collectors.toList());
        if (levelMarkers.size() == 0) {
            statusMap.put(markSubject.getId(), false);
            throw new RuntimeException("没有设定评卷员");
        }

        List<MarkUser> markerLeader = markUserRepo.findByWorkIdAndSubjectAndRole(workId, subject, Role.MARK_LEADER);
        if (markerLeader.size() == 0) {
            statusMap.put(markSubject.getId(), false);
            throw new RuntimeException("没有设定科组长");
        }

        for (int i = 0; i < levels.size(); i++) {
            levels.get(i).setLevelValue(i);
        }
        levelRepo.save(levels);
        //assignTaskService.assignForAll(papers, levelMarkers, markSubject);
        List<MarkerGroup> markerGroups = markerGroupRepo.findByWorkIdAndSubject(workId, subject);
        if (markerGroups.size() == 0) {
            statusMap.put(markSubject.getId(), false);
            throw new RuntimeException("评卷员没有进行分组");
        }

        if (markSubject.getTest() != 1) {
            //是否有未结束的分档任务
            int count = paperRepo.countByWorkIdAndSubjectAndLevelIsNullAndIsMissingFalseAndActiveTrueAndBatchNoNotNullAndTest(workId, subject, 0);
            if (count > 0) {
                statusMap.put(markSubject.getId(), false);
                throw new RuntimeException("没有分档完成");
            }

            if (Objects.nonNull(questionId)) {
                Long questionId1 = Long.valueOf(questionId.toString());
                int qcount = paperRepo.countByWorkIdAndQuestionIdAndSubjectAndLevelIsNullAndIsMissingFalseAndTest(workId, questionId1, subject, 0);
                if (qcount == 0) {
                    statusMap.put(markSubject.getId(), false);
                    throw new RuntimeException("没有可分档任务");
                }
            }

            //任务数量大于0，小于等于待评数量
            if (taskCount == 0) {
                statusMap.put(markSubject.getId(), false);
                throw new RuntimeException("请输入正确的分配任务数量");
            }
            int waitCount;
            if (Objects.isNull(questionId)) {
                waitCount = paperRepo.countByWorkIdAndSubjectAndIsMissingFalseAndActiveFalseAndBatchNoIsNullAndTest(workId, subject, 0);
            } else {
                Long questionId1 = Long.valueOf(questionId.toString());
                waitCount = paperRepo.countByWorkIdAndQuestionIdAndSubjectAndIsMissingFalseAndActiveFalseAndBatchNoIsNullAndTest(workId, questionId1, subject, 0);
            }
            if (taskCount - waitCount > 0) {
                statusMap.put(markSubject.getId(), false);
                throw new RuntimeException("分配任务数量不能大于待评数量");
            }
        }

        List<Paper> papers = null;
        if (markSubject.getTest() == 1) {
            papers = paperRepo.findByWorkIdAndSubjectAndIsMissingAndTest(workId, subject, false, markSubject.getTest());
        } else {
            List<Paper> papersList;
            if (Objects.isNull(questionId)) {
                papersList = paperRepo.findByWorkIdAndSubjectAndIsMissingFalseAndActiveFalseAndTestOrderByQuestionId(workId, subject, TrialEnum.DEFAULT.getId());
            } else {
                Long questionId1 = Long.valueOf(questionId.toString());
                papersList = paperRepo.findByWorkIdAndQuestionIdAndSubjectAndIsMissingFalseAndActiveFalseAndTestOrderByQuestionId(workId, questionId1, subject, 0);
            }
            papers = papersList.subList(0, taskCount);
        }
        assignTaskService.assignForGrouping(papers, markerGroups, markSubject, null);
    }

    /**
     * 进入打分阶段
     * 1.检查是否有能够打分的评卷员
     * 2.检查是否所有试卷都分档完成（有仲裁卷或打回重评卷）
     *
     * @param markSubject
     */
    private void enterScoreStage(MarkSubject markSubject) throws Exception {
        Long workId = markSubject.getWorkId();
        Subject subject = markSubject.getSubject();
        List<MarkUser> markers = markUserRepo.findByWorkIdAndSubjectAndRole(workId, subject, Role.MARKER);
        List<MarkUser> levelMarkers = markers.stream().filter(m -> m.getMarkRight() == MarkRight.ALLOW_ALL || m.getMarkRight() == MarkRight.ALLOW_SCORING).collect(Collectors.toList());
        if (levelMarkers.size() == 0) {
            statusMap.put(markSubject.getId(), false);
            throw new RuntimeException("没有设定评卷员");
        }
        int count = paperRepo.countByWorkIdAndSubjectAndLevelIsNullAndIsMissingFalseAndActiveTrueAndBatchNoNotNullAndTest(workId, subject, 0);
        if (count > 0) {
            statusMap.put(markSubject.getId(), false);
            throw new RuntimeException("没有分档完成");
        }
        this.isPtFull(workId, markSubject);
        List<MarkerGroup> markerGroups = markerGroupRepo.findByWorkIdAndSubject(workId, subject);
        if (markerGroups.size() == 0) {
            statusMap.put(markSubject.getId(), false);
            throw new RuntimeException("评卷员没有进行分组");
        }
        List<Paper> papers = null;
        //是否启用打分配置
        if (Objects.nonNull(scoreConfig) && scoreConfig.isEnable()) {
            //2019.11.20日加入根据配置文件打分分档
            if (Objects.nonNull(scoreConfig) && Objects.nonNull(scoreConfig.getExclude()) && scoreConfig.getExclude().size() > 0) {
                List<String> configLevelList = scoreConfig.getExclude();
                configLevelList = configLevelList.stream().map(string -> string.trim().toUpperCase()).collect(Collectors.toList());
                long levelCount = levelRepo.countByWorkIdAndCodeIn(workId, configLevelList);
                if (levelCount == 0) {
                    statusMap.put(markSubject.getId(), false);
                    throw new RuntimeException("配置的档位:" + configLevelList + "不存在");
                }
                List<Level> levels = levelRepo.findByWorkIdAndCodeNotIn(workId, configLevelList);
                List<String> levelList = levels.stream().map(Level::getCode).collect(Collectors.toList());
                Collections.sort(levelList);
                Object o1 = levelList.stream().map(s -> "'" + s + "'").collect(Collectors.joining(","));
                StringJoiner joiner = new StringJoiner("");
                joiner.add("select count(1),p.`level` from mark_task mt left join paper p on p.id = mt.paper_id where mt.stage = 2 and p.`level` in (").add(o1.toString()).add(") and mt.work_id = ").add(String.valueOf(workId)).add(" and mt.subject = '").add(String.valueOf(subject)).add("'");
                String sql = sqlUtil.sqlGroupBy(joiner.toString(), "p.`level`");
                List list = sqlUtil.execSqlForMap(sql);
                List<String> finalLevelList = new ArrayList();
                if (Objects.isNull(list) || list.size() == 0) {
                    finalLevelList.addAll(levelList);
                } else {
                    for (int i = 0; i < list.size(); i++) {
                        Map map = (Map) list.get(i);
                        String level = String.valueOf(map.get("level"));
                        if (!levelList.contains(level)) {
                            finalLevelList.add(level);
                        }
                    }
                }
                if (Objects.nonNull(list) && list.size() > 0 && finalLevelList.size() == 0) {
                    statusMap.put(markSubject.getId(), false);
                    throw new RuntimeException("档位:" + o1 + "已经分配过");
                }
                markSubject.setAllLevel(false);
                papers = paperRepo.findByWorkIdAndSubjectAndIsMissingFalseAndActiveTrueAndLevelIn(workId, subject, finalLevelList);
                if (Objects.isNull(papers) || papers.size() == 0) {
                    statusMap.put(markSubject.getId(), false);
                    throw new RuntimeException("试卷中没有找到" + finalLevelList + "档位");
                }
            } else if (Objects.nonNull(scoreConfig) && Objects.nonNull(scoreConfig.getTaskSort())) {
                if (Objects.equals("paper", scoreConfig.getTaskSort().trim()) && Objects.nonNull(scoreConfig.getExclude()) && scoreConfig.getExclude().size() == 0) {
                    List<Level> allLevel = levelRepo.findByWorkId(workId);
                    List<String> levelList = allLevel.stream().map(Level::getCode).collect(Collectors.toList());
                    Collections.sort(levelList);
                    Object o1 = levelList.stream().map(s -> "'" + s + "'").collect(Collectors.joining(","));
                    StringJoiner joiner = new StringJoiner("");
                    joiner.add("select count(1),p.`level` from mark_task mt left join paper p on p.id = mt.paper_id where mt.stage = 2 and p.`level` in (").add(o1.toString()).add(") and mt.work_id = ").add(String.valueOf(workId)).add(" and mt.subject = '").add(String.valueOf(subject)).add("'");
                    String sql = sqlUtil.sqlGroupBy(joiner.toString(), "p.`level`");
                    List list = sqlUtil.execSqlForMap(sql);
                    List<String> finalLevelList = new ArrayList();
                    for (int i = 0; i < list.size(); i++) {
                        Map map = (Map) list.get(i);
                        String level = String.valueOf(map.get("level"));
                        finalLevelList.add(level);
                    }
                    //求task任务完成度
                    if (finalLevelList.size() > 0) {
                        joiner = new StringJoiner("");
                        Object o2 = finalLevelList.stream().map(s -> "'" + s + "'").collect(Collectors.joining(","));
                        joiner.add("select count(1) as count from mark_task mt left join paper p on p.id = mt.paper_id where mt.stage = 2 and p.`level` in (").add(o2.toString()).add(")").add(" and mt.`result` is null").add(" and mt.work_id = ").add(String.valueOf(workId)).add(" and mt.subject = '").add(String.valueOf(subject)).add("'");
                        list = sqlUtil.execSqlForMap(joiner.toString());
                        if (Objects.nonNull(list) && list.size() > 0) {
                            Map map = (Map) list.get(0);
                            int taskCount = Integer.parseInt(String.valueOf(map.get("count")));
                            if (taskCount > 0) {
                                statusMap.put(markSubject.getId(), false);
                                throw new RuntimeException("档位:" + o2 + "还有任务未完成");
                            }
                        }
                    }
                    //求差值
                    List<String> distinctIdList = levelList.stream().filter(item -> !finalLevelList.contains(item)).collect(Collectors.toList());
                    markSubject.setAllLevel(true);
                    papers = paperRepo.findByWorkIdAndSubjectAndIsMissingFalseAndActiveTrueAndLevelIn(workId, subject, distinctIdList);
                    if (Objects.isNull(papers) || papers.size() == 0) {
                        statusMap.put(markSubject.getId(), false);
                        throw new RuntimeException("试卷中没有找到" + distinctIdList + "档位");
                    }
                } else {
                    statusMap.put(markSubject.getId(), false);
                    throw new RuntimeException("请配置打分exclude");
                }
            }
        } else {
            markSubject.setAllLevel(true);
            Sort sort = new Sort("questionId");
            papers = paperRepo.findByWorkIdAndSubjectAndIsMissingFalseAndActiveTrue(workId, subject, sort);
        }
        assignTaskService.assignForGrouping(papers, markerGroups, markSubject, null);
    }

    public void enterToScoreStage(MarkSubject markSubject) {
        Long workId = markSubject.getWorkId();
        Subject subject = markSubject.getSubject();
        List<MarkUser> markers = markUserRepo.findByWorkIdAndSubjectAndRole(workId, subject, Role.MARKER);
        List<MarkUser> levelMarkers = markers.stream().filter(m -> m.getMarkRight() == MarkRight.ALLOW_ALL || m.getMarkRight() == MarkRight.ALLOW_SCORING).collect(Collectors.toList());
        if (levelMarkers.size() == 0) {
            statusMap.put(markSubject.getId(), false);
            throw new RuntimeException("没有设定评卷员");
        }
        int count = paperRepo.countByWorkIdAndSubjectAndLevelIsNullAndIsMissingFalseAndActiveTrueAndBatchNoNotNullAndTest(workId, subject, 0);
        if (count > 0) {
            statusMap.put(markSubject.getId(), false);
            throw new RuntimeException("没有分档完成");
        }
        this.isPtFull(workId, markSubject);
        List<MarkerGroup> markerGroups = markerGroupRepo.findByWorkIdAndSubject(workId, subject);
        if (markerGroups.size() == 0) {
            statusMap.put(markSubject.getId(), false);
            throw new RuntimeException("评卷员没有进行分组");
        }
        markSubject.setAllLevel(true);
        assignTaskService.assignForGroupingScore(markerGroups, markSubject);
    }

    @Transactional
    public void enterScoreStage(MarkSubject markSubject, List<TaskPublishSetting> taskList, Object questionId) throws Exception {
        Long workId = markSubject.getWorkId();
        Subject subject = markSubject.getSubject();
        List<MarkUser> markers = markUserRepo.findByWorkIdAndSubjectAndRole(workId, subject, Role.MARKER);
        List<MarkUser> levelMarkers = markers.stream().filter(m -> m.getMarkRight() == MarkRight.ALLOW_ALL || m.getMarkRight() == MarkRight.ALLOW_SCORING).collect(Collectors.toList());
        if (levelMarkers.size() == 0) {
            statusMap.put(markSubject.getId(), false);
            throw new RuntimeException("没有设定评卷员");
        }
        int count = paperRepo.countByWorkIdAndSubjectAndLevelIsNullAndIsMissingFalseAndActiveTrueAndBatchNoNotNullAndTest(workId, subject, 0);
        if (count > 0) {
            statusMap.put(markSubject.getId(), false);
            throw new RuntimeException("没有分档完成");
        }
        this.isPtFull(workId, markSubject);
        List<MarkerGroup> markerGroups = markerGroupRepo.findByWorkIdAndSubject(workId, subject);
        if (markerGroups.size() == 0) {
            statusMap.put(markSubject.getId(), false);
            throw new RuntimeException("评卷员没有进行分组");
        }

        for (MarkerGroup markerGroup : markerGroups) {
            if(markerGroup.getMarkers().size() == 0){
                statusMap.put(markSubject.getId(), false);
                throw new RuntimeException("分组里没有评卷员");
            }
        }

        //校验发布任务数量
        for (TaskPublishSetting taskPublishSetting : taskList) {
            if (Objects.nonNull(taskPublishSetting.getTaskCount()) && taskPublishSetting.getTaskCount() > 0 && taskPublishSetting.getWaitCount() < taskPublishSetting.getTaskCount()) {
                statusMap.put(markSubject.getId(), false);
                throw new RuntimeException(taskPublishSetting.getCode() + "档位本次任务数量必须小于等于未评数量");
            }
        }
        //已发布任务是否都已完成
        int waitCount = paperRepo.countByWorkIdAndSubjectAndScoreBatchNoIsNotNullAndScoreIsNull(workId, subject);
        if (waitCount > 0) {
            statusMap.put(markSubject.getId(), false);
            throw new RuntimeException("没有打分完成");
        }

        //总的发布任务数
        int totalTaskCount = taskList.stream().map(m->{
            if(Objects.isNull(m.getTaskCount())){
                m.setTaskCount(0);
            }
            return m;
        }).mapToInt(TaskPublishSetting::getTaskCount).sum();

        Sort sort = new Sort("questionId", "level");
        List<Paper> papers;
        //questionId为空，为所有考区
        if (Objects.isNull(questionId)) {
            int totalCount = taskList.stream().mapToInt(TaskPublishSetting::getTotalCount).sum();
            int successCount = taskList.stream().mapToInt(TaskPublishSetting::getSuccessCount).sum();
            papers = paperRepo.findByWorkIdAndSubjectAndIsMissingFalseAndActiveTrueAndScoreBatchNoIsNull(workId, subject, sort);
            if (successCount > 0) {
                statusMap.put(markSubject.getId(), false);
                throw new RuntimeException("单考区发布过任务，不能再发布所有考区任务");
            } else if (totalTaskCount - totalCount != 0) {
                statusMap.put(markSubject.getId(), false);
                throw new RuntimeException("选择所有考区时，要发布所有任务");
            }
        } else {
            Long questionId0 = Long.valueOf(questionId.toString());
//            papers = paperRepo.findByWorkIdAndQuestionIdAndSubjectAndIsMissingFalseAndActiveTrueAndScoreBatchNoIsNull(workId, questionId0, subject, sort);
            papers = new ArrayList<>();
            for (TaskPublishSetting taskPublishSetting : taskList) {
                if(taskPublishSetting.getTaskCount() == 0){
                    continue;
                }
                List<Paper> paperList = paperRepo.findByWorkIdAndQuestionIdAndSubjectAndLevelAndIsMissingFalseAndActiveTrueAndScoreBatchNoIsNull(workId, questionId0, subject, taskPublishSetting.getCode(),  sort);
                List<Paper> subPaperList = paperList.subList(0, taskPublishSetting.getTaskCount());
                papers.addAll(subPaperList);
            }
        }
//        papers = papers.subList(0, totalTaskCount);

        assignTaskService.assignForGrouping(papers, markerGroups, markSubject, taskList);

        //保存发布数据
        int max = taskPublishSettingRepo.maxPublishCount(workId, subject.name());
        long scoreBatchNo = papers.get(0).getScoreBatchNo();
        List<TaskPublishSetting> taskListAll = taskPublishSettingRepo.findByWorkIdAndSubjectAndPublishCount(workId, subject.name(), max);
        if (Objects.isNull(questionId)) {
            Map<String, TaskPublishSetting> map = taskList.stream().collect(Collectors.toMap(TaskPublishSetting::getCode, p -> p));
            List<TaskPublishSetting> finalList = taskListAll.stream().map(m -> {
                TaskPublishSetting taskPublishSetting = new TaskPublishSetting();
                taskPublishSetting.setWorkId(workId);
                taskPublishSetting.setQuestionId(m.getQuestionId());
                taskPublishSetting.setSubject(subject.name());
                taskPublishSetting.setCode(m.getCode());
                taskPublishSetting.setTotalCount(m.getTotalCount());
                taskPublishSetting.setSuccessCount(m.getTotalCount());
                taskPublishSetting.setWaitCount(0);
                taskPublishSetting.setSortRule(map.get(m.getCode()).getSortRule());
                taskPublishSetting.setDisplayNumber(map.get(m.getCode()).getDisplayNumber());
                taskPublishSetting.setTaskCount(0);
                taskPublishSetting.setBatchNo(scoreBatchNo);
                taskPublishSetting.setPublishCount(max + 1);
                return taskPublishSetting;
            }).collect(Collectors.toList());
            taskPublishSettingRepo.save(finalList);
        } else {
            Long questionId0 = Long.valueOf(questionId.toString());
            List<TaskPublishSetting> finalList = taskListAll.stream().map(m -> {
                TaskPublishSetting taskPublishSetting = new TaskPublishSetting();
                taskPublishSetting.setId(null);
                taskPublishSetting.setWorkId(m.getWorkId());
                taskPublishSetting.setQuestionId(m.getQuestionId());
                taskPublishSetting.setSubject(m.getSubject());
                taskPublishSetting.setCode(m.getCode());
                taskPublishSetting.setSuccessCount(m.getSuccessCount());
                taskPublishSetting.setTotalCount(m.getTotalCount());
                taskPublishSetting.setWaitCount(m.getWaitCount());
                taskPublishSetting.setSortRule(m.getSortRule());
                taskPublishSetting.setTaskCount(0);
                taskPublishSetting.setPublishCount(max + 1);
                taskPublishSetting.setBatchNo(scoreBatchNo);
                for (TaskPublishSetting tps : taskList) {
                    if (m.getQuestionId().equals(questionId0) && m.getCode().equals(tps.getCode())) {
                        taskPublishSetting.setSuccessCount(tps.getSuccessCount() + tps.getTaskCount());
                        taskPublishSetting.setWaitCount(tps.getTotalCount() - taskPublishSetting.getSuccessCount());
                        taskPublishSetting.setSortRule(tps.getSortRule());
                        taskPublishSetting.setDisplayNumber(tps.getDisplayNumber());
                        taskPublishSetting.setTaskCount(0);
                    }
                }
                return taskPublishSetting;
            }).collect(Collectors.toList());
            taskPublishSettingRepo.save(finalList);
        }

    }

    /**
     * @param workId
     * @param markSubject
     */
    private void isPtFull(Long workId, MarkSubject markSubject) {
        //控制分档比例
        List<Level> levels = levelRepo.findByWorkId(workId);
        for (Level targetLevel : levels) {
            int pt = targetLevel.getPt();
            long count = paperRepo.countByWorkIdAndSubjectAndLevel(workId, markSubject.getSubject(), targetLevel.getCode());
            long total = paperRepo.countByWorkIdAndSubject(workId, markSubject.getSubject());

            if ((count * 1.0D) / total * 1.0D > pt / 100.D) {
                statusMap.put(markSubject.getId(), false);
                throw new RuntimeException(targetLevel.getCode() + "档已满，占比总阀值已达" + pt + "%。");
            }
            //判断考点阀值是否已满
            int kdpt = targetLevel.getKdpt();
            List<ExamQuestion> examQuestions = examQuestionRepo.findByWorkIdAndSubject(workId, markSubject.getSubject());
            for (ExamQuestion examQuestion : examQuestions) {
                long kdcount = paperRepo.countByWorkIdAndSubjectAndQuestionIdAndLevel(workId, markSubject.getSubject(), examQuestion.getId(), targetLevel.getCode());
                long kdtotal = paperRepo.countByWorkIdAndSubjectAndQuestionId(workId, markSubject.getSubject(), examQuestion.getId());
                if ((kdcount * 1.0D) / kdtotal * 1.0D > kdpt / 100.D) {
                    statusMap.put(markSubject.getId(), false);
                    throw new RuntimeException(targetLevel.getCode() + "档已满，考点阀值已达" + kdpt + "%。");
                }
            }
        }
    }

    /**
     * 进入到抽查阶段
     *
     * @param markSubject
     */
    private void enterInspectStage(MarkSubject markSubject) {
        // TODO: 2017/10/11
        Long workId = markSubject.getWorkId();
        Subject subject = markSubject.getSubject();
//        List<MarkUser> checkers = markUserRepo.findByWorkIdAndSubjectAndRole(workId, subject, Role.INSPECTOR);
//        if (checkers.size() == 0) {
//            statusMap.put(markSubject.getId(), false);
//            throw new RuntimeException("没有设定复评专家");
//        }

    }

    /**
     * 重置所有评卷数据，回到INIT状态
     *
     * @param markSubject
     * @param stage       重置的阶段
     * @param force       是否强制重置，如果为false，当有评卷记录时，不可重置，如果为true，不论有无评卷记录，删除所有数据
     */
    @Transactional
    public void reset(MarkSubject markSubject, MarkStage stage, boolean force) {
        Subject subject = markSubject.getSubject();
        Long workId = markSubject.getWorkId();
        markTaskRepo.deleteByWorkIdAndSubjectAndStage(workId, subject, markSubject.getStage());
        markSubject.setStage(stage);
        markSubjectRepo.save(markSubject);
    }

    /**
     * 分档进度查询
     *
     * @param markSubject
     */
    public LevleProgressDTO progress(MarkSubject markSubject) {
        Long workId = markSubject.getWorkId();
        Subject subject = markSubject.getSubject();
        //已评任务数
        int successCount = paperRepo.countByWorkIdAndSubjectAndLevelNotNullAndIsMissingFalseAndActiveTrueAndTest(workId, subject, 0);
        //所有任务数(查询所有有效试卷)
        int totalCount = paperRepo.countByWorkIdAndSubjectAndIsMissingFalseAndTest(workId, subject, 0);

        BigDecimal waitTotal = BigDecimal.valueOf(totalCount).subtract(BigDecimal.valueOf(successCount));
        //进度
        BigDecimal progress = BigDecimal.ZERO.compareTo(BigDecimal.valueOf(totalCount)) == 0 ? BigDecimal.ZERO : BigDecimal.valueOf(successCount).multiply(BigDecimal.valueOf(100)).divide(BigDecimal.valueOf(totalCount), 2, BigDecimal.ROUND_HALF_UP);

        LevleProgressDTO progressDTO = new LevleProgressDTO();
        progressDTO.setSuccessCount(successCount);
        progressDTO.setTotalCount(totalCount);
        progressDTO.setWaitCount(waitTotal.intValue());
        progressDTO.setProgress(progress.doubleValue());

        return progressDTO;
    }

    /**
     * 分档进度查询
     *
     * @param markSubject
     */
    public List scoreProgress(MarkSubject markSubject, Long questionId) {
        /*List<TaskPublishSetting> publishSettings = taskPublishSettingRepo.findByWorkIdAndSubject(markSubject.getWorkId(), markSubject.getSubject().name());
        if (publishSettings != null && publishSettings.size() > 0) {
            int maxCount = taskPublishSettingRepo.maxPublishCount(markSubject.getWorkId(), markSubject.getSubject().name());
            return taskPublishSettingRepo.findByWorkIdAndSubjectAndPublishCount(markSubject.getWorkId(), markSubject.getSubject().name(), maxCount);
        }*/

        Integer maxCount = taskPublishSettingRepo.maxPublishCount(markSubject.getWorkId(), markSubject.getSubject().name());
        if (maxCount != null && maxCount.intValue() >= 0) {
            List settingList = null;
            //单个考区
            if (questionId != null) {
                settingList = taskPublishSettingRepo.findByWorkIdAndQuestionIdAndSubjectAndPublishCount(markSubject.getWorkId(), questionId, markSubject.getSubject().name(), maxCount);
                return settingList;
            }
            //所有考区
            else {
                List<Object[]> settingList1 = taskPublishSettingRepo.findAllByWorkIdAndSubjectAndPublishCount(markSubject.getWorkId(), markSubject.getSubject().name(), maxCount);
                List<TaskPublishSetting> taskPublishSettings = new ArrayList<>();
                settingList1.forEach(m->{
                    TaskPublishSetting taskPublishSetting = new TaskPublishSetting();
                    taskPublishSetting.setWorkId(Long.valueOf(m[0].toString()));
                    taskPublishSetting.setSubject(String.valueOf(m[1]));
                    taskPublishSetting.setCode(String.valueOf(m[2]));
                    taskPublishSetting.setTotalCount(Integer.valueOf(m[3].toString()));
                    taskPublishSetting.setSuccessCount(Integer.valueOf(m[4].toString()));
                    taskPublishSetting.setWaitCount(Double.valueOf(m[5].toString()).intValue());
                    taskPublishSettings.add(taskPublishSetting);
                });
                return taskPublishSettings;
            }
        }
        return null;
    }


    /**
     * 分档进度查询
     *
     * @param markSubject
     */
    public List<LevleProgressDTO> areaProgress(MarkSubject markSubject) {
        Long workId = markSubject.getWorkId();
        Subject subject = markSubject.getSubject();

        List<LevleProgressDTO> list = new ArrayList<>();
        List<ExamQuestion> examQuestions = examQuestionRepo.findByWorkIdAndSubject(workId, markSubject.getSubject());
        for (ExamQuestion examQuestion : examQuestions) {
            //已评任务数
            int areaSuccessCount = paperRepo.countByWorkIdAndSubjectAndLevelNotNullAndIsMissingFalseAndActiveTrueAndTestAndQuestionId(workId, subject, 0, examQuestion.getId());
            //所有任务数(查询所有有效试卷)
            int areaTotalCount = paperRepo.countByWorkIdAndSubjectAndIsMissingFalseAndTestAndQuestionId(workId, subject, 0, examQuestion.getId());

            BigDecimal areaWaitTotal = BigDecimal.valueOf(areaTotalCount).subtract(BigDecimal.valueOf(areaSuccessCount));
            //进度
            BigDecimal areaProgress = BigDecimal.ZERO.compareTo(BigDecimal.valueOf(areaTotalCount)) == 0 ? BigDecimal.ZERO : BigDecimal.valueOf(areaSuccessCount).multiply(BigDecimal.valueOf(100)).divide(BigDecimal.valueOf(areaTotalCount), 2, BigDecimal.ROUND_HALF_UP);

            LevleProgressDTO areaProgressDTO = new LevleProgressDTO();
            areaProgressDTO.setSuccessCount(areaSuccessCount);
            areaProgressDTO.setTotalCount(areaTotalCount);
            areaProgressDTO.setWaitCount(areaWaitTotal.intValue());
            areaProgressDTO.setProgress(areaProgress.doubleValue());
            areaProgressDTO.setAreaName(examQuestion.getAreaName());
            areaProgressDTO.setQuestionId(examQuestion.getId());
            list.add(areaProgressDTO);
        }

        if (examQuestions != null && examQuestions.size() > 1) {
            //已评任务数
            int successCount = paperRepo.countByWorkIdAndSubjectAndLevelNotNullAndIsMissingFalseAndActiveTrueAndTest(workId, subject, 0);
            //所有任务数(查询所有有效试卷)
            int totalCount = paperRepo.countByWorkIdAndSubjectAndIsMissingFalseAndTest(workId, subject, 0);

            BigDecimal waitTotal = BigDecimal.valueOf(totalCount).subtract(BigDecimal.valueOf(successCount));
            //进度
            BigDecimal progress = BigDecimal.ZERO.compareTo(BigDecimal.valueOf(totalCount)) == 0 ? BigDecimal.ZERO : BigDecimal.valueOf(successCount).multiply(BigDecimal.valueOf(100)).divide(BigDecimal.valueOf(totalCount), 2, BigDecimal.ROUND_HALF_UP);

            LevleProgressDTO progressDTO = new LevleProgressDTO();
            progressDTO.setSuccessCount(successCount);
            progressDTO.setTotalCount(totalCount);
            progressDTO.setWaitCount(waitTotal.intValue());
            progressDTO.setProgress(progress.doubleValue());
            progressDTO.setAreaName("所有考区");
            progressDTO.setQuestionId(null);
            list.add(progressDTO);
        }
        return list;
    }

}
