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

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
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.dto.RejectResult;
import cn.com.qmth.stmms.admin.utils.ExportInspectExcel;
import cn.com.qmth.stmms.admin.vo.InspectedSubjectVO;
import cn.com.qmth.stmms.biz.config.service.impl.SystemCache;
import cn.com.qmth.stmms.biz.exam.bean.ExamStudentVo;
import cn.com.qmth.stmms.biz.exam.bean.InspectWorkVo;
import cn.com.qmth.stmms.biz.exam.model.Exam;
import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
import cn.com.qmth.stmms.biz.exam.query.ExamStudentSearchQuery;
import cn.com.qmth.stmms.biz.exam.query.InspectQuery;
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.ExamStudentService;
import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
import cn.com.qmth.stmms.biz.exam.service.InspectHistoryService;
import cn.com.qmth.stmms.biz.exam.service.InspectedService;
import cn.com.qmth.stmms.biz.exam.service.query.ExamSubjectSearchQuery;
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.service.MarkService;
import cn.com.qmth.stmms.biz.mark.service.TaskService;
import cn.com.qmth.stmms.biz.school.model.School;
import cn.com.qmth.stmms.biz.school.service.SchoolService;
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.ExamType;
import cn.com.qmth.stmms.common.enums.LockType;
import cn.com.qmth.stmms.common.enums.LogType;
import cn.com.qmth.stmms.common.enums.Role;
import cn.com.qmth.stmms.common.enums.SelectiveStatus;
import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
import cn.com.qmth.stmms.common.utils.ExportExcel;
import cn.com.qmth.stmms.common.utils.RequestUtils;
import net.sf.json.JSONObject;

@Controller("inspectedController")
@RequestMapping("/admin/exam/inspected")
public class InspectedController extends BaseExamController {

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

    @Autowired
    private ExamStudentService studentService;

    @Autowired
    private InspectedService inspectedService;

    @Autowired
    private InspectHistoryService inspectHistoryService;

    @Autowired
    private ExamQuestionService questionService;

    @Autowired
    private FileService fileService;

    @Autowired
    private LockService lockService;

    @Autowired
    private MarkService markService;

    @Autowired
    private ExamService examService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private ExamSubjectService subjectService;

    @Autowired
    private SystemCache systemCache;

    @Autowired
    private SchoolService schoolService;

    @Value("${slice.split.config}")
    private String splitConfig;

    public static final String UN_SELECTIVE_SCORE = "-1";

