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

import cn.com.qmth.stmms.ms.commons.threadPool.MyThreadPool;
import cn.com.qmth.stmms.ms.commons.utils.SqlUtil;
import cn.com.qmth.stmms.ms.core.cache.ParamCache;
import cn.com.qmth.stmms.ms.core.domain.Level;
import cn.com.qmth.stmms.ms.core.domain.MarkStage;
import cn.com.qmth.stmms.ms.core.domain.MarkSubject;
import cn.com.qmth.stmms.ms.core.domain.Student;
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.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.assembler.LevelStatAssembler;
import cn.com.qmth.stmms.ms.marking.assembler.MarkerAssembler;
import cn.com.qmth.stmms.ms.marking.assembler.QuestionStatAssembler;
import cn.com.qmth.stmms.ms.marking.dto.*;
import javassist.bytecode.stackmap.BasicBlock;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

/**
 * 评卷中，评卷员的相关数据api
 * Created by zhengmin on 2016/10/14.
 */
@RestController
@RequestMapping("api/markers")
public class MakrerApi {
    private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(MakrerApi.class);

    @Autowired
    private MarkUserRepo markUserRepo;

    @Autowired
    private MarkTaskRepo markTaskRepo;

    @Autowired
    private MarkerAssembler markerAssembler;

    @Autowired
    private QuestionStatAssembler questionStatAssembler;

    @Autowired
    private MarkSubjectRepo markSubjectRepo;

    @Autowired
    private LevelRepo levelRepo;

    @Autowired
    private LevelStatAssembler levelStatAssembler;

    @Autowired
    ExamQuestionRepo examQuestionRepo;

    @Autowired
    SqlUtil sqlUtil;

    @Autowired
    PaperRepo paperRepo;

    @Autowired
    StudentRepo studentRepo;

    /**
     * 评卷员信息
     *
     * @param markerId 评卷员用户id
     * @return
     */
    @RequestMapping(value = "{markerId}", method = RequestMethod.GET)
    public MarkerDTO getMarker(@PathVariable Long markerId) {
        MarkUser marker = markUserRepo.findOne(markerId);
        return markerAssembler.toDTO(marker);
    }

    /**
     * 更新默认显示试卷数量
     *
     * @param markerId 评卷员用户id
     * @return
     */
    @RequestMapping(value = "updateDisplayCount", method = RequestMethod.POST)
    public ResponseEntity getMarker(Long markerId, Integer displayCount) {
        MarkUser marker = markUserRepo.findOne(markerId);
        marker.setDisplayCount(displayCount);
        markUserRepo.saveAndFlush(marker);
        return new ResponseEntity(HttpStatus.OK);
    }

    /**
     * 评卷员列表
     *
     * @param workId  评卷工作id
     * @param subject 科目
     * @return
     */
    @RequestMapping(method = RequestMethod.GET)
    public List<MarkUser> list(@RequestParam Long workId,
                               @RequestParam Subject subject) {
        List<MarkUser> markUsers = markUserRepo.findByWorkIdAndSubjectAndRole(workId, subject, Role.MARKER);
        String markSubjectId = workId + "-" + subject.toString();
        MarkSubject markSubject = markSubjectRepo.findOne(markSubjectId);
        if (MarkStage.INIT == markSubject.getStage()) {
            markUsers = markUsers.stream().filter(m -> m.getMarkRight() == MarkRight.ALLOW_LEVELING || m.getMarkRight() == MarkRight.ALLOW_ALL).collect(Collectors.toList());
        } else if (MarkStage.LEVEL == markSubject.getStage()) {
            markUsers = markUsers.stream().filter(m -> m.getMarkRight() == MarkRight.ALLOW_SCORING || m.getMarkRight() == MarkRight.ALLOW_ALL).collect(Collectors.toList());
        }
        return markUsers;
    }

    @Autowired
    MyThreadPool myThreadPool;

