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

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

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.transaction.annotation.Transactional;
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.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.google.common.collect.Lists;

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.ExamStudent;
import cn.com.qmth.stmms.biz.exam.model.ExamStudentVO;
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.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.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.mark.service.MarkLibraryService;
import cn.com.qmth.stmms.biz.user.model.User;
import cn.com.qmth.stmms.biz.user.service.UserService;
import cn.com.qmth.stmms.common.utils.DateUtils;
import cn.com.qmth.stmms.common.utils.ExportExcel;
import cn.com.qmth.stmms.common.utils.ImportExcel;
import cn.com.qmth.stmms.common.utils.PictureUrlBuilder;
import cn.com.qmth.stmms.common.utils.RequestUtils;
import net.sf.json.JSONObject;

@Controller("examStudentController")
@RequestMapping("/admin/exam-param/student")
public class ExamStudentController extends BaseParameterController {

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

    @Autowired
    private CampusService campusService;

    @Autowired
    private ExamStudentService studentService;

    @Autowired
    private ExamSubjectService subjectService;

    @Autowired
    private ExamService examService;

    @Autowired
    private MarkLibraryService libraryService;

    @Autowired
    private MarkerService markerService;

    @Autowired
    private ExamQuestionService questionService;

    @Autowired
    private ExamPackageService packageService;

    @Autowired
    private UserService userService;

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

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

    @RequestMapping
    public String list(Model model, HttpServletRequest request, ExamStudentSearchQuery query) {
        int examId = getSessionExamId(request);
        if (examId > 0) {
            query.setExamId(examId);
            if (query.getBatchCode() != null) {
                query.setBatchCode(StringUtils.upperCase(query.getBatchCode()));
            }
            query = studentService.findByQuery(query);
            if (query.getCurrentCount() > 0) {
                for (ExamStudent student : query.getResult()) {
                    student.setSubjectRemark(
                            subjectService.find(student.getExamId(), student.getSubjectCode()).getRemark());
                    buildSheetUrl(student);
                    buildPackageUrl(student);
                }
                model.addAttribute("studentList", query.getResult());
            }
            model.addAttribute("query", query);
            model.addAttribute("campusList", studentService.findDistinctCampusName(examId));
            model.addAttribute("subjectList", getExamSubject(examId));
            model.addAttribute("levelList", subjectService.listLevel(examId));
            model.addAttribute("categoryList", subjectService.listCategory(examId));
            model.addAttribute("imageServer", imageServer);
            model.addAttribute("packageServer", packageServer);
            return "modules/exam/param/studentList";
        } else {
            return "redirect:/admin/exam/list";
        }
    }

    @RequestMapping("/clear")
    @Transactional
    public ModelAndView clear(HttpServletRequest request) {
        Exam exam = examService.findById(getSessionExamId(request));
        User user = RequestUtils.getWebUser(request).getUser();
        if (exam != null && exam.getCreatorId().equals(user.getId())) {
            subjectService.deleteByExamId(exam.getId());
            studentService.deleteByExamId(exam.getId());
            libraryService.deleteByExam(exam.getId());
            markerService.deleteByExam(exam.getId());
            questionService.deleteByExam(exam.getId());
            packageService.deleteByExamId(exam.getId());
            userService.deleteSubjectViewerByExamId(exam.getId());
            return new ModelAndView("redirect:/admin/exam-param/student").addObject("message", "考生删除成功");
        } else {
            return new ModelAndView("redirect:/admin/exam/list");
        }
    }

    @RequestMapping(value = "/add")
    public String form(HttpServletRequest request, ExamStudent student, Model model) {
        Exam exam = examService.findById(getSessionExamId(request));
        model.addAttribute("student", student);
        model.addAttribute("subjectList", getExamSubject(exam.getId()));
        model.addAttribute("campusList", studentService.findDistinctCampusName(exam.getId()));
        return "modules/exam/param/studentForm";
    }

