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

import java.util.LinkedList;
import java.util.List;

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

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import cn.com.qmth.stmms.admin.dto.ExamStudentDTO;
import cn.com.qmth.stmms.admin.dto.ExamStudentScoreDTO;
import cn.com.qmth.stmms.admin.dto.ScoreEditDTO;
import cn.com.qmth.stmms.admin.dto.ScoreExportDTO;
import cn.com.qmth.stmms.admin.exam.parameter.BaseParameterController;
import cn.com.qmth.stmms.admin.thread.ScoreCalculateThread;
import cn.com.qmth.stmms.biz.campus.model.Campus;
import cn.com.qmth.stmms.biz.campus.service.CampusService;
import cn.com.qmth.stmms.biz.exam.model.Exam;
import cn.com.qmth.stmms.biz.exam.model.ExamPackage;
import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
import cn.com.qmth.stmms.biz.exam.model.ExamStudentPaper;
import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
import cn.com.qmth.stmms.biz.exam.model.Marker;
import cn.com.qmth.stmms.biz.exam.query.ExamStudentSearchQuery;
import cn.com.qmth.stmms.biz.exam.service.ExamPackageService;
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.ExamStudentPaperService;
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.MarkerService;
import cn.com.qmth.stmms.biz.exam.service.ScoreRateService;
import cn.com.qmth.stmms.biz.mark.model.MarkLibrary;
import cn.com.qmth.stmms.biz.mark.service.MarkLibraryService;
import cn.com.qmth.stmms.biz.utils.ScoreItem;
import cn.com.qmth.stmms.common.enums.ExamStatus;
import cn.com.qmth.stmms.common.enums.LibraryStatus;
import cn.com.qmth.stmms.common.utils.DateUtils;
import cn.com.qmth.stmms.common.utils.ExportExcel;
import cn.com.qmth.stmms.common.utils.ExportExcel2;
import cn.com.qmth.stmms.common.utils.PictureUrlBuilder;
import cn.com.qmth.stmms.common.utils.RequestUtils;
import net.sf.json.JSONObject;

@Controller
@RequestMapping("/admin/exam/score")
public class ScoreController extends BaseParameterController {

    @Autowired
    private ExamService examService;

    @Autowired
    private CampusService campusService;

    @Autowired
    private ExamStudentPaperService studentPaperService;

    @Autowired
    private ExamSubjectService subjectService;

    @Autowired
    private ExamStudentService studentService;

    @Autowired
    private ExamQuestionService questionService;

    @Autowired
    private ExamPackageService packageService;

    @Autowired
    private MarkLibraryService markLibraryService;

    @Autowired
    private ScoreRateService scoreRateService;

    @Value("${sheet.image.server}")
    private String imageServer;

    @Value("${package.image.server}")
    private String packageServer;

    @Value("${card.server}")
    private String cardServer;

    @Value("${scoreList.showExportScore}")
    private String showExportScore;

    @Autowired
    private AsyncTaskExecutor taskExecutor;

    @Autowired
    private MarkerService markerService;