    @RequestMapping(value = "/list")
    public String list(Model model, HttpServletRequest request, InspectQuery query,
            @RequestParam(required = false) SubjectiveStatus status,
            @RequestParam(required = false) SelectiveStatus selectiveStatus,
            @RequestParam(required = false) Integer mainNumber, @RequestParam(required = false) Double mainStartScore,
            @RequestParam(required = false) Double mainEndScore) {
        int examId = getSessionExamId(request);
        Exam exam = examService.findById(examId);
        if (ExamType.MULTI_MEDIA.equals(exam.getType())) {
            return "modules/exam/permission";
        }
        WebUser wu = RequestUtils.getWebUser(request);
        query.setExamId(examId);
        List<ExamSubject> subjectList = getExamSubject(examId, wu);
        if (StringUtils.isBlank(query.getSubjectCode()) && wu.getRole() != Role.SCHOOL_ADMIN) {
            List<String> subjectCodeIn = new ArrayList<String>();
            subjectList.forEach(e -> subjectCodeIn.add(e.getCode()));
            query.setSubjectCodeIn(StringUtils.join(subjectCodeIn, ","));
        }
        List<ExamStudentVo> list = inspectedService.findByQuery(query, status, mainNumber, mainStartScore,
                mainEndScore, selectiveStatus);
        for (ExamStudentVo e : list) {
            e.setSubjectiveScoreList(e.getSubjectiveScoreList().replace(UN_SELECTIVE_SCORE, "/"));
            // e.setInspectHistoryList(inspectHistoryService.findByStudentIdLimit3(e.getId()));
        }
//        int maxInspectRound = 1;
//        if (list != null && list.size() > 0) {
//            Set<String> subjectCodes = list.stream().map(e -> e.getSubjectCode()).collect(Collectors.toSet());
//            maxInspectRound = subjectService.findMaxInspectRound(examId, subjectCodes);
//            inspectedService.fillInspectHistoryMap(list, maxInspectRound);
//        }
      int maxInspectCount = 0;
      if (list != null && list.size() > 0) {
          Set<Integer> stuIds = list.stream().map(e -> e.getId()).collect(Collectors.toSet());
          maxInspectCount = inspectHistoryService.findMaxInspectCount(stuIds);
          inspectedService.fillInspectHistoryMap(list);
      }
        Integer totalCount = inspectedService.countByQuery(query, status, mainNumber, mainStartScore, mainEndScore,
                selectiveStatus);
//        Integer inspectCount = inspectedService.needInspectCount(query, mainNumber, mainStartScore, mainEndScore,
//                selectiveStatus);
        query.setResult(list);
        query.setTotalCount(totalCount);
        model.addAttribute("query", query);
        model.addAttribute("maxInspectRound", maxInspectCount);
        model.addAttribute("inspectCount", totalCount);
        model.addAttribute("questionList",
                questionService.findMainByExamAndSubjectAndObjective(examId, query.getSubjectCode(), false));
        model.addAttribute("mainNumber", mainNumber);
        model.addAttribute("mainStartScore", mainStartScore);
        model.addAttribute("mainEndScore", mainEndScore);
        model.addAttribute("subjectList", subjectList);
        model.addAttribute("statusList", SubjectiveStatus.getOptionList());
        model.addAttribute("selectiveStatusList", SelectiveStatus.getOptionList());
        model.addAttribute("status", status);
        model.addAttribute("selectiveStatus", selectiveStatus);
        model.addAttribute("exam", exam);
        model.addAttribute("examFinish", checkFinish(exam));
        if (StringUtils.isNotBlank(query.getSubjectCode())) {
            ExamSubject es = subjectService.find(examId, query.getSubjectCode());
            if (inspectedService.inspectFinish(examId, query.getSubjectCode(), es.getInspectRound())) {
                model.addAttribute("showNextInspect", true);
            }
        }
        return "modules/exam/inspectedList";
    }

    private boolean checkFinish(Exam exam) {
        List<ExamSubject> list = subjectService.list(exam.getId());
        for (ExamSubject subject : list) {
            String meaages = subjectService.enableExport(exam, subject.getCode());
            if (meaages != null) {
                return false;
            }
        }
        return true;
    }