    /**
     * 评卷员分档数量及占比数据
     *
     * @param marker     评卷员用户id
     * @param questionId 试题id
     * @return
     */
    @RequestMapping(value = "{marker}/stat/levels", method = RequestMethod.GET)
    public List<LevelStatDTO> levelStats(@PathVariable MarkUser marker, @RequestParam Long questionId) throws Exception {
        List<LevelStatDTO> levelStatDTOs = new ArrayList<>();
        MarkSubject markSubject = markSubjectRepo.findOne(marker.getWorkId() + "-" + marker.getSubject().toString());
        List<Level> levels = levelRepo.findByWorkId(markSubject.getWorkId());
        Map<String, Level> levelMap = levels.stream().collect(Collectors.toMap(Level::getCode, l -> l));
//        Long batchNo = paperRepo.findByQuestionId(questionId);
        Long batchNo = paperRepo.findMaxBatchNoByWorkIdAndSubject(marker.getWorkId(), marker.getSubject());
        Future future = myThreadPool.arbitratePoolTaskExecutor.submit(new Callable<Map<String, Long>>() {

            @Override
            public Map<String, Long> call() throws Exception {
                Map<String, Long> map = new HashMap<>();
                //当前老师当前批次试卷总数
                long kdtotal;
                if (ParamCache.paramMap.get(marker.getWorkId()).getLevelShowAllPaper() == 1) {
                    kdtotal = markTaskRepo.countByQuestionIdAll(questionId, marker.getId());
                } else {
                    kdtotal = markTaskRepo.countByQuestionId(questionId, batchNo, marker.getId());
                }
                //当前考区内试卷总数
                long total = paperRepo.countByWorkIdAndQuestionId(markSubject.getWorkId(), questionId);
                map.put("kdtotal", kdtotal);
                map.put("total", total);
                return map;
            }
        });
        //当前考区各档位定档数量
        paperRepo.countGroupByLevel(questionId)
                .forEach(o -> {
                    LevelStatDTO levelStatDTO = levelStatAssembler.toDTO(o);
                    levelStatDTO.setGcount(levelStatDTO.getCount());
                    if (Objects.isNull(levelStatDTO.getId())) {
                        //求任务数为null的条数
                        int count;
                        if (ParamCache.paramMap.get(marker.getWorkId()).getLevelShowAllPaper() == 1) {
                            count = markTaskRepo.countByQuestionIdAndMarkerIdAndStageAndResultIsNullAndIsMissingAll(questionId, marker.getId(), MarkStage.LEVEL.ordinal(), false);
                        } else {
                            count = markTaskRepo.countByQuestionIdAndMarkerIdAndStageAndResultIsNullAndIsMissing(questionId, marker.getId(), MarkStage.LEVEL.ordinal(), false, batchNo);
                        }
                        //查询当前老师打回个数
                        int rejectCount = markTaskRepo.countByQuestionIdAndMarkerIdAndStageAndIsRejectedTrueAndIsMissing(questionId, marker.getId(), MarkStage.LEVEL.ordinal(), false);
                        levelStatDTO.setCount(count);
                        levelStatDTO.setRejected(rejectCount);
                    }
                    levelStatDTOs.add(levelStatDTO);
                });
        for (Level level : levels) {
            //所有档位依次比较
            long count = levelStatDTOs.stream().filter(l -> String.valueOf(l.getId()).equals(level.getCode())).count();
            if (count == 0) {
                LevelStatDTO dto = new LevelStatDTO();
                dto.setId(level.getCode());
                dto.setCount(0);
                dto.setPercent(0.0);

                //当前老师当前档位评档次数(所有考试)
//                int countNew;
//                if (ParamCache.paramMap.get(marker.getWorkId()).getLevelShowAllPaper() == 1) {
////                    countNew = markTaskRepo.countByQuestionIdAndStageAndResultAndIsMissingAll(questionId, MarkStage.LEVEL.ordinal(), level.getCode(), false, marker.getId());
//                } else {
//                    countNew = markTaskRepo.countByQuestionIdAndStageAndResultAndIsMissing(questionId, MarkStage.LEVEL.ordinal(), level.getCode(), false, batchNo, marker.getId());
//                }
//                dto.setCount(countNew);
                levelStatDTOs.add(dto);
            }
        }
        long kdtotal = 0L, total = 0L;
        if (Objects.nonNull(future) && Objects.nonNull(future.get())) {
            Map<String, Long> map = (Map<String, Long>) future.get();
            kdtotal = map.get("kdtotal");
            total = map.get("total");
        }
//        //当前老师当前试卷的评档次数(不分档位)
//        long kdtotal = markTaskRepo.countByQuestionId(questionId, batchNo, marker.getId());
//        //当前老师所有的评档次数(不分档位)
//        long total = paperRepo.countByWorkIdAndQuestionId(markSubject.getWorkId(), questionId);

        long finalKdtotal = kdtotal;
        long finalTotal = total;
        levelStatDTOs.forEach(o -> {
            if (o.getId() != null) {
                //当前老师各档位数量
                int countNew;
                if (ParamCache.paramMap.get(marker.getWorkId()).getLevelShowAllPaper() == 1) {
//                            count = markTaskRepo.countByQuestionIdAndStageAndResultAndIsMissingAll(questionId, MarkStage.LEVEL.ordinal(), levelStatDTO.getId().toString(), false, marker.getId());
                    countNew = markTaskRepo.countByQuestionIdAndMarkerIdAndStageAndResultAll(questionId, marker.getId(), MarkStage.LEVEL.ordinal(), String.valueOf(o.getId()));
                } else {
//                            count = markTaskRepo.countByQuestionIdAndStageAndResultAndIsMissing(questionId, MarkStage.LEVEL.ordinal(), levelStatDTO.getId().toString(), false, batchNo, marker.getId());
                    countNew = markTaskRepo.countByQuestionIdAndMarkerIdAndStageAndResult(questionId, marker.getId(), MarkStage.LEVEL.ordinal(), String.valueOf(o.getId()), batchNo);
                }
                o.setCount(countNew);
                //该档位考区内已定档数量
                long gcountNew = paperRepo.countByWorkIdAndSubjectAndQuestionIdAndLevel(marker.getWorkId(), markSubject.getSubject(), questionId, String.valueOf(o.getId()));
                o.setGcount((int) gcountNew);

                o.setPt(levelMap.get(o.getId()).getPt());
                o.setKdpt(levelMap.get(o.getId()).getKdpt());
                o.setCount(Objects.isNull(o.getCount()) ? 0 : o.getCount());
                double p = finalKdtotal == 0 ? 0 : (double) o.getCount() / finalKdtotal * 100;
                BigDecimal bd = new BigDecimal(p).setScale(3, RoundingMode.HALF_EVEN);
                o.setPercent(bd.doubleValue());

                o.setGcount(Objects.isNull(o.getGcount()) ? 0 : o.getGcount());
                double gp = finalTotal == 0 ? 0 : (double) o.getGcount() / finalTotal * 100;
                BigDecimal gbd = new BigDecimal(gp).setScale(3, RoundingMode.HALF_EVEN);
                o.setGpercent(gbd.doubleValue());
//                int count;
//                if (ParamCache.paramMap.get(marker.getWorkId()).getLevelShowAllPaper() == 1) {
//                    count = markTaskRepo.countByQuestionIdAndMarkerIdAndStageAndResultAll(questionId, marker.getId(), MarkStage.LEVEL.ordinal(), o.getId().toString());
//                } else {
//                    count = markTaskRepo.countByQuestionIdAndMarkerIdAndStageAndResult(questionId, marker.getId(), MarkStage.LEVEL.ordinal(), o.getId().toString(), batchNo);
//                }
//                o.setPercent(count == 0 ? 0 : o.getPercent());
//                o.setCount(count);
            }
        });
        Collections.sort(levelStatDTOs, (o1, o2) -> {
            if (o1.getId() == null || o2.getId() == null) {
                return 1;
            }
            return o1.getId().toString().compareTo(o2.getId().toString());
        });
        return levelStatDTOs;
    }