    @RequestMapping
    public ModelAndView list(HttpServletRequest request, ExamStudentSearchQuery query,
            @RequestParam(defaultValue = "0") Integer filter) {
        int examId = getSessionExamId(request);
        String subjectCode = RequestUtils.getSession(request).getParameter("subjectCode");
        if (examId > 0) {
            Exam exam = examService.findById(examId);
            ModelAndView view = new ModelAndView("modules/exam/scoreList");
            if (subjectCode != null) {
                query.setSubjectCode(subjectCode);
            }
            query.setExamId(examId);
            // query.setUpload(true);
            // query.setAbsent(false);
            query.orderByExamNumber();
            if (filter == 1) {
                query.setObjectiveScore(0d);
                query.setSubjectiveScoreGt(0d);
            } else if (filter == 2) {
                query.setObjectiveScoreGt(0d);
                query.setSubjectiveScore(0d);
            }
            String ids = getStudentIdsByMarkLoginAndMarkName(query.getMarkLogin(), query.getMarkName());
            if (StringUtils.isNotBlank(ids)) {
                query.setIds(ids);
            }
            query = studentService.findByQuery(query);
            for (ExamStudent student : query.getResult()) {
                buildSheetUrl(student);
                buildPackageUrl(student);
                buildAnswerUrl(student);
                student.setSubjectRemark(
                        subjectService.find(student.getExamId(), student.getSubjectCode()).getRemark());
                student.setMarked(isMarked(student));
                Marker marker = markerService.findByStudentId(student.getId());
                if (marker != null) {
                    student.setMarkLogin(marker.getLoginName());
                    student.setMarkName(marker.getName());
                }
                MarkLibrary markLibrary = markLibraryService.findByStudentId(student.getId());
                if (markLibrary != null) {
                    student.setTagValue(markLibrary.getTags());
                }
            }
            view.addObject("query", query);
            view.addObject("filter", filter);
            view.addObject("subjectList", getExamSubject(examId));
            view.addObject("exam", exam);
            view.addObject("imageServer", imageServer);
            view.addObject("packageServer", packageServer);
            view.addObject("cardServer", cardServer);
            view.addObject("showExportScore", showExportScore);
            return view;
        } else {
            return new ModelAndView("redirect:/admin/exam/list");
        }
    }

    @RequestMapping("/detail")
    public ModelAndView detail(HttpServletRequest request, @RequestParam String examNumber,
            @RequestParam String queryString) {
        int examId = getSessionExamId(request);
        if (examId > 0) {
            ExamStudent student = studentService.findByExamIdAndExamNumber(examId, examNumber);
            if (student != null) {
                buildSheetUrl(student);
                buildPackageUrl(student);
                buildAnswerUrl(student);
                ModelAndView view = new ModelAndView("modules/exam/scoreDetail");
                view.addObject("student", student);
                view.addObject("scoreList", buildScoreList(student));
                view.addObject("imageServer", imageServer);
                view.addObject("packageServer", packageServer);
                view.addObject("cardServer", cardServer);
                view.addObject("queryString", StringUtils.trimToEmpty(queryString));
                return view;
            } else {
                return new ModelAndView("redirect:/admin/exam/score");
            }
        } else {
            return new ModelAndView("redirect:/admin/exam/list");
        }
    }

    @RequestMapping("/edit")
    @ResponseBody
    public JSONObject edit(HttpServletRequest request, ScoreEditDTO dto) {
        JSONObject result = new JSONObject();
        int examId = getSessionExamId(request);
        ExamStudent student = studentService.findByExamIdAndExamNumber(examId, dto.getExamNumber());
        if (student != null) {
            double oScore = 0d;
            List<ScoreItem> oList = dto.getObjectiveScoreItems();
            for (ScoreItem item : oList) {
                oScore += item.getScore();
            }
            student.setObjectiveScore(oScore);
            student.setScoreList(oList, true);

            double sScore = 0d;
            List<ScoreItem> sList = dto.getSubjectiveScoreItems();
            for (ScoreItem item : sList) {
                sScore += item.getScore();
            }
            student.setSubjectiveScore(sScore);
            student.setScoreList(sList, false);

            studentService.save(student);
            result.accumulate("success", true);
        } else {
            result.accumulate("success", false);
            result.accumulate("message", "找不到对应的考生");
        }
        return result;
    }

    @RequestMapping("/calculate")
    public ModelAndView calculate(HttpServletRequest request) {
        int examId = getSessionExamId(request);
        if (examId > 0) {
            Exam exam = examService.findById(examId);
            if (exam != null && exam.getStatus() == ExamStatus.START) {
                exam.setStatus(ExamStatus.CALCULATING);
                examService.save(exam);

                ScoreCalculateThread thread = new ScoreCalculateThread(exam, examService, studentService,
                        studentPaperService, questionService, subjectService, scoreRateService, markLibraryService);
                taskExecutor.submit(thread);
            }
            return new ModelAndView("redirect:/admin/exam/score");
        } else {
            return new ModelAndView("redirect:/admin/exam/list");
        }
    }