    @Logging(menu = "开始考生复核", type = LogType.QUERY)
    @RequestMapping(value = "/getTask", method = RequestMethod.POST)
    @ResponseBody
    public Task getTask(HttpServletRequest request, HttpServletResponse response, RedirectAttributes ra,
            InspectQuery query,
            @RequestParam(required = false, defaultValue = "false") SelectiveStatus selectiveStatus,
            @RequestParam(required = false) Integer mainNumber, @RequestParam(required = false) Double mainStartScore,
            @RequestParam(required = false) Double mainEndScore, @RequestParam(required = false) Double questionScore,
            @RequestParam(required = false) Integer studentId) {
        int examId = getSessionExamId(request);
        WebUser wu = RequestUtils.getWebUser(request);
        Exam exam = examService.findById(examId);
        Task task = null;
        if (studentId != null) {
            ExamStudent student = studentService.findById(studentId);
//            if (exam.getInspectUnrepeated() && inspectHistoryService.existByStudentIdAndUserId(studentId, wu.getId())) {
//                errMessage("考试已设置为全卷多次复核时不能为同一账号", response);
//                return null;
//            }
            releaseStudent(studentId);
            if (inspectedService.applyStudent(ExamStudentVo.of(student), wu.getId())) {
                task = taskService.build(student);
            }
        } else if (StringUtils.isNotBlank(query.getSecretNumber())) {
            ExamStudent student = studentService.findByExamIdAndSecretNumber(examId, query.getSecretNumber());
            if (student == null) {
                return null;
            }
//            if (exam.getInspectUnrepeated() && inspectHistoryService.existByStudentIdAndUserId(studentId, wu.getId())) {
//                errMessage("考试已设置为全卷多次复核时不能为同一账号", response);
//                return null;
//            }
            releaseStudent(student.getId());
            if (inspectedService.applyStudent(ExamStudentVo.of(student), wu.getId())) {
                task = taskService.build(student);
            }
        }else {
	        int retry = 1;
	        while (task == null) {
	            List<ExamStudentVo> list = new ArrayList<>();
	            // 需要判断评卷员是否绑定了机组
	            query.setExamId(examId);
	            query.setPageNumber(retry);
	            query.setPageSize(20);
	            List<ExamSubject> subjectList = getExamSubject(examId, wu);
	            if (StringUtils.isBlank(query.getSubjectCode()) && !subjectList.isEmpty()) {
	                query.setSubjectCode(subjectList.get(0).getCode());
	            }
	            query.setInspected(false);
	            query.setInspectUnrepeated(exam.getInspectUnrepeated());
	            query.setInspectorId(wu.getId());
	            list = inspectedService.findByQuery(query, SubjectiveStatus.MARKED, mainNumber, mainStartScore,
	                    mainEndScore, selectiveStatus);
	            if (list.isEmpty()) {
	                break;
	            }
	            for (ExamStudentVo student : list) {
	                if (inspectedService.applyStudent(student, wu.getId())) {
	                    task = taskService.build(ExamStudent.of(student));
	                    break;
	                }
	            }
	            if (task == null) {
	                retry++;
	            }
	        }
	    }
        if(task!=null) {
        	task.setInspectTime(null);
        }
        return task;
    }

    @Logging(menu = "考生评卷复核", type = LogType.UPDATE)
    @RequestMapping(value = "/save", method = RequestMethod.POST)
    @ResponseBody
    public Object save(HttpServletRequest request, @RequestParam Integer studentId) {
        WebUser wu = RequestUtils.getWebUser(request);
        JSONObject obj = new JSONObject();
        ExamStudent student = studentService.findById(studentId);
        if(student==null) {
        	obj.accumulate("success", false);
            obj.accumulate("message", "未找到考生信息");
            return obj;
        }
        try {
            lockService.watch(LockType.EXAM_SUBJECT, student.getExamId(), student.getSubjectCode());
            lockService.waitlock(LockType.STUDENT, studentId);
            if (inspectedService.inspect(student, wu.getId())) {
                inspectedService.releaseByStudent(student);
                obj.accumulate("success", true);
            } else {
                obj.accumulate("success", false);
                obj.accumulate("message", "无法确认，请刷新页面");
            }
        } catch (Exception e) {
            obj.accumulate("success", false);
            log.error("inspected save error", e);
        } finally {
            lockService.unlock(LockType.STUDENT, studentId);
            lockService.unwatch(LockType.EXAM_SUBJECT, student.getExamId(), student.getSubjectCode());
        }
        return obj;
    }

    @RequestMapping(value = "/clear", method = RequestMethod.POST)
    @ResponseBody
    @RoleRequire({ Role.SCHOOL_ADMIN, Role.SUBJECT_HEADER, Role.INSPECTOR, Role.COLLEGE_ADMIN })
    public JSONObject clear(HttpServletRequest request, @RequestParam(required = false) String subjectCode,
            @RequestParam(required = false) Integer studentId) {
        JSONObject obj = new JSONObject();
        if (studentId != null) {
            releaseStudent(studentId);
            obj.accumulate("success", true);
        } else if (subjectCode != null) {
            int examId = getSessionExamId(request);
            releaseUser(examId, subjectCode, RequestUtils.getWebUser(request).getId());
            obj.accumulate("success", true);
        } else {
            obj.accumulate("success", false);
        }
        return obj;
    }

