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

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

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.ScoreEditDTO;
import cn.com.qmth.stmms.admin.dto.ScoreExportDTO;
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.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.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.ExamStudentService;
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.exam.service.ScoreRateService;
import cn.com.qmth.stmms.biz.lock.LockService;
import cn.com.qmth.stmms.biz.mark.model.MarkLibrary;
import cn.com.qmth.stmms.biz.mark.service.MarkLibraryService;
import cn.com.qmth.stmms.biz.mark.service.MarkService;
import cn.com.qmth.stmms.biz.user.model.User;
import cn.com.qmth.stmms.biz.user.service.UserService;
import cn.com.qmth.stmms.biz.utils.ScoreItem;
import cn.com.qmth.stmms.common.auth.annotation.RoleRequire;
import cn.com.qmth.stmms.common.domain.WebUser;
import cn.com.qmth.stmms.common.enums.LockType;
import cn.com.qmth.stmms.common.enums.Role;
import cn.com.qmth.stmms.common.utils.ExportExcel;
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 BaseExamController {

    @Autowired
    private CampusService campusService;

    @Autowired
    private ExamSubjectService subjectService;

    @Autowired
    private ExamStudentService studentService;

    @Autowired
    private ExamQuestionService questionService;

    @Autowired
    private ExamPackageService packageService;

    @Autowired
    private MarkService markService;

    @Autowired
    private MarkLibraryService markLibraryService;

    @Autowired
    private MarkGroupService groupService;

    @Autowired
    private ScoreRateService scoreRateService;

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

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

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

    @Autowired
    private MarkerService markerService;

    @Autowired
    private UserService userService;

    @Autowired
    private AsyncTaskExecutor taskExecutor;

    @Autowired
    private LockService lockService;

    @RequestMapping
    public ModelAndView list(HttpServletRequest request, ExamStudentSearchQuery query,
            @RequestParam(defaultValue = "0") Integer filter) {
        WebUser wu = RequestUtils.getWebUser(request);
        int examId = getSessionExamId(request);
        String subjectCode = RequestUtils.getSession(request).getParameter("subjectCode");
        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);
        }
        subjectFilter(query, wu);
        query = studentService.findByQuery(query);
        for (ExamStudent student : query.getResult()) {
            buildSheetUrl(student);
            buildPackageUrl(student);
            buildAnswerUrl(student);
            student.setSubjectRemark(subjectService.find(student.getExamId(), student.getSubjectCode()).getRemark());
            List<Marker> markers = markerService.findByStudentId(student.getId());
            if (!markers.isEmpty()) {
                String loginNames = "";
                String names = "";
                for (Marker marker : markers) {
                    loginNames = loginNames.equals("") ? marker.getLoginName()
                            : loginNames + "," + marker.getLoginName();
                    names = names.equals("") ? marker.getName() : names + "," + marker.getName();
                }
                student.setMarkLogin(loginNames);
                student.setMarkName(names);
            }
            List<MarkLibrary> markLibrarys = markLibraryService.findByStudentId(student.getId());
            if (!markLibrarys.isEmpty()) {
                Set<String> tags = new HashSet<String>();
                for (MarkLibrary markLibrary : markLibrarys) {
                    if (markLibrary.getTags() != null) {
                        String[] tag = markLibrary.getTags().split(",");
                        for (String s : tag) {
                            tags.add(s);
                        }
                    }
                    if (markLibrary.getHeaderId() != null) {
                        User user = userService.findById(markLibrary.getHeaderId());
                        student.setMarkLogin(user.getLoginName());
                        student.setMarkName(user.getName());
                    }
                }
                if (!tags.isEmpty()) {
                    student.setTagValue(tags.toString());
                }
            }
        }
        view.addObject("query", query);
        view.addObject("filter", filter);
        view.addObject("subjectList", getExamSubject(examId, wu));
        view.addObject("running", lockService.isLocked(LockType.EXAM, examId));
        view.addObject("imageServer", imageServer);
        view.addObject("packageServer", packageServer);
        view.addObject("cardServer", cardServer);
        return view;
    }

    @RequestMapping("/detail")
    public ModelAndView detail(HttpServletRequest request, @RequestParam String examNumber,
            @RequestParam String queryString) {
        int examId = getSessionExamId(request);
        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");
        }
    }

    @RequestMapping("/edit")
    @ResponseBody
    @RoleRequire(Role.SCHOOL_ADMIN)
    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")
    @RoleRequire(Role.SCHOOL_ADMIN)
    public ModelAndView calculate(HttpServletRequest request) {
        int examId = getSessionExamId(request);
        if (lockService.trylock(LockType.EXAM, examId)) {
            ScoreCalculateThread thread = new ScoreCalculateThread(examId, lockService, studentService, questionService,
                    subjectService, scoreRateService, markService, groupService);
            taskExecutor.submit(thread);
        }
        return new ModelAndView("redirect:/admin/exam/score");
    }

    @RequestMapping("/export")
    public String export(ExamStudentSearchQuery query, HttpServletRequest request, HttpServletResponse response,
            RedirectAttributes redirectAttributes) {
        WebUser wu = RequestUtils.getWebUser(request);
        int examId = getSessionExamId(request);
        String subjectCode = RequestUtils.getSession(request).getParameter("subjectCode");
        query.setExamId(examId);
        // query.setUpload(true);
        // query.setAbsent(false);
        query.setPageNumber(1);
        query.setPageSize(Integer.MAX_VALUE);
        subjectFilter(query, wu);
        String ids = getStudentIdsByMarkLoginAndMarkName(query.getMarkLogin(), query.getMarkName());
        if (StringUtils.isNotBlank(ids)) {
            query.setIds(ids);
        }
        query = studentService.findByQuery(query);
        String fileName = "成绩单.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";
        }
    }

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

        List<ExamQuestion> 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 = 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());
        }
    }

    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;
    }
}