    @RequestMapping(value = "/update")
    public String update(HttpServletRequest request, Integer id, Model model) {
        Exam exam = examService.findById(getSessionExamId(request));
        ExamStudent student = studentService.findById(id);
        model.addAttribute("student", student);
        model.addAttribute("subjectList", getExamSubject(exam.getId()));
        model.addAttribute("campusList", studentService.findDistinctCampusName(exam.getId()));
        return "modules/exam/param/studentForm";
    }

    @RequestMapping(value = "/save")
    public String save(ExamStudent student, Model model, RedirectAttributes redirectAttributes,
            HttpServletRequest request, HttpServletResponse response) {
        int examId = getSessionExamId(request);
        if (examId == 0) {
            return "redirect:/admin/exam/list";
        }
        Exam exam = examService.findById(examId);
        ExamSubject subject = subjectService.find(examId, student.getSubjectCode());
        if (subject == null) {
            addMessage(redirectAttributes, "科目不存在");
        } else {
            if (student.getId() != null) {
                ExamStudent previous = studentService.findById(student.getId());
                if (previous != null) {
                    /**
                     * 前提条件：该学生已经上传答题卡 upload = true
                     * 处理逻辑：如果修改“学习中心”或“课程名称”或“准考证号”则需要要求重新上传答题卡，并将上传状态重置为“未上传”
                     */
                    boolean showTip = false;
                    if (previous.isUpload()) {
                        if ((!previous.getCampusName().equals(student.getCampusName()))
                                || (!previous.getSubjectCode().equals(student.getSubjectCode()))
                                || (!previous.getExamNumber().equals(student.getExamNumber()))) {
                            previous.setUpload(false);
                            showTip = true;
                        }
                    }
                    previous.setCampusName(student.getCampusName());
                    previous.setSubjectCode(subject.getCode());
                    previous.setSubjectName(subject.getName());
                    previous.setStudentCode(student.getStudentCode());
                    previous.setName(student.getName());
                    previous.setExamNumber(student.getExamNumber());
                    previous.setPackageCode(student.getPackageCode());
                    if (checkExamNumber(previous, null, null)) {
                        studentService.save(previous);
                        addMessage(redirectAttributes, "考生" + previous.getName() + "保存成功");
                        if (showTip)
                            addMessage(redirectAttributes, "修改成功，但需要重新上传考生答题卡");
                    } else {
                        addMessage(redirectAttributes, "准考证号" + previous.getExamNumber() + "已存在");
                        redirectAttributes.addAttribute("id", student.getId());
                        return "redirect:/admin/exam-param/student/update";
                    }
                } else {
                    addMessage(redirectAttributes, "考生不存在");
                }
            } else {
                student.setExamId(examId);
                student.setSchoolId(exam.getSchoolId());
                student.setSubjectName(subject.getName());
                student.setAbsent(false);
                student.setBreach(false);
                student.setUpload(false);
                student.setException(false);
                student.setSliceCount(0);
                student.setSheetCount(0);
                student.setObjectiveScore(0d);
                student.setSubjectiveScore(0d);
                if (checkExamNumber(student, null, null)) {
                    studentService.save(student);
                    addMessage(redirectAttributes, "考生" + student.getName() + "保存成功");
                } else {
                    addMessage(redirectAttributes, "准考证号" + student.getExamNumber() + "已存在");
                    return "redirect:/admin/exam-param/student/add";
                }
            }
        }
        return "redirect:/admin/exam-param/student";
    }

    @RequestMapping(value = "/delete")
    public String delete(Integer id, RedirectAttributes redirectAttributes) {
        studentService.deleteById(id);
        libraryService.deleteByStudent(id);
        addMessage(redirectAttributes, "删除考生成功");
        return "redirect:/admin/exam-param/student";
    }