    @Logging(menu = "取消复核", type = LogType.UPDATE)
    @RequestMapping(value = "/cancel", method = RequestMethod.POST)
    @ResponseBody
    @RoleRequire({ Role.SCHOOL_ADMIN, Role.SUBJECT_HEADER, Role.INSPECTOR, Role.COLLEGE_ADMIN })
    public JSONObject cancel(HttpServletRequest request, @RequestParam Integer studentId) {
        JSONObject obj = new JSONObject();
        ExamStudent student = studentService.findById(studentId);
        if(student==null) {
        	obj.accumulate("success", false);
            obj.accumulate("message", "未找到考生信息");
            return obj;
        }
        obj.accumulate("subjectCode", student.getSubjectCode());
        WebUser wu = RequestUtils.getWebUser(request);
        if (subjectCheck(student.getSubjectCode(), wu)) {
            try {
                lockService.watch(LockType.EXAM_SUBJECT, student.getExamId(), student.getSubjectCode());
                lockService.waitlock(LockType.STUDENT, studentId);
                if (inspectedService.cancelByStudent(studentId)) {
                    obj.accumulate("success", true);
                } else {
                    obj.accumulate("success", false);
                    obj.accumulate("message", "无法取消复核");
                }
            } catch (Exception e) {
                obj.accumulate("success", false);
                obj.accumulate("message", "取消复核失败");
                log.error("back inspected error", e);
            } finally {
                lockService.unlock(LockType.STUDENT, studentId);
                lockService.unwatch(LockType.EXAM_SUBJECT, student.getExamId(), student.getSubjectCode());
            }
        } else {
            obj.accumulate("success", false);
            obj.accumulate("message", "没有操作该评卷任务的权限");
        }
        return obj;
    }

    @Logging(menu = "再次复核", type = LogType.UPDATE)
    @RequestMapping(value = "nextround", method = RequestMethod.POST)
    @RoleRequire({ Role.SCHOOL_ADMIN, Role.SUBJECT_HEADER, Role.INSPECTOR, Role.COLLEGE_ADMIN })
    public String nextround(RedirectAttributes ra, HttpServletRequest request, @RequestParam String subjectCode) {
        int examId = getSessionExamId(request);
        ExamSubject es = subjectService.find(examId, subjectCode);
        lockService.waitlock(LockType.EXAM_SUBJECT, examId, subjectCode);
        try {
            if (!inspectedService.inspectFinish(examId, subjectCode, es.getInspectRound())) {
                ra.addFlashAttribute("errmsg", "该科目第" + es.getInspectRound() + "次复核还未完成");
                return "redirect:/admin/exam/inspected/list";
            }
            subjectService.nextInspectRound(examId, subjectCode);
            return "redirect:/admin/exam/inspected/list";
        } finally {
            lockService.unlock(LockType.EXAM_SUBJECT, examId, subjectCode);
        }
    }

