package cn.com.qmth.stmms.admin.exam;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import cn.com.qmth.stmms.admin.vo.MarkerVO;
import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
import cn.com.qmth.stmms.biz.exam.model.Marker;
import cn.com.qmth.stmms.biz.exam.query.MarkerSearchQuery;
import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
import cn.com.qmth.stmms.biz.exam.service.ExamService;
import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
import cn.com.qmth.stmms.biz.exam.service.MarkGroupService;
import cn.com.qmth.stmms.biz.exam.service.MarkerService;
import cn.com.qmth.stmms.biz.file.service.FileService;
import cn.com.qmth.stmms.biz.lock.LockService;
import cn.com.qmth.stmms.biz.mark.model.Task;
import cn.com.qmth.stmms.biz.mark.model.TrialLibrary;
import cn.com.qmth.stmms.biz.mark.query.MarkLibrarySearchQuery;
import cn.com.qmth.stmms.biz.mark.service.MarkLibraryService;
import cn.com.qmth.stmms.biz.mark.service.TaskService;
import cn.com.qmth.stmms.biz.mark.service.TrialService;
import cn.com.qmth.stmms.biz.mark.thread.MarkQualityThread;
import cn.com.qmth.stmms.biz.user.model.User;
import cn.com.qmth.stmms.biz.user.service.UserService;
import cn.com.qmth.stmms.common.annotation.Logging;
import cn.com.qmth.stmms.common.annotation.RoleRequire;
import cn.com.qmth.stmms.common.domain.WebUser;
import cn.com.qmth.stmms.common.enums.LibraryStatus;
import cn.com.qmth.stmms.common.enums.LockType;
import cn.com.qmth.stmms.common.enums.LogType;
import cn.com.qmth.stmms.common.enums.MarkStatus;
import cn.com.qmth.stmms.common.enums.Role;
import cn.com.qmth.stmms.common.utils.RequestUtils;

@Controller("markQualityController")
@RequestMapping("/admin/exam/quality")
public class MarkQualityController extends BaseExamController {

    protected static Logger log = LoggerFactory.getLogger(MarkQualityController.class);

    @Autowired
    private MarkGroupService groupService;

    @Autowired
    private MarkerService markerService;

    @Autowired
    private LockService lockService;

    @Qualifier("task-executor")
    @Autowired
    private AsyncTaskExecutor taskExecutor;

    @Autowired
    private ExamSubjectService subjectService;

    @Autowired
    private MarkLibraryService libraryService;

    @Autowired
    private ExamQuestionService questionService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private TrialService trialService;

    @Autowired
    private ExamService examService;

    @Autowired
    private UserService userService;

    @Autowired
    private FileService fileService;

    @Logging(menu = "质量监控查询", type = LogType.QUERY)
    @RequestMapping
    public String list(Model model, HttpServletRequest request, MarkerSearchQuery query) {
        int examId = getSessionExamId(request);
        WebUser wu = RequestUtils.getWebUser(request);
        List<ExamSubject> subjectList = getExamSubject(examId, wu);
        if (subjectList.isEmpty()) {
            return "redirect:/admin/exam/mark";
        }
        query.setExamId(examId);
        query.orderById();
        if (StringUtils.isBlank(query.getSubjectCode()) && !subjectList.isEmpty()) {
            query.setSubjectCode(subjectList.get(0).getCode());
        }
        List<MarkGroup> groupList = groupService.findByExamAndSubject(examId, query.getSubjectCode());
        if (query.getSubjectCode() != null) {
            query = markerService.findByQuery(query);
            model.addAttribute(
                    "running",
                    lockService.isLocked(LockType.BATCH_QUALITY,
                            getLockKey(examId, query.getSubjectCode(), query.getGroupNumber())));
            for (Marker marker : query.getResult()) {
                marker.setUser(userService.findById(marker.getUserId()));
                MarkGroup group = groupService.findOne(examId, marker.getSubjectCode(), marker.getGroupNumber());
                group.setQuestionList(questionService.findByExamAndSubjectAndObjectiveAndGroupNumber(examId,
                        marker.getSubjectCode(), false, group.getNumber()));
                marker.setGroup(group);
            }
        }
        model.addAttribute("query", query);
        model.addAttribute("subjectList", subjectList);
        model.addAttribute("groupList", groupList);
        return "modules/exam/qualityList";
    }

    @Logging(menu = "重新计算质量监控", type = LogType.UPDATE)
    @RequestMapping("/update")
    public String update(HttpServletRequest request, RedirectAttributes redirectAttributes,
            @RequestParam String subjectCode, @RequestParam Integer groupNumber) {
        int examId = getSessionExamId(request);
        MarkGroup group = groupService.findOne(examId, subjectCode, groupNumber);
        if (group != null) {
            final String lockKey = getLockKey(examId, subjectCode, groupNumber);
            if (lockService.trylock(LockType.BATCH_QUALITY, lockKey)) {
                taskExecutor.submit(new MarkQualityThread(markerService.findByExamAndSubjectAndGroup(examId,
                        subjectCode, groupNumber), lockKey));
            }
            redirectAttributes.addAttribute("groupNumber", groupNumber);
        }
        redirectAttributes.addAttribute("subjectCode", subjectCode);
        return "redirect:/admin/exam/quality";
    }

    private String getLockKey(Integer examId, String subjectCode, Integer groupNumber) {
        return examId + "_" + subjectCode + "_" + groupNumber;
    }

