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

import cn.com.qmth.stmms.ms.core.domain.*;
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.marking.assembler.LevelStatAssembler;
import cn.com.qmth.stmms.ms.marking.assembler.QuestionStatAssembler;
import cn.com.qmth.stmms.ms.marking.dto.LevelStatDTO;
import cn.com.qmth.stmms.ms.marking.dto.LevleProgressDTO;
import cn.com.qmth.stmms.ms.marking.dto.QuestionStatDTO;
import cn.com.qmth.stmms.ms.marking.service.StageControlService;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 评卷科目数据api
 * Created by zhengmin on 2016/10/10.
 */
@RestController
@RequestMapping("api/marksubjects")
public class MarkSubjectApi {

    @Autowired
    private PaperRepo paperRepo;

    @Autowired
    private MarkSubjectRepo markSubjectRepo;

    @Autowired
    private QuestionStatAssembler questionStatAssembler;

    @Autowired
    private LevelRepo levelRepo;

    @Autowired
    private LevelStatAssembler levelStatAssembler;

    @Autowired
    private MarkerGroupRepo markerGroupRepo;

    @Autowired
    private MarkUserRepo markUserRepo;

    @Autowired
    private StageControlService stageControlService;

    @Autowired
    private TaskPublishSettingRepo taskPublishSettingRepo;

    /**
     * 查询所有科目状态
     *
     * @param workId
     * @return
     */
    @RequestMapping(value = "getAllSubjectStage/{workId}", method = RequestMethod.GET)
    public List<MarkSubject> getAllSubjectStage(@PathVariable Long workId) {
        return markSubjectRepo.findAllByWorkIdAndEnableTrue(workId);
    }

    /**
     * 当个评卷科目信息
     *
     * @param markSubjectId 评卷科目id
     * @return
     */
    @RequestMapping(value = "{markSubjectId}", method = RequestMethod.GET)
    public MarkSubject get(@PathVariable String markSubjectId) {
        MarkSubject subject = markSubjectRepo.findOne(markSubjectId);
        return subject;
    }

    /**
     * 该评卷科目下的评卷员列表
     *
     * @param markSubject 评卷科目id
     * @return
     */
    @RequestMapping(value = "{markSubject}/markers", method = RequestMethod.GET)
    public List<MarkUser> markUsers(@PathVariable MarkSubject markSubject) {
        List<MarkUser> markUsers = markUserRepo.findByWorkIdAndSubjectAndRole(markSubject.getWorkId(), markSubject.getSubject(), Role.MARKER);
        if (MarkStage.LEVEL == markSubject.getStage()) {
            markUsers = markUsers.stream().filter(m -> m.getMarkRight() == MarkRight.ALLOW_LEVELING || m.getMarkRight() == MarkRight.ALLOW_ALL).collect(Collectors.toList());
        } else if (MarkStage.SCORE == markSubject.getStage()) {
            markUsers = markUsers.stream().filter(m -> m.getMarkRight() == MarkRight.ALLOW_SCORING || m.getMarkRight() == MarkRight.ALLOW_ALL).collect(Collectors.toList());
        }
        return markUsers;
    }

    /**
     * 该评卷科目的试题统计信息
     *
     * @param markSubject 评卷科目id
     * @return
     */
    @RequestMapping(value = "{markSubject}/stat/questions", method = RequestMethod.GET)
    public List<QuestionStatDTO> questions(@PathVariable MarkSubject markSubject) {
        List<QuestionStatDTO> questionStatDTOs = new ArrayList<>();
        List<Object[]> qStats = null;
        if (markSubject.getStage() == MarkStage.LEVEL) {
            qStats = paperRepo.countGroupByQuestionForLevel(markSubject.getWorkId(), markSubject.getSubject().toString(), markSubject.getTest());
        } else {
            qStats = paperRepo.countGroupByQuestionForScore(markSubject.getWorkId(), markSubject.getSubject().toString());
        }
        for (Object[] objects : qStats) {
            QuestionStatDTO dto = questionStatAssembler.toDTO(objects);
            questionStatDTOs.add(dto);
        }
        return questionStatDTOs;
    }