    @Logging(menu = "打回", type = LogType.UPDATE)
    @RequestMapping(value = "/rejected", method = RequestMethod.POST)
    @ResponseBody
    @RoleRequire({ Role.SCHOOL_ADMIN, Role.SUBJECT_HEADER, Role.INSPECTOR, Role.COLLEGE_ADMIN })
    public JSONObject rejected(HttpServletRequest request, @RequestBody RejectResult rejectResult) {
        JSONObject obj = new JSONObject();
        ExamStudent student = studentService.findById(rejectResult.getStudentId());
        WebUser wu = RequestUtils.getWebUser(request);
        if (student == null) {
            obj.accumulate("success", false);
            obj.accumulate("message", "无法打回");
            return obj;
        }
        if (student.getSubjectiveStatus().equals(SubjectiveStatus.MARKED) && subjectCheck(student.getSubjectCode(), wu)) {
            try {
                lockService.watch(LockType.EXAM_SUBJECT, student.getExamId(), student.getSubjectCode());
                lockService.waitlock(LockType.STUDENT, student.getId());
                if (markService.rejectedStudent(student, rejectResult.getQuestionList(), wu.getId(),
                        rejectResult.getReason())) {
                    inspectedService.releaseByStudent(student);
                    obj.accumulate("success", true);
                } else {
                    obj.accumulate("success", false);
                    obj.accumulate("message", "无法打回");
                }
            } catch (Exception e) {
                obj.accumulate("success", false);
                obj.accumulate("message", "打回失败");
                log.error("back inspected error", e);
            } finally {
                lockService.unlock(LockType.STUDENT, student.getId());
                lockService.unwatch(LockType.EXAM_SUBJECT, student.getExamId(), student.getSubjectCode());
            }
        } else {
            obj.accumulate("success", false);
            obj.accumulate("message", "无法打回");
        }
        return obj;
    }

    @Logging(menu = "回看全卷复核任务", type = LogType.QUERY)
    @RequestMapping(value = "/getHistory", method = RequestMethod.POST)
    @ResponseBody
    public Object getHistory(HttpServletRequest request, @RequestParam String subjectCode,
            @RequestParam int pageNumber, @RequestParam int pageSize) throws Exception {
        int examId = getSessionExamId(request);
        WebUser wu = RequestUtils.getWebUser(request);
        List<Task> list = new ArrayList<>();
        ExamStudentSearchQuery query = new ExamStudentSearchQuery();
        query.setExamId(examId);
        query.setSubjectCode(subjectCode);
        query.setInspectorId(wu.getId());
        query.setInspected(null);
        query.setPageNumber(pageNumber);
        query.setPageSize(pageSize);
        query.orderByInspectTimeDesc();
        query = studentService.findByQuery(query);
        for (ExamStudent student : query.getResult()) {
            Task task = taskService.build(student);
            task.setPrevious(true);
            list.add(task);
        }
        return list;
    }

    @RequestMapping(value = "/getStatus", method = RequestMethod.POST)
    @ResponseBody
    public JSONObject status(HttpServletRequest request, InspectQuery query,
            @RequestParam(required = false) SelectiveStatus selectiveStatus,
            @RequestParam(required = false) Integer mainNumber, @RequestParam(required = false) Double mainStartScore,
            @RequestParam(required = false) Double mainEndScore, @RequestParam(required = false) Double questionScore) {
        JSONObject status = new JSONObject();
        int examId = getSessionExamId(request);
        query.setExamId(examId);
        List<Integer> ids = inspectedService.needInspectIds(query, mainNumber, mainStartScore, mainEndScore,
                selectiveStatus);
        status.accumulate("totalCount", ids.size());
        status.accumulate("studentIds", ids);
        status.accumulate("valid", true);
        return status;
    }