    /**
     * 评卷员打分数量
     *
     * @param marker     评卷员用户id
     * @param questionId 试题id
     * @return
     */
    @RequestMapping(value = "{marker}/stat/scores", method = RequestMethod.GET)
    public List<LevelStatDTO> scoreStats(@PathVariable MarkUser marker, @RequestParam Long questionId) throws Exception {
        List<LevelStatDTO> levelStatDTOs = new ArrayList<>();
        MarkSubject markSubject = markSubjectRepo.findOne(marker.getWorkId() + "-" + marker.getSubject().toString());
        List<Level> levels = levelRepo.findByWorkId(markSubject.getWorkId());
        Map<String, Level> levelMap = levels.stream().collect(Collectors.toMap(Level::getCode, l -> l));
//        Long batchNo = paperRepo.findScoreBatchNoByQuestionId(questionId);
        Long batchNo = paperRepo.findMaxScoreBatchNoByWorkIdAndSubject(marker.getWorkId(), marker.getSubject());
        Future future = myThreadPool.arbitratePoolTaskExecutor.submit(new Callable<Map<String, Long>>() {

            @Override
            public Map<String, Long> call() throws Exception {
                Map<String, Long> map = new HashMap<>();
                //当前老师当前试卷的评档次数(不分档位)
                long kdtotal = markTaskRepo.countScoreByQuestionId(questionId, batchNo, marker.getId());
                //当前老师所有的评档次数(不分档位)
                long total = paperRepo.countByWorkIdAndQuestionId(markSubject.getWorkId(), questionId);
                map.put("kdtotal", kdtotal);
                map.put("total", total);
                return map;
            }
        });
        LevelStatDTO levelStatDTO = new LevelStatDTO();
        //求任务数为null的条数
        int totalCount = markTaskRepo.countScoreByQuestionIdAndMarkerIdAndStageAndResultIsNullAndIsMissing(questionId, marker.getId(), MarkStage.SCORE.ordinal(), false, batchNo);
        levelStatDTO.setCount(totalCount);
        //查询改档
        int shiftCount = markTaskRepo.countShiftByQuestionIdAndMarkerIdAndStageAndResultIsNullAndIsMissing(questionId, marker.getId(), MarkStage.LEVEL.ordinal(), false);
        levelStatDTO.setShift(shiftCount);
        //查询改档打分
        int shiftScoreCount = markTaskRepo.countShiftScoreByQuestionIdAndMarkerIdAndStageAndResultIsNullAndIsMissing(questionId, marker.getId(), MarkStage.SCORE.ordinal(), false);
        levelStatDTO.setShiftScore(shiftScoreCount);
        levelStatDTOs.add(levelStatDTO);

        for (Level level : levels) {
            //所有档位依次比较
            long count = levelStatDTOs.stream().filter(l -> String.valueOf(l.getId()).equals(level.getCode())).count();
            if (count == 0) {
                LevelStatDTO dto = new LevelStatDTO();
                dto.setId(level.getCode());
                dto.setCount(0);
                dto.setPercent(0.0);

                //当前老师当前档位评档次数(所有考试)
                int countNew;
                if (ParamCache.paramMap.get(marker.getWorkId()).getScoreShowAllPaper() == 1) {
                    countNew = markTaskRepo.countScoreByQuestionIdAndStageAndResultAndIsMissingAll(questionId, MarkStage.SCORE.ordinal(), level.getCode(), false, marker.getId());
                } else {
                    countNew = markTaskRepo.countScoreByQuestionIdAndStageAndResultAndIsMissing(questionId, MarkStage.SCORE.ordinal(), level.getCode(), false, batchNo, marker.getId());
                }
                dto.setCount(countNew);
                levelStatDTOs.add(dto);
            }
        }
        long kdtotal = 0L, total = 0L;
        if (Objects.nonNull(future) && Objects.nonNull(future.get())) {
            Map<String, Long> map = (Map<String, Long>) future.get();
            kdtotal = map.get("kdtotal");
            total = map.get("total");
        }

        long finalKdtotal = kdtotal;
        long finalTotal = total;
        levelStatDTOs.forEach(o -> {
            if (o.getId() != null) {
                o.setPt(levelMap.get(o.getId()).getPt());
                o.setKdpt(levelMap.get(o.getId()).getKdpt());
                o.setCount(Objects.isNull(o.getCount()) ? 0 : o.getCount());
//                double p = (double) o.getCount() / finalKdtotal;
//                BigDecimal bd = new BigDecimal(p).setScale(3, RoundingMode.HALF_EVEN);
                o.setPercent(0D);

                o.setGcount(Objects.isNull(o.getGcount()) ? 0 : o.getGcount());
                double gp = (double) o.getGcount() / finalTotal;
                BigDecimal gbd = new BigDecimal(gp).setScale(3, RoundingMode.HALF_EVEN);
                o.setGpercent(gbd.doubleValue());

                int count;
                if(ParamCache.paramMap.get(marker.getWorkId()).getScoreShowAllPaper() == 1){
                    count = markTaskRepo.countScoreByQuestionIdAndMarkerIdAndStageAndResultAll(questionId, marker.getId(), MarkStage.SCORE.ordinal(), o.getId().toString());
                } else {
                    count = markTaskRepo.countScoreByQuestionIdAndMarkerIdAndStageAndResult(questionId, marker.getId(), MarkStage.SCORE.ordinal(), o.getId().toString(), batchNo);
                }
                o.setPercent(count == 0 ? 0 : o.getPercent());
                o.setCount(count);
            }
        });
        return levelStatDTOs;
    }