    /**
     * 该评卷科目的分档统计信息
     *
     * @param markSubject 评卷科目id
     * @param questionId  试题id
     * @return
     */
    @RequestMapping(value = "{markSubject}/stat/levels", method = RequestMethod.GET)
    public List<LevelStatDTO> levelStat(HttpServletRequest request, @PathVariable MarkSubject markSubject, @RequestParam Long questionId) {
        List<LevelStatDTO> levelStatDTOs = new ArrayList<>();
        paperRepo.countGroupByLevelAll(questionId, markSubject.getTest())
                .forEach(o -> levelStatDTOs.add(levelStatAssembler.toDTO(o)));
        List<Level> levels = levelRepo.findByWorkId(markSubject.getWorkId());
        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);
                levelStatDTOs.add(dto);
            }
        }
        //当前考区总数
        long total = paperRepo.countByWorkIdAndQuestionId(markSubject.getWorkId(), questionId);
        //所有考区总数
        long gtotal = paperRepo.countByWorkIdAndSubject(markSubject.getWorkId(), markSubject.getSubject());
        levelStatDTOs.forEach(o -> {
            if (o.getId() != null) {
                //当前考区档位占比
                double p = total == 0 ? 0 : (double) o.getCount() / total * 100;
                BigDecimal bd = new BigDecimal(p).setScale(3, RoundingMode.HALF_EVEN);
                o.setPercent(bd.doubleValue());
                //考区阈值
                Level level = levels.stream().filter(l -> l.getCode().equals(o.getId())).collect(Collectors.toList()).get(0);
                o.setKdpt(level.getKdpt());
                //所有考区档位数量
                long gcount = paperRepo.countByWorkIdAndSubjectAndLevel(markSubject.getWorkId(), markSubject.getSubject(), String.valueOf(o.getId()));
                o.setGcount((int) gcount);
                //所有考区档位占比
                double gp = gtotal == 0 ? 0 : (double) o.getGcount() / gtotal * 100;
                BigDecimal gbd = new BigDecimal(gp).setScale(3, RoundingMode.HALF_EVEN);
                o.setGpercent(gbd.doubleValue());
                o.setPt(level.getPt());
            }
        });
        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 markSubject 评卷科目id
     * @param questionId  试题id
     * @return
     */
    @RequestMapping(value = "{markSubject}/stat/scores", method = RequestMethod.GET)
    public List<LevelStatDTO> scoreStat(HttpServletRequest request, @PathVariable MarkSubject markSubject, @RequestParam Long questionId) {
        List<LevelStatDTO> levelStatDTOs = new ArrayList<>();
        paperRepo.countScoreGroupByLevelAll(questionId, markSubject.getTest())
                .forEach(o -> levelStatDTOs.add(levelStatAssembler.toDTO(o)));
        List<Level> levels = levelRepo.findByWorkId(markSubject.getWorkId());
        for (Level level : levels) {
            //没有该档位，新增
            LevelStatDTO dto = new LevelStatDTO();
            dto.setId(level.getCode());
            dto.setCount(0);
            dto.setPercent(0.0);
            levelStatDTOs.add(dto);
        }
        levelStatDTOs.forEach(o -> {
            if (o.getId() != null) {
                int count = paperRepo.countByWorkIdAndSubjectAndQuestionIdAndLevelAndScoreNotNull(markSubject.getWorkId(), markSubject.getSubject(), questionId, String.valueOf(o.getId()));
                o.setCount(count);
                //所有考区已打分数量
                int gcount = paperRepo.countByWorkIdAndSubjectAndLevelAndScoreNotNull(markSubject.getWorkId(), markSubject.getSubject(), o.getId());
                o.setGcount(gcount);
            }
        });
        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 markSubject 评卷科目id
     * @return
     */
    @RequestMapping(value = "{markSubject}/markergroups", method = RequestMethod.GET)
    public List<MarkerGroup> getMarkerGroups(@PathVariable MarkSubject markSubject) {
        return markerGroupRepo.findByWorkIdAndSubject(markSubject.getWorkId(), markSubject.getSubject());
    }

    /**
     * 创建评卷组
     *
     * @param markSubject 评卷科目id
     * @param markerGroup 评卷组
     */
    @RequestMapping(value = "{markSubject}/markergroups", method = RequestMethod.POST)
    public MarkerGroup createMarkerGroup(@PathVariable MarkSubject markSubject, @RequestBody MarkerGroup markerGroup) {
        if (markerGroup.getMarkers().size() == 0) {
            throw new RuntimeException("不可创建空分组");
        }
        markerGroup.setWorkId(markSubject.getWorkId());
        markerGroup.setSubject(markSubject.getSubject());
        return markerGroupRepo.save(markerGroup);
    }

    /**
     * 修改评卷组名
     *
     * @param markSubject 评卷科目id
     * @param domain      评卷组id
     * @param markerGroup 评卷组
     */
    @RequestMapping(value = "{markSubject}/markergroups/{domain}", method = RequestMethod.PATCH)
    public void updateMarkerGroup(@PathVariable MarkSubject markSubject, @PathVariable MarkerGroup domain, @RequestBody MarkerGroup markerGroup) {
        domain.setName(markerGroup.getName());
        markerGroupRepo.save(markerGroup);
    }

    /**
     * 删除评卷组
     *
     * @param markSubject 评卷科目id
     * @param domain      评卷组id
     */
    @RequestMapping(value = "{markSubject}/markergroups/{domain}", method = RequestMethod.DELETE)
    public void removeMarkerGroup(@PathVariable MarkSubject markSubject, @PathVariable MarkerGroup domain) {
        markerGroupRepo.delete(domain);
    }

    /**
     * 单个评卷组信息
     *
     * @param markSubject 评卷科目id
     * @param domain      评卷组id
     * @return
     */
    @RequestMapping(value = "{markSubject}/markergroups/{domain}", method = RequestMethod.GET)
    public MarkerGroup getMarkerGroup(@PathVariable MarkSubject markSubject, @PathVariable MarkerGroup domain) {
        return domain;
    }

    /**
     * 为评卷组设置评卷员
     *
     * @param markSubject 评卷科目id
     * @param domain      评卷组id
     * @param markerIds   评卷员用户id数组
     */
    @RequestMapping(value = "{markSubject}/markergroups/{domain}/setmaker", method = RequestMethod.PATCH)
    public void setMaker(@PathVariable MarkSubject markSubject, @PathVariable MarkerGroup domain, @RequestParam Long... markerIds) {
        domain.setMarkers(new HashSet<MarkUser>());
        for (Long markerId : markerIds) {
            domain.addMarker(markUserRepo.findOne(markerId));
        }
        markerGroupRepo.save(domain);
    }

    /**
     * 是否可以进行打分任务投放
     *
     * @param markSubject
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "{markSubject}/canScore", method = RequestMethod.GET)
    public Boolean canScore(@PathVariable MarkSubject markSubject) {
        int count = paperRepo.countByWorkIdAndSubjectAndScoreBatchNoIsNotNullAndScoreIsNull(markSubject.getWorkId(), markSubject.getSubject());
        return count > 0 ? false : true;
    }

    /**
     * 是否可以进行打分任务全部考区发布
     *
     * @param markSubject
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "{markSubject}/canScoreAll", method = RequestMethod.GET)
    public Boolean canScoreAll(@PathVariable MarkSubject markSubject) {
        //查询pulish_count为1的，如果总数不等于成功数，则为单个考区发过任务的
        List<TaskPublishSetting> taskPublishSettings = taskPublishSettingRepo.findByWorkIdAndSubjectAndPublishCount(markSubject.getWorkId(), markSubject.getSubject().name(), 1);
        int totalTaskCount = taskPublishSettings.stream().mapToInt(TaskPublishSetting::getTotalCount).sum();
        int successTaskCount = taskPublishSettings.stream().mapToInt(TaskPublishSetting::getSuccessCount).sum();

        return totalTaskCount - successTaskCount > 0 ? false : true;
    }

    /**
     * 该评卷科目进入下一阶段
     *
     * @param markSubject 评卷科目id
     */
    @RequestMapping(value = "{markSubject}", method = RequestMethod.PATCH)
    public void goNext(@PathVariable MarkSubject markSubject, @RequestBody Map map) throws Exception {
        stageControlService.goNext(markSubject, map);
    }

    /**
     * 检查是否已分档完成
     */
    @RequestMapping(value = "{markSubject}/canLevel", method = RequestMethod.GET)
    public Boolean canLevel(@PathVariable MarkSubject markSubject) {
        int count = paperRepo.countByWorkIdAndSubjectAndLevelIsNullAndIsMissingFalseAndActiveTrueAndBatchNoNotNullAndTest(markSubject.getWorkId(), markSubject.getSubject(), 0);
        return count > 0 ? false : true;
    }


    /**
     * 打分任务发布
     *
     * @param markSubject 评卷科目id
     */
    @RequestMapping(value = "{markSubject}/publishScore", method = RequestMethod.POST)
    public void publishScore(@PathVariable MarkSubject markSubject, @RequestBody Map map) throws Exception {
        Object questionId = map.get("questionId");
        List<TaskPublishSetting> taskList = JSONObject.parseArray(JSONObject.toJSONString(map.get("taskList")), TaskPublishSetting.class);
        stageControlService.enterScoreStage(markSubject, taskList, questionId);
    }

    /**
     * 查询分档进度
     *
     * @param markSubject 评卷科目id
     */
    @RequestMapping(value = "{markSubject}/progress", method = RequestMethod.GET)
    public LevleProgressDTO progress(@PathVariable MarkSubject markSubject) {
        return stageControlService.progress(markSubject);
    }

    /**
     * 查询打分进度
     *
     * @param markSubject 评卷科目id
     */
    @RequestMapping(value = "{markSubject}/scoreProgress", method = RequestMethod.GET)
    public List scoreProgress(@PathVariable MarkSubject markSubject,@RequestParam(defaultValue = "") Long questionId) {
        return stageControlService.scoreProgress(markSubject, questionId);
    }

    /**
     * 分考区查询分档进度
     *
     * @param markSubject 评卷科目id
     */
    @RequestMapping(value = "{markSubject}/areaProgress", method = RequestMethod.GET)
    public List<LevleProgressDTO> areaProgress(@PathVariable MarkSubject markSubject) {
        return stageControlService.areaProgress(markSubject);
    }

    /**
     * 查询所有科目
     *
     * @param workId
     * @return
     */
    @RequestMapping(value = "{workId}/subjects", method = RequestMethod.GET)
    public List<MarkSubject> subjects(@PathVariable Long workId) {
        return markSubjectRepo.findAllByWorkId(workId);
    }

    /**
     * 更新科目状态
     *
     * @param markSubject 评卷科目id
     */
    @RequestMapping(value = "{markSubject}/updateEnable", method = RequestMethod.POST)
    public ResponseEntity updateEnable(@PathVariable MarkSubject markSubject) {
        //有采集数据，不能禁用
        List<Paper> papers = paperRepo.findByWorkIdAndSubject(markSubject.getWorkId(), markSubject.getSubject());
        if (papers != null && papers.size() > 0) {
            throw new RuntimeException("已有采集数据，不可" + (markSubject.isEnable() ? "禁用" : "启用"));
        }
        markSubject.setEnable(!markSubject.isEnable());
        markSubjectRepo.saveAndFlush(markSubject);
        return new ResponseEntity(HttpStatus.OK);
    }

    /**
     * 更新科目名称
     *
     * @param markSubject 评卷科目id
     */
    @RequestMapping(value = "{subjectId}/updateName", method = RequestMethod.POST)
    public ResponseEntity updateName(@PathVariable String subjectId, MarkSubject markSubject) {
        MarkSubject markSubjectT = markSubjectRepo.findOne(subjectId);
        //有采集数据，不能禁用
        List<Paper> papers = paperRepo.findByWorkIdAndSubject(markSubjectT.getWorkId(), markSubjectT.getSubject());
        if (papers != null && papers.size() > 0) {
            throw new RuntimeException("已有采集数据，不能修改科目名称");
        }
        markSubjectT.setName(markSubject.getName());
        markSubjectRepo.saveAndFlush(markSubjectT);
        return new ResponseEntity(HttpStatus.OK);
    }

}