    @RequestMapping(value = "/getSetting", method = RequestMethod.POST)
    @ResponseBody
    public JSONObject getSetting(HttpServletRequest request, @RequestParam String subjectCode) {
        JSONObject setting = new JSONObject();
        WebUser wu = RequestUtils.getWebUser(request);
        int examId = getSessionExamId(request);
        Exam exam = examService.findById(examId);
        setting.accumulate("examType", exam.getType());
        setting.accumulate("fileServer", fileService.getFileServer());
        setting.accumulate("userName", wu.getName());
        setting.accumulate("splitConfig", getSplitConfig());
        setting.accumulate("inspectScroll", exam.getInspectScrollBottom());
        School school = schoolService.findById(exam.getSchoolId());
        setting.accumulate("doubleTrack", systemCache.isDoubleTrack() && school.isDoubleTrack());

        ExamSubject examSubject = subjectService.find(examId, subjectCode);
        JSONObject subject = new JSONObject();
        subject.accumulate("name", examSubject.getName());
        subject.accumulate("code", examSubject.getCode());
        examSubject.setPaperAnswerUrl(fileService);
        subject.accumulate("paperUrl", examSubject.getPaperUrl() == null ? "" : examSubject.getPaperUrl());
        subject.accumulate("answerUrl", examSubject.getAnswerUrl() == null ? "" : examSubject.getAnswerUrl());
        setting.accumulate("subject", subject);
        setting.accumulate("enableSplit",
                examSubject.getEnableSplit() == null ? exam.isEnableSplit() : examSubject.getEnableSplit());
        return setting;
    }

    private double[] getSplitConfig() {
        String strs[] = splitConfig.split(",");
        double[] config = new double[strs.length];
        for (int i = 0; i < strs.length; i++) {
            config[i] = Double.parseDouble(strs[i]);
        }
        return config;
    }

    private void releaseUser(Integer examId, String subjectCode, Integer userId) {
        try {
            lockService.waitlock(LockType.USER, userId);
            inspectedService.releaseByUserId(examId, subjectCode, userId);
        } catch (Exception e) {
            log.error("release user error", e);
        } finally {
            lockService.unlock(LockType.USER, userId);
        }
    }

    private void releaseStudent(Integer studentId) {
        try {
            lockService.waitlock(LockType.STUDENT, studentId);
            ExamStudent student = studentService.findById(studentId);
            inspectedService.releaseByStudent(student);
        } catch (Exception e) {
            log.error("release user error", e);
        } finally {
            lockService.unlock(LockType.STUDENT, studentId);
        }
    }

    @Logging(menu = "取消复核", type = LogType.UPDATE)
    @RequestMapping(value = "/batchCancel", method = RequestMethod.POST)
    @RoleRequire({ Role.SCHOOL_ADMIN, Role.SUBJECT_HEADER, Role.INSPECTOR, Role.COLLEGE_ADMIN })
    public String batchCancel(HttpServletRequest request, @RequestParam Integer[] ids) {
        WebUser wu = RequestUtils.getWebUser(request);
        // String subjectCode = "";
        for (Integer id : ids) {
            ExamStudent student = studentService.findById(id);
            // subjectCode = student.getSubjectCode();
            if (student != null && subjectCheck(student.getSubjectCode(), wu)) {
                try {
                    lockService.watch(LockType.EXAM_SUBJECT, student.getExamId(), student.getSubjectCode());
                    lockService.waitlock(LockType.STUDENT, student.getId());
                    inspectedService.cancelByStudent(id);
                } catch (Exception e) {
                    log.error("back inspected error", e);
                } finally {
                    lockService.unlock(LockType.STUDENT, student.getId());
                    lockService.unwatch(LockType.EXAM_SUBJECT, student.getExamId(), student.getSubjectCode());
                }
            }
        }
        return "redirect:/admin/exam/inspected/list";
    }

    private void subjectCodeQuery(ExamSubjectSearchQuery query, List<String> subjectCodeIn) {
        if (StringUtils.isEmpty(query.getCodeIn())) {
            query.setCodeIn(StringUtils.join(subjectCodeIn, ","));
        } else {
            Set<String> set = new HashSet<>();
            for (String c : query.getCodeIn().split(",")) {
                set.add(c);
            }
            set.addAll(subjectCodeIn);
            query.setCodeIn(StringUtils.join(set, ","));
        }
    }