    @RequestMapping(value = "/template")
    public String importFileTemplate(HttpServletResponse response, RedirectAttributes redirectAttributes) {
        try {
            String fileName = "考生数据导入模板.xlsx";
            List<ExamStudent> list = Lists.newArrayList();
            list.add(new ExamStudent());
            new ExportExcel("考生数据", ExamStudent.class, 2).setDataList(list).write(response, fileName).dispose();
            return null;
        } catch (Exception e) {
            addMessage(redirectAttributes, "导入模板下载失败！失败信息：" + e.getMessage());
        }
        return "redirect:" + "/admin/exam-param/student";
    }

    @RequestMapping(value = "/import", method = RequestMethod.POST)
    public String importFile(HttpServletRequest request, MultipartFile file, RedirectAttributes redirectAttributes) {
        int examId = getSessionExamId(request);
        Exam exam = examService.findById(examId);
        try {
            int successNum = 0;
            int failureNum = 0;
            StringBuilder failureMsg = new StringBuilder();
            ImportExcel ei = new ImportExcel(file, 1, 0);
            List<ExamStudent> list = ei.getDataList(ExamStudent.class);
            List<ExamStudent> saveList = new LinkedList<ExamStudent>();
            Map<String, ExamStudent> saveMap = new HashMap<String, ExamStudent>();
            Map<String, ExamStudent> current = null;
            // 当数据库中已存在考生小于一定数量，则一次性取出所有考生，用于校验准考证号是否重复
            if (studentService.countByExamId(examId) < 10000) {
                current = new HashMap<String, ExamStudent>();
                List<ExamStudent> list2 = studentService.findByExamId(examId);
                for (ExamStudent s : list2) {
                    current.put(s.getExamNumber(), s);
                }
            }

            for (ExamStudent student : list) {
                if (StringUtils.isBlank(student.getStudentCode()) || StringUtils.isBlank(student.getName())
                        || StringUtils.isBlank(student.getSubjectCode())
                        || StringUtils.isBlank(student.getSubjectName())
                        || StringUtils.isBlank(student.getCampusName())) {
                    continue;
                }

                student.setExamId(examId);
                student.setSchoolId(exam.getSchoolId());
                student.setAbsent(false);
                student.setUpload(false);
                student.setException(false);
                student.setSliceCount(0);
                student.setSheetCount(0);
                student.setObjectiveScore(0d);
                student.setSubjectiveScore(0d);
                student.setBreach(false);

                if (checkExamNumber(student, current, saveMap)) {
                    saveList.add(student);
                    saveMap.put(student.getExamNumber(), student);
                } else {
                    failureMsg.append("<br/>准考证号 " + student.getExamNumber() + " 已存在; ");
                    failureNum++;
                }
            }

            successNum = studentService.batchSave(saveList);

            if (failureNum > 0) {
                failureMsg.insert(0, "，失败 " + failureNum + " 条用户");
            }
            addMessage(redirectAttributes, "已成功导入 " + successNum + " 条用户" + failureMsg);
        } catch (Exception e) {
            log.error("Batch import student error!", e);
            addMessage(redirectAttributes, "导入考生失败！失败信息：" + e.getMessage());
        }
        return "redirect:" + "/admin/exam-param/student";
    }

    @RequestMapping(value = "/breachTemplate")
    public String breachTemplate(HttpServletResponse response, RedirectAttributes redirectAttributes) {
        try {
            String fileName = "违纪考生导入模板.xlsx";
            List<ExamStudentVO> list = Lists.newArrayList();
            list.add(new ExamStudentVO());
            new ExportExcel("违纪考生", ExamStudentVO.class, 2).setDataList(list).write(response, fileName).dispose();
            return null;
        } catch (Exception e) {
            addMessage(redirectAttributes, "导入模板下载失败！失败信息：" + e.getMessage());
        }
        return "redirect:" + "/admin/exam-param/student";
    }