    @RequestMapping("/export")
    public String export(ExamStudentSearchQuery query, HttpServletRequest request, HttpServletResponse response,
            RedirectAttributes redirectAttributes) {
        int examId = getSessionExamId(request);
        String subjectCode = RequestUtils.getSession(request).getParameter("subjectCode");
        if (examId > 0) {
            query.setExamId(examId);
            // query.setUpload(true);
            // query.setAbsent(false);
            query.setPageNumber(1);
            query.setPageSize(Integer.MAX_VALUE);
            String ids = getStudentIdsByMarkLoginAndMarkName(query.getMarkLogin(), query.getMarkName());
            if (StringUtils.isNotBlank(ids)) {
                query.setIds(ids);
            }
            query = studentService.findByQuery(query);
            String fileName = "成绩单_" + DateUtils.getDate("yyyyMMdd") + ".xlsx";
            try {
                if (subjectCode != null) {
                    fileName = subjectService.find(examId, subjectCode).getName() + "-机阅考试成绩表";
                    List<ScoreExportDTO> list = new LinkedList<ScoreExportDTO>();
                    for (ExamStudent student : query.getResult()) {
                        if (student.isBreach() || student.isAbsent()) {
                            student.setObjectiveScore(0d);
                            student.setSubjectiveScore(0d);
                        }
                        list.add(new ScoreExportDTO(student));
                    }
                    new ExportExcel(subjectCode + "-" + subjectService.find(examId, subjectCode).getName(),
                            ScoreExportDTO.class).setDataList(list).write(response, fileName + ".xlsx").dispose();
                    return null;
                }
                List<ExamStudentDTO> list = new LinkedList<ExamStudentDTO>();
                for (ExamStudent student : query.getResult()) {
                    if (student.isBreach() || student.isAbsent()) {
                        student.setObjectiveScore(0d);
                        student.setSubjectiveScore(0d);
                    }
                    list.add(new ExamStudentDTO(student));
                }
                new ExportExcel("成绩单", ExamStudentDTO.class).setDataList(list).write(response, fileName).dispose();
                return null;
            } catch (Exception e) {
                addMessage(redirectAttributes, "导出成绩失败！" + e.getMessage());
                return "redirect:/admin/exam/score";
            }
        } else {
            return "redirect:/admin/exam/list";
        }
    }

    private List<ScoreItem> buildScoreList(ExamStudent student) {
        List<ScoreItem> scoreList = new LinkedList<ScoreItem>();

        List<ExamQuestion> oList = null;
        ExamStudentPaper oPaper = studentPaperService.find(student.getExamId(), student.getExamNumber(), true);
        if (oPaper != null) {
            oList = oPaper.getQuestionList();
        }
        if (oList == null || oList.isEmpty()) {
            oList = questionService.findByExamAndSubjectAndObjective(student.getExamId(), student.getSubjectCode(),
                    true);
        }
        List<ScoreItem> list1 = student.getScoreList(true);
        int index = 0;
        for (ExamQuestion question : oList) {
            try {
                ScoreItem item = list1.get(index);
                item.setTitle(question.getMainTitle() + "-" + question.getSubNumber());
                item.setMainNumber(question.getMainNumber());
                item.setSubNumber(question.getSubNumber());
            } catch (Exception e) {
            }
            index++;
        }
        scoreList.addAll(list1);

        List<ExamQuestion> sList = null;
        ExamStudentPaper sPaper = studentPaperService.find(student.getExamId(), student.getExamNumber(), false);
        if (sPaper != null) {
            sList = sPaper.getQuestionList();
        }
        if (sList == null || sList.isEmpty()) {
            sList = questionService.findByExamAndSubjectAndObjective(student.getExamId(), student.getSubjectCode(),
                    false);
        }
        List<ScoreItem> list2 = student.getScoreList(false);
        index = 0;
        for (ExamQuestion question : sList) {
            try {
                ScoreItem item = list2.get(index);
                item.setTitle(question.getMainTitle() + "-" + question.getSubNumber());
                item.setMainNumber(question.getMainNumber());
                item.setSubNumber(question.getSubNumber());
            } catch (Exception e) {
            }
            index++;
        }
        scoreList.addAll(list2);

        return scoreList;
    }