    @Logging(menu = "成绩复核进度查询", type = LogType.QUERY)
    @RequestMapping(value = "/info")
    public String info(HttpServletRequest request, Model model, ExamSubjectSearchQuery query) {
        WebUser wu = RequestUtils.getWebUser(request);
        int examId = getSessionExamId(request);
        Exam exam = examService.findById(examId);
        query.setExamId(examId);
        Set<String> unFinishSet = studentService.findSubjectUnInspectedByExamId(examId);
        if (query.getFinished() != null) {
            String subjectCodeIn = StringUtils.join(unFinishSet, ",");
            if (query.getFinished()) {
                query.setCodeNotIn(subjectCodeIn);
            } else {
                query.setCodeIn(subjectCodeIn);
            }
        }
        // if (wu.isSubjectHeader()) {
        // String subjectCodeIn = StringUtils.join(wu.getSubjectCodeSet(), ",");
        // query.setCodeIn(subjectCodeIn);
        // }
        List<ExamSubject> subjectList = getExamSubject(examId, wu);
        if (StringUtils.isBlank(query.getCode()) && wu.getRole() != Role.SCHOOL_ADMIN) {
            List<String> subjectCodeIn = new ArrayList<String>();
            subjectList.forEach(e -> subjectCodeIn.add(e.getCode()));
            subjectCodeQuery(query, subjectCodeIn);
        }
        query = subjectService.findByQuery(query);
        if (unFinishSet.isEmpty() && query.getFinished() != null && !query.getFinished()) {
            query.setResult(new ArrayList<ExamSubject>());
        }

        List<InspectedSubjectVO> list = new LinkedList<InspectedSubjectVO>();
        for (ExamSubject subject : query.getResult()) {
            InspectedSubjectVO vo = new InspectedSubjectVO();
            vo.setSubject(subject);
            ExamStudentSearchQuery sQuery = new ExamStudentSearchQuery();
            sQuery.setExamId(examId);
            sQuery.setUpload(true);
            sQuery.setAbsent(false);
            sQuery.setBreach(false);
            sQuery.setSubjectCode(subject.getCode());
            long totalPaperCount = studentService.countByQuery(sQuery);
            vo.setTotalPaperCount(totalPaperCount);
            sQuery.setInspected(true);
            long inspectedCount = studentService.countByQuery(sQuery);
            vo.setInspectedCount(inspectedCount);
            sQuery.addStatus(SubjectiveStatus.MARKED);
            sQuery.setInspected(null);
            long totalCount = studentService.countByQuery(sQuery);
            vo.setTotalCount(totalCount);
            vo.setLeftCount(totalCount - inspectedCount);
            if (vo.getLeftCount() < 0) {
                vo.setLeftCount(0);
            }
            String percent = totalCount > 0 ? (new DecimalFormat("####.###")
                    .format(inspectedCount * 100.0 / totalCount) + "%") : "100%";
            vo.setPercent(percent);
            if (unFinishSet.contains(vo.getSubject().getCode())) {
                vo.setFinishCount(vo.getSubject().getInspectRound() - 1);
            } else {
                if (totalCount == 0) {
                    vo.setFinishCount(vo.getSubject().getInspectRound() - 1);
                } else {
                    vo.setFinishCount(vo.getSubject().getInspectRound());
                }
            }
            list.add(vo);
        }
        ExamStudentSearchQuery sQuery = new ExamStudentSearchQuery();
        sQuery.setExamId(examId);
        sQuery.setUpload(true);
        sQuery.setAbsent(false);
        sQuery.setBreach(false);
        sQuery.setInspected(true);
        long markedCount = studentService.countByQuery(sQuery);
        sQuery.setInspected(null);
        sQuery.addStatus(SubjectiveStatus.MARKED);
        long total = studentService.countByQuery(sQuery);
        model.addAttribute("unMarkedCount", total - markedCount);
        model.addAttribute("markedCount", markedCount);
        long subjectCount = subjectService.count(examId);
        model.addAttribute("unFinishCount", unFinishSet.size());
        model.addAttribute("finishCount", subjectCount - unFinishSet.size());
        model.addAttribute("resultList", list);
        model.addAttribute("query", query);
        model.addAttribute("subjectList", getExamSubject(examId, wu));
        model.addAttribute("examFinish", checkFinish(exam));
        return "modules/exam/inspectedInfo";
    }

