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

import cn.com.qmth.stmms.ms.commons.utils.SqlUtil;
import cn.com.qmth.stmms.ms.commons.web.PageableDTO;
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.task.MarkTask;
import cn.com.qmth.stmms.ms.core.domain.user.MarkUser;
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.ChangeLevelAssembler;
import cn.com.qmth.stmms.ms.marking.dto.ChangeLevelDTO;
import cn.com.qmth.stmms.ms.marking.service.MarkingService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/changelevel")
public class ChangeLevelApi {

    @Autowired
    private PaperRepo paperRepo;

    @Autowired
    private ChangeLevelRepo changeLevelRepo;

    @Autowired
    private MarkTaskRepo markTaskRepo;

    @Autowired
    private ChangeLevelAssembler changeLevelAssembler;

    @Autowired
    private MarkingService markingService;

    @Autowired
    private MarkLogRepo markLogRepo;

    @Autowired
    private WorkRepo workRepo;

    @Autowired
    MarkUserRepo markUserRepo;

    /**
     * 查询改档列表
     *
     * @param workId
     * @param questionId
     * @param subject
     * @param status
     * @return
     */
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public PageableDTO changeLevel(@RequestParam(required = false) Long workId,
                                   @RequestParam(required = false) Long questionId,
                                   @RequestParam(required = false) String subject,
                                   @RequestParam(required = false) String status,
                                   Pageable pageable) {
        List<ChangeLevelDTO> levelDTOs = new ArrayList<>();
        Specification<Paper> specification = (root, query, builder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (!StringUtils.isEmpty(workId)) {
                predicates.add(builder.equal(root.get("workId"), workId));
            }
            if (!StringUtils.isEmpty(questionId)) {
                List<Paper> papers = paperRepo.findByworkIdAndSubjectAndQuestionIdAndIsMissingAndTest(workId, Subject.valueOf(subject), questionId, false, TrialEnum.DEFAULT.ordinal());
//                predicates.add(builder.equal(root.get("areaCode"), areaCode));
                if(papers != null && papers.size() > 0) {
                    CriteriaBuilder.In<Object> in = builder.in(root.get("paperId"));
                    for (Paper paper : papers) {
                        in.value(paper.getId());
                    }
                    predicates.add(builder.and(builder.and(in)));
                }
            }
            if (!StringUtils.isEmpty(subject)) {
                predicates.add(builder.equal(root.get("subject"), subject));
            }
            if (!StringUtils.isEmpty(status) && !StringUtils.isEmpty(status)) {
                if (Objects.equals(status, "0")) {
                    predicates.add(builder.equal(root.get("auditStatus"), status));
                } else {
                    predicates.add(builder.notEqual(root.get("auditStatus"), 0));
                }

            }
            return builder.and(predicates.toArray(new Predicate[predicates.size()]));
        };

        Page<ChangeLevel> levels = changeLevelRepo.findAll(specification, pageable);

//        PageInfo<Map> pageInfo = sqlUtil.execSqlForListPageInfo(sql.toString(), pageable.getPageNumber(), pageable.getPageSize(), null);
        levels.getContent().forEach(m -> {
            levelDTOs.add(changeLevelAssembler.toDTO(m));
        });
        return new PageableDTO(levelDTOs, levels.getTotalElements(), levels.getTotalPages(), pageable.getPageNumber());
    }