    private void buildSheetUrl(ExamStudent student) {
        Campus campus = campusService.findBySchoolAndName(student.getSchoolId(), student.getCampusName());
        student.setSheetUrls(PictureUrlBuilder.getSheetUrls(student.getExamId(), campus.getId(),
                student.getSubjectCode(), student.getExamNumber(), student.getSheetCount()));
    }

    private void buildPackageUrl(ExamStudent student) {
        if (StringUtils.isNotBlank(student.getPackageCode())) {
            ExamPackage ep = packageService.find(student.getExamId(), student.getPackageCode());
            if (ep != null && ep.getPicCount() > 0) {
                student.setPackageUrls(PictureUrlBuilder.getPackageUrls(student.getExamId(), student.getPackageCode(),
                        ep.getPicCount()));
            }
        }
    }

    private void buildAnswerUrl(ExamStudent student) {
        ExamSubject subject = subjectService.find(student.getExamId(), student.getSubjectCode());
        if (subject != null && subject.getHasAnswer().booleanValue()) {
            student.setAnswerUrl(subject.getAnswerUrl());
        }
    }

    private boolean isMarked(ExamStudent student) {
        MarkLibrary markLibrary = markLibraryService.findByStudentId(student.getId());
        if (markLibrary != null) {
            if (StringUtils.isNotEmpty(markLibrary.getMarkerScoreList())
                    && markLibrary.getStatus().equals(LibraryStatus.MARKED)) {
                return true;
            } else {
                return false;
            }
        }
        return false;
    }

    @RequestMapping("/exportScore")
    public String exportScore(ExamStudentSearchQuery query, HttpServletRequest request, HttpServletResponse response,
            RedirectAttributes redirectAttributes) {
        int examId = getSessionExamId(request);
        String examName = "[考试批次名称]成绩单";
        if (examId > 0) {
            Exam exam = examService.findById(examId);
            if (exam != null) {
                examName = "[" + exam.getName() + "]成绩单";
            }
            String ids = getStudentIdsByMarkLoginAndMarkName(query.getMarkLogin(), query.getMarkName());
            if (StringUtils.isNotBlank(ids)) {
                query.setIds(ids);
            }
            query.setExamId(examId);
            // query.setUpload(true);
            // query.setAbsent(false);
            query.setPageNumber(1);
            query.setPageSize(Integer.MAX_VALUE);
            query = studentService.findByQuery(query);
            String fileName = "成绩单_" + DateUtils.getDate("yyyyMMdd") + ".xls";
            String subTitle = "负责教师签字：_______________ 交回日期：_______________";
            try {
                List<ExamStudentScoreDTO> list = new LinkedList<ExamStudentScoreDTO>();
                int i = 1;
                for (ExamStudent student : query.getResult()) {
                    if (student.isBreach() || student.isAbsent()) {
                        student.setObjectiveScore(0d);
                        student.setSubjectiveScore(0d);
                    }
                    student.setNumber(i);
                    list.add(new ExamStudentScoreDTO(student));
                    i++;
                }
                new ExportExcel2(examName, subTitle, ExamStudentScoreDTO.class).setDataList(list).write(response,
                        fileName);
                return null;
            } catch (Exception e) {
                addMessage(redirectAttributes, "导出成绩失败！" + e.getMessage());
                return "redirect:/admin/exam/score";
            }
        } else {
            return "redirect:/admin/exam/list";
        }
    }

    public String getStudentIdsByMarkLoginAndMarkName(String markLogin, String markName) {
        String ids = "";
        if (StringUtils.isNotBlank(markLogin)) {
            ids += studentService.findIdsByMarkLogin(markLogin);
            if (ids.equals("")) {
                ids = "-1";
            }
        }
        if (StringUtils.isNotBlank(markName)) {
            String s = studentService.findIdsByMarkName(markName);
            if (StringUtils.isBlank(ids)) {
                if (s.equals("")) {
                    ids = "-1";
                } else {
                    ids += s;
                }
            } else {
                if (!ids.equals("-1")) {
                    if (StringUtils.isBlank(s)) {
                        ids = "-1";
                    }
                }
            }
        }
        return ids;
    }
}