    /**
     * 各试题统计数据
     *
     * @param marker 评卷员用户id
     * @return
     */
    @RequestMapping(value = "{marker}/stat/questions", method = RequestMethod.GET)
    public List<QuestionStatDTO> questions(@PathVariable MarkUser marker) {
        List<QuestionStatDTO> questionStatDTOs = new ArrayList<>();
        List<Object[]> qStats = null;
        MarkSubject markSubject = markSubjectRepo.findOne(marker.getWorkId() + "-" + marker.getSubject().toString());
        if (markSubject.getStage() == MarkStage.SCORE) {
            qStats = markTaskRepo.countGroupByQuestion(marker.getId(), markSubject.getStage().ordinal());
        } else {
            qStats = markTaskRepo.countGroupByQuestion(marker.getId(), markSubject.getStage().ordinal(), markSubject.getTest());
        }
        if (qStats != null) {
            for (Object[] objects : qStats) {
                QuestionStatDTO dto = questionStatAssembler.toDTO(objects);
                questionStatDTOs.add(dto);
            }
        }
        return questionStatDTOs;
    }

    /**
     * 各评卷员评卷进度、考区评卷进度
     *
     * @return
     */
    @RequestMapping(value = "/stat/progress", method = RequestMethod.GET)
    public Map markProgress(@RequestParam Long workId, @RequestParam Subject subject) {
        Map<String, Object> objectMap = new HashMap<>();
        MarkSubject markSubject = markSubjectRepo.findOne(workId + "-" + subject.toString());

        //总体进度
        if (markSubject.getStage().name() == MarkStage.INIT.name()) {
            List<Student> students = studentRepo.findByWorkIdAndTest(workId, String.valueOf(TrialEnum.DEFAULT.getId()));
            long stuTotalCount = students.stream().count();
            long stuAbsentCount = students.stream().filter(s -> s.isAbsent()).count();
            long c = 0L;
            for (Student student : students) {
                String[] uploadStatus = student.getUploadStatus().split(",");
                for (String s : uploadStatus) {
                    if ("1".equals(s.split(":")[1])) {
                        if (subject.name().equals(s.split(":")[0])) {
                            ++c;
                        }
                    }
                }
            }

            LevleProgressDTO progressDTO = new LevleProgressDTO();
            progressDTO.setSuccessCount((int) c);
            progressDTO.setTotalCount((int) stuTotalCount);
            progressDTO.setWaitCount((int) (stuTotalCount - c));
            BigDecimal progress = stuTotalCount == 0 ? new BigDecimal("0") : new BigDecimal(c * 100).divide(new BigDecimal(stuTotalCount), 2, BigDecimal.ROUND_HALF_UP);
            progressDTO.setProgress(progress.doubleValue());
            objectMap.put("totalProgress", progressDTO);
        } else {
            //已评任务数
            int successCount = 0;
            if (markSubject.getStage().name() == MarkStage.LEVEL.name()) {
                successCount = paperRepo.countByWorkIdAndSubjectAndLevelNotNullAndIsMissingFalseAndActiveTrueAndTest(workId, subject, 0);
            }
            if (markSubject.getStage().name() == MarkStage.SCORE.name()) {
                successCount = paperRepo.countByWorkIdAndSubjectAndScoreNotNullAndIsMissingFalseAndActiveTrueAndTest(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());
            objectMap.put("totalProgress", progressDTO);
        }


        //考区进度
        List<Object[]> areas;
        if (markSubject.getStage().name() == MarkStage.SCORE.name()) {
            areas = markTaskRepo.listGroupByAreaName(workId, markSubject.getSubject().name());
        } else {
            areas = markTaskRepo.listGroupByAreaName(workId, markSubject.getSubject().name(), markSubject.getTest());
        }
        if (areas != null) {
            List<QuestionStatDTO> questionStatDTOs = new ArrayList<>();
            for (Object[] objects : areas) {
                QuestionStatDTO dto = questionStatAssembler.toProgressDTO(objects);
                questionStatDTOs.add(dto);
            }
            objectMap.put("areaProgress", questionStatDTOs);
        }

        //科组长
        List<MarkUser> markUser = markUserRepo.findByWorkIdAndSubjectAndRole(workId, subject, Role.MARK_LEADER);
        //仲裁数量
        int arbitrate = paperRepo.countByWorkIdAndSubjectAndIsArbitratedTrue(workId, subject);
        if (markUser != null && markUser.size() > 0) {
            Map map = new HashMap();
            map.put("loginName", markUser.get(0).getLoginName());
            map.put("name", markUser.get(0).getName());
            map.put("arbitrated", arbitrate);
            objectMap.put("kzz", map);
        }

        //各评卷员评卷进度
        List<Object[]> qStats;
        Long batchNo;
        if (markSubject.getStage().name() == MarkStage.SCORE.name()) {
            batchNo = paperRepo.findMaxScoreBatchNoByWorkIdAndSubject(workId, markSubject.getSubject());
            qStats = markTaskRepo.listGroupByQuestionAndMarkerAndScoreBatchNo(workId, markSubject.getSubject().name(), markSubject.getStage().ordinal(), batchNo);
        } else {
            batchNo = paperRepo.findMaxBatchNoByWorkIdAndSubject(workId, markSubject.getSubject());
            qStats = markTaskRepo.listGroupByQuestionAndMarkerAndBatchNo(workId, markSubject.getSubject().name(), markSubject.getStage().ordinal(), markSubject.getTest(), batchNo);
        }
        if (qStats != null) {
            List<MarkQuestionStatDTO> questionStatDTOs = new ArrayList<>();
            for (Object[] objects : qStats) {
                MarkQuestionStatDTO dto = questionStatAssembler.toMarkProgressDTO(objects, workId, subject);
                questionStatDTOs.add(dto);
            }
            objectMap.put("markerProgress", questionStatDTOs);
        }
        return objectMap;
    }

}