    /**
     * 科组长改档申请
     *
     * @param markSubject
     * @param paperId
     * @param level
     * @return
     */
    @RequestMapping(value = "{markSubject}/changeLevel", method = RequestMethod.POST)
    @Transactional
    public ResponseEntity changeLevel(@PathVariable MarkSubject markSubject,
                                      @RequestParam Long paperId,
                                      @RequestParam String level,
                                      @RequestParam Long userId) {
        //只有打分阶段才能改档
        if (!Objects.equals(markSubject.getStage().name(), MarkStage.SCORE.name())) {
            throw new RuntimeException("只有打分阶段才允许改档");
        }
        Paper paper = paperRepo.findOne(paperId);
        MarkUser markUser = markUserRepo.findOne(userId);

        //
        ChangeLevel changeLevel = changeLevelRepo.findByWorkIdAndSubjectAndPaperId(markSubject.getWorkId(), markSubject.getSubject().name(), paperId);
        if (changeLevel == null) {
            changeLevel = new ChangeLevel();
            changeLevel.setWorkId(markSubject.getWorkId());
            changeLevel.setSubject(markSubject.getSubject().name());
            changeLevel.setPaperId(paperId);
            changeLevel.setOriginalLevel(paper.getLevel());
            changeLevel.setSuggestLevel(level);
            changeLevel.setAuditStatus(0);
            changeLevel.setCreateId(markUser.getId());
            changeLevel.setCreateDate(new Date());
        } else {
            changeLevel.setOriginalLevel(paper.getLevel());
            changeLevel.setSuggestLevel(level);
            changeLevel.setCreateId(markUser.getId());
            changeLevel.setCreateDate(new Date());
        }
        changeLevelRepo.save(changeLevel);

        //记录日志
        Work work = workRepo.findOne(paper.getWorkId());
        MarkLog markLog = new MarkLog(markUser.getId(), markUser.getName(), markUser.getRole(), markUser.getSubject(), paper.getExamNumber(), paper.getStudentName(), MarkLogOperType.CHANGE_LEVEL_APPLY.getId(), paper.getWorkId(), paper.getId(), MarkStage.SCORE, changeLevel.getOriginalLevel(), changeLevel.getSuggestLevel(), null, work.getName());
        markLogRepo.save(markLog);

        return new ResponseEntity(HttpStatus.OK);
    }

    /**
     * 科组长改档审核
     *
     * @param id
     * @param auditStatus
     * @return
     */
    @RequestMapping(value = "/changeLevelAudit", method = RequestMethod.POST)
    @Transactional
    public ResponseEntity changeLevelAudit(@RequestParam Long id,
                                           @RequestParam Integer auditStatus,
                                           @RequestParam Long userId) {
        ChangeLevel changeLevel = changeLevelRepo.findOne(id);
        changeLevel.setAuditStatus(auditStatus);
        changeLevelRepo.save(changeLevel);
        //同意
        if(auditStatus == 1) {
            Paper paper = paperRepo.findOne(changeLevel.getPaperId());
            //重置分数
            paper.setScore(null);
            //状态设置
            paper.setShift(true);
            paper.setShiftScore(true);
            List<MarkTask> markTasks = markTaskRepo.findByPaperIdAndStage(paper.getId(), MarkStage.LEVEL);
            List<String> ranges = markTasks.stream().map(m->m.getMarkerId().toString()).collect(Collectors.toList());
            markingService.reject(paper, changeLevel.getSuggestLevel(), String.join(",", ranges));

            //重置已经打分的数据
            List<MarkTask> markTasksScore = markTaskRepo.findByPaperIdAndStage(paper.getId(), MarkStage.SCORE);
            if (markTasksScore != null && markTasksScore.size() > 0){
                markTasksScore.forEach(o-> o.setResult(null));
                markTaskRepo.save(markTasksScore);
            }

            //记录日志
            MarkUser markUser = markUserRepo.findOne(userId);
            Work work = workRepo.findOne(paper.getWorkId());
            MarkLog markLog = new MarkLog(markUser.getId(), markUser.getName(), markUser.getRole(), markUser.getSubject(), paper.getExamNumber(), paper.getStudentName(), MarkLogOperType.CHANGE_LEVEL_AGREE.getId(), paper.getWorkId(), paper.getId(), MarkStage.SCORE, changeLevel.getOriginalLevel(), changeLevel.getSuggestLevel(), null, work.getName());
            markLogRepo.save(markLog);
        }
        return new ResponseEntity(HttpStatus.OK);
    }

}