    @Logging(menu = "查询给分曲线", type = LogType.QUERY)
    @RequestMapping("/chart")
    public String chart(HttpServletRequest request, Model model, @RequestParam String subjectCode,
            @RequestParam Integer groupNumber) {
        int examId = getSessionExamId(request);
        MarkGroup group = groupService.findOne(examId, subjectCode, groupNumber);
        if (group != null) {
            List<MarkerVO> list = new ArrayList<MarkerVO>();
            List<Marker> markers = markerService.findByExamAndSubjectAndGroup(examId, subjectCode, groupNumber);
            List<Double> scores = libraryService.findScore(examId, subjectCode, groupNumber, LibraryStatus.MARKED,
                    LibraryStatus.INSPECTED);
            for (Marker marker : markers) {
                List<Object[]> libraries = libraryService.findScoreCount(examId, subjectCode, groupNumber,
                        marker.getId(), LibraryStatus.MARKED, LibraryStatus.INSPECTED);
                Map<Double, Long> scoreCount = new HashMap<Double, Long>();
                for (Object[] array : libraries) {
                    Double score = (Double) array[0];
                    Long count = (Long) array[1];
                    scoreCount.put(score, count);
                }
                User user = userService.findById(marker.getUserId());
                MarkerVO vo = new MarkerVO();
                vo.setId(marker.getId());
                vo.setLoginName(user.getLoginName());
                vo.setName(user.getName());
                vo.setScoreCount(scoreCount);
                list.add(vo);
            }
            group.setQuestionList(questionService.findByExamAndSubjectAndObjectiveAndGroupNumber(examId, subjectCode,
                    false, group.getNumber()));
            model.addAttribute("scores", scores);
            model.addAttribute("markers", list);
            model.addAttribute("group", group);
        }
        model.addAttribute("subject", subjectService.find(examId, subjectCode));
        model.addAttribute("subjectCode", subjectCode);
        model.addAttribute("groupNumber", groupNumber);
        return "modules/exam/qualityChart";
    }

    @RequestMapping("/getChart")
    @ResponseBody
    public List<MarkerVO> getChart(HttpServletRequest request, @RequestParam String subjectCode,
            @RequestParam Integer groupNumber) {
        int examId = getSessionExamId(request);
        List<MarkerVO> list = new ArrayList<MarkerVO>();
        List<Marker> markers = markerService.findByExamAndSubjectAndGroup(examId, subjectCode, groupNumber);
        for (Marker marker : markers) {
            List<Object[]> libraries = libraryService.findScoreCount(examId, subjectCode, groupNumber, marker.getId(),
                    LibraryStatus.MARKED, LibraryStatus.INSPECTED);
            MarkLibrarySearchQuery query = new MarkLibrarySearchQuery();
            query.setMarkerId(marker.getId());
            query.addStatus(LibraryStatus.MARKED);
            query.addStatus(LibraryStatus.INSPECTED);
            long totalCount = libraryService.countByQuery(query);
            Map<Double, Double> scorePercent = new HashMap<Double, Double>();
            for (Object[] array : libraries) {
                Double score = (Double) array[0];
                Long count = (Long) array[1];
                double percent = 0;
                if (totalCount != 0) {
                    percent = count * 100 / totalCount;
                }
                scorePercent.put(score, percent);
            }
            User user = userService.findById(marker.getUserId());
            MarkerVO vo = new MarkerVO();
            vo.setId(marker.getId());
            vo.setLoginName(user.getLoginName());
            vo.setName(user.getName());
            vo.setScorePercent(scorePercent);
            list.add(vo);
        }
        return list;
    }

    @Logging(menu = "质量监控查询给分记录详情", type = LogType.QUERY)
    @RequestMapping(value = "/history", method = RequestMethod.POST)
    @ResponseBody
    @RoleRequire({ Role.SCHOOL_ADMIN, Role.SUBJECT_HEADER, Role.COLLEGE_ADMIN })
    public List<Task> getTask(HttpServletRequest request, @RequestParam Integer markerId,
            @RequestParam Double markerScore, @RequestParam(required = false) Integer pageNumber,
            @RequestParam(required = false) Integer pageSize) {
        Marker marker = markerService.findById(markerId);
        List<Task> list = new ArrayList<>();
        MarkGroup group = groupService.findOne(marker.getExamId(), marker.getSubjectCode(), marker.getGroupNumber());
        if (group != null && group.getStatus() != MarkStatus.TRIAL) {
            // 正评查找已给分的评卷任务
            MarkLibrarySearchQuery query = new MarkLibrarySearchQuery();
            query.setExamId(marker.getExamId());
            query.setSubjectCode(marker.getSubjectCode());
            query.setMarkerId(marker.getId());
            query.addStatus(LibraryStatus.MARKED);
            query.addStatus(LibraryStatus.INSPECTED);
            query.setGroupNumber(marker.getGroupNumber());
            query.setMarkerScore(markerScore);
            if (pageNumber != null) {
                query.setPageNumber(pageNumber);
            }
            if (pageSize != null) {
                query.setPageSize(pageSize);
            }
            query.orderByMarkerTimeDesc();

            list = taskService.findByQuery(query);
        } else if (group != null && group.getStatus() == MarkStatus.TRIAL) {
            // 试评查找给分历史记录
            List<TrialLibrary> historyList = new ArrayList<TrialLibrary>();
            historyList = trialService.findHistory(marker.getExamId(), marker.getSubjectCode(),
                    marker.getGroupNumber(), marker.getId(), pageNumber, pageSize, null, markerScore);
            for (TrialLibrary library : historyList) {
                Task task = taskService.build(library);
                list.add(task);
            }
        }
        return list;
    }
}