    @RequestMapping(value = "list/export", method = RequestMethod.POST)
    public String exportListFile(HttpServletRequest request, HttpServletResponse response,
            RedirectAttributes redirectAttributes, InspectQuery query,
            @RequestParam(required = false) SubjectiveStatus status,
            @RequestParam(required = false) SelectiveStatus selectiveStatus,
            @RequestParam(required = false) Integer mainNumber, @RequestParam(required = false) Double mainStartScore,
            @RequestParam(required = false) Double mainEndScore) {
        int examId = getSessionExamId(request);
        Exam exam = examService.findById(examId);
        if (ExamType.MULTI_MEDIA.equals(exam.getType())) {
            return "modules/exam/permission";
        }
        WebUser wu = RequestUtils.getWebUser(request);
        query.setExamId(examId);
        List<ExamSubject> subjectList = getExamSubject(examId, wu);
        if (StringUtils.isBlank(query.getSubjectCode()) && wu.getRole() != Role.SCHOOL_ADMIN) {
            List<String> subjectCodeIn = new ArrayList<String>();
            subjectList.forEach(e -> subjectCodeIn.add(e.getCode()));
            query.setSubjectCodeIn(StringUtils.join(subjectCodeIn, ","));
        }
        query.setExport(true);
        List<ExamStudentVo> list = inspectedService.findByQuery(query, status, mainNumber, mainStartScore,
                mainEndScore, selectiveStatus);
        for (ExamStudentVo e : list) {
            e.setSubjectiveScoreList(e.getSubjectiveScoreList().replace(UN_SELECTIVE_SCORE, "/"));
        }
        int maxInspectRound = 0;
        if (list != null && list.size() > 0) {
//            Set<String> subjectCodes = list.stream().map(e -> e.getSubjectCode()).collect(Collectors.toSet());
//            maxInspectRound = subjectService.findMaxInspectRound(examId, subjectCodes);
        	maxInspectRound=inspectedService.fillInspectHistoryMap(list);
        }
        try {
            String fileName = "确认列表.xlsx";
            List<String> headerList = getInspectHeader(maxInspectRound);
            ExportInspectExcel excel = new ExportInspectExcel("确认列表", headerList, ExamStudentVo.class);
            excel.setDataList(list);
            excel.write(response, fileName).dispose();
            return null;
        } catch (Exception e) {
            addErrMessage(redirectAttributes, e, "导出数据失败");
        }
        return "redirect:/admin/exam/inspected/list";
    }

    private List<String> getInspectHeader(int maxInspectRound) {
        List<String> ret = new ArrayList<>();
        for (int i = 1; i <= maxInspectRound; i++) {
            ret.add("确认人" + i);
            ret.add("确认时间" + i);
        }
        return ret;
    }

    @RequestMapping(value = "work/export", method = RequestMethod.POST)
    public String exportWorkFile(HttpServletRequest request, HttpServletResponse response,
            RedirectAttributes redirectAttributes) {
        Integer examId = getSessionExamId(request);
        Exam exam = examService.findById(examId);
        if (ExamType.MULTI_MEDIA.equals(exam.getType())) {
            return "modules/exam/permission";
        }
        try {
            List<InspectWorkVo> list = inspectHistoryService.findInspectWork(examId);
            String fileName = "工作量.xlsx";
            new ExportExcel("工作量", InspectWorkVo.class).setDataList(list).write(response, fileName).dispose();
            return null;
        } catch (Exception e) {
            addErrMessage(redirectAttributes, e, "导出数据失败");
        }
        return "redirect:/admin/exam/inspected/list";
    }

}