    @RequestMapping(value = "/breachImport", method = RequestMethod.POST)
    public String breachImportFile(HttpServletRequest request, MultipartFile file,
            RedirectAttributes redirectAttributes) {
        int examId = getSessionExamId(request);
        // Exam exam = examService.findById(examId);
        try {
            int successNum = 0;
            int failureNum = 0;
            StringBuilder failureMsg = new StringBuilder();
            ImportExcel ei = new ImportExcel(file, 1, 0);
            List<ExamStudentVO> list = ei.getDataList(ExamStudentVO.class);
            for (ExamStudentVO studentVO : list) {
                if (StringUtils.isBlank(studentVO.getExamNumber())) {
                    continue;
                }
                ExamStudent student = studentService.findByExamIdAndExamNumber(examId, studentVO.getExamNumber());
                if (student != null) {
                    student.setBreach(true);
                    studentService.save(student);
                    saveMarkLibrary(student);
                    successNum++;
                } else {
                    failureMsg.append("<br/>准考证号 " + studentVO.getExamNumber() + " 不存在; ");
                    failureNum++;
                }

            }
            if (failureNum > 0) {
                failureMsg.insert(0, "，失败 " + failureNum + " 条用户");
            }
            addMessage(redirectAttributes, "已成功导入 " + successNum + " 条用户" + failureMsg);
        } catch (Exception e) {
            log.error("Batch import BreachStudent error!", e);
            addMessage(redirectAttributes, "导入违纪考生失败！失败信息：" + e.getMessage());
        }
        return "redirect:" + "/admin/exam-param/student";
    }

    @RequestMapping(value = "/updateBreach", method = RequestMethod.POST)
    @ResponseBody
    public JSONObject updateBreach(HttpServletRequest request, Integer id) {
        JSONObject result = new JSONObject();
        ExamStudent student = studentService.findById(id);
        student.setBreach(false);
        try {
            if (student.isUpload()) {// 上传的状态才去优化m_library
                saveMarkLibrary(student);
            }
            student = studentService.save(student);
            if (student != null) {
                result.accumulate("message", "重置成功！");
                result.accumulate("success", true);
            } else {
                result.accumulate("message", "将违纪考生信息重置为正常时出错!");
                result.accumulate("success", false);
            }
        } catch (Exception e) {
            log.error("将违纪考生信息重置为正常时出错！", e);
            result.accumulate("message", "将违纪考生信息重置为正常时抛异常！");
            result.accumulate("success", false);
        }
        return result;
    }

    @RequestMapping(value = "/export", method = RequestMethod.POST)
    public String exportFile(ExamStudentSearchQuery query, HttpServletRequest request, HttpServletResponse response,
            RedirectAttributes redirectAttributes) {
        int examId = getSessionExamId(request);
        try {
            query.setPageNumber(1);
            query.setPageSize(Integer.MAX_VALUE);
            query.setExamId(examId);
            // query.orderByExamNumber();
            String fileName = "考生数据" + DateUtils.getDate("yyyyMMdd") + ".xlsx";
            query = studentService.findByQuery(query);
            for (ExamStudent student : query.getResult()) {
                student.setSubjectLevel(subjectService.find(student.getExamId(), student.getSubjectCode()).getLevel());
            }
            new ExportExcel("考生数据", ExamStudent.class).setDataList(query.getResult()).write(response, fileName)
                    .dispose();
            return null;
        } catch (Exception e) {
            addMessage(redirectAttributes, "导出考生数据失败！" + e.getMessage());
        }
        return "redirect:/admin/exam-param/student";
    }

    private boolean checkExamNumber(ExamStudent student, Map<String, ExamStudent> current,
            Map<String, ExamStudent> saveMap) {
        ExamStudent previous = null;
        if (saveMap != null) {
            previous = saveMap.get(student.getExamNumber());
        }

        if (previous != null) {
            return false;
        }

        if (current != null) {
            previous = current.get(student.getExamNumber());
        } else {
            previous = studentService.findByExamIdAndExamNumber(student.getExamId(), student.getExamNumber());
        }

        if (previous == null) {
            return true;
        }
        if (student.getId() != null && student.getId().intValue() == previous.getId().intValue()) {
            return true;
        }

        return false;
    }

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