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

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

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.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
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.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import cn.com.qmth.stmms.admin.dto.ObjectiveQuestionDTO;
import cn.com.qmth.stmms.admin.dto.QuestionDTO;
import cn.com.qmth.stmms.admin.dto.SubjectQuestionDTO;
import cn.com.qmth.stmms.admin.dto.SubjectiveQuestionDTO;
import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
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.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.query.ExamQuestionSearchQuery;
import cn.com.qmth.stmms.biz.exam.service.query.ExamSubjectSearchQuery;
import cn.com.qmth.stmms.common.auth.annotation.RoleRequire;
import cn.com.qmth.stmms.common.domain.WebUser;
import cn.com.qmth.stmms.common.enums.Role;
import cn.com.qmth.stmms.common.utils.ExportExcel;
import cn.com.qmth.stmms.common.utils.ImportExcel;
import cn.com.qmth.stmms.common.utils.RequestUtils;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

@Controller("examPaperController")
@RequestMapping("/admin/exam/paper")
public class PaperController extends BaseExamController {

    @Autowired
    private ExamSubjectService subjectService;

    @Autowired
    private ExamQuestionService questionService;

    @Autowired
    private MarkGroupService groupService;

    @Autowired
    private ExamService examService;

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

    @RequestMapping
    public String list(Model model, HttpServletRequest request, ExamSubjectSearchQuery query,
            @RequestParam(required = false) Boolean upload) {
        WebUser wu = RequestUtils.getWebUser(request);
        int examId = getSessionExamId(request);
        query.setExamId(examId);
        if (upload != null) {
            if (upload.booleanValue()) {
                query.setUploadCountGt(0);
            } else {
                query.setUploadCountEqual(0);
            }
        }
        subjectFilter(query, wu);
        query = subjectService.findByQuery(query);
        model.addAttribute("query", query);
        model.addAttribute("upload", upload);
        model.addAttribute("subjectList", getExamSubject(examId, wu));
        model.addAttribute("levelList", subjectService.listLevel(examId));
        model.addAttribute("categoryList", subjectService.listCategory(examId));
        model.addAttribute("cardServer", cardServer);
        return "modules/exam/paperList";
    }

    @RequestMapping("/detail")
    public String detail(Model model, HttpServletRequest request, @RequestParam String subjectCode,
            @RequestParam(required = false) Boolean objective) {
        WebUser wu = RequestUtils.getWebUser(request);
        int examId = getSessionExamId(request);
        if (wu.isSubjectHeader() && !subjectCode.equals(wu.getUser().getSubjectCode())) {
            return "redirect:/admin/exam/paper";
        }
        ExamSubject subject = subjectService.find(examId, subjectCode);
        if (subject != null) {
            List<ExamQuestion> list = new LinkedList<ExamQuestion>();
            if (objective == null || objective.booleanValue() == true) {
                list.addAll(questionService.findByExamAndSubjectAndObjective(examId, subjectCode, true));
            }
            if (objective == null || objective.booleanValue() == false) {
                list.addAll(questionService.findByExamAndSubjectAndObjective(examId, subjectCode, false));
            }
            model.addAttribute("questionList", list);
            model.addAttribute("subject", subject);
            model.addAttribute("objective", objective);
            return "modules/exam/paperDetail";
        } else {
            return "redirect:/admin/exam/paper";
        }
    }

    @RequestMapping(value = "/template")
    public String importTemplate(HttpServletResponse response, @RequestParam Boolean objective,
            RedirectAttributes redirectAttributes) {
        try {
            String fileName = objective ? "客观题导入模板.xlsx" : "主观题导入模板.xlsx";
            String title = objective ? "客观题数据" : "主观题数据";
            List<QuestionDTO> list = new LinkedList<QuestionDTO>();
            list.add(objective ? new ObjectiveQuestionDTO() : new SubjectiveQuestionDTO());
            new ExportExcel(title, objective ? ObjectiveQuestionDTO.class : SubjectiveQuestionDTO.class, 2)
                    .setDataList(list).write(response, fileName).dispose();
            return null;
        } catch (Exception e) {
            addMessage(redirectAttributes, "导入模板下载失败！失败信息：" + e.getMessage());
        }
        return "redirect:/admin/exam/paper";
    }

    @RequestMapping(value = "/export")
    public String exportFile(HttpServletRequest request, HttpServletResponse response, @RequestParam Boolean objective,
            RedirectAttributes redirectAttributes) {
        int examId = getSessionExamId(request);

        Map<String, ExamSubject> subjectMap = new HashMap<String, ExamSubject>();
        List<ExamSubject> subjectList = subjectService.list(examId);
        for (ExamSubject subject : subjectList) {
            subjectMap.put(subject.getCode(), subject);
        }

        Map<String, MarkGroup> groupMap = new HashMap<String, MarkGroup>();
        List<MarkGroup> groupList = groupService.findByExam(examId);
        for (MarkGroup group : groupList) {
            groupMap.put(group.getSubjectCode() + "_" + group.getNumber(), group);
        }

        List<QuestionDTO> list = new LinkedList<QuestionDTO>();
        ExamQuestionSearchQuery query = new ExamQuestionSearchQuery();
        query.setExamId(examId);
        query.setObjective(objective);
        query.setSort(new Sort(Direction.ASC, "subjectCode", "paperType", "mainNumber", "subNumber"));
        query.setPageNumber(1);
        query.setPageSize(Integer.MAX_VALUE);
        query = questionService.findByQuery(query);
        for (ExamQuestion q : query.getResult()) {
            list.add(objective ? new ObjectiveQuestionDTO(q, subjectMap.get(q.getSubjectCode()))
                    : new SubjectiveQuestionDTO(q, subjectMap.get(q.getSubjectCode()),
                            groupMap.get(q.getSubjectCode() + "_" + q.getGroupNumber())));
        }
        try {
            String fileName = objective ? "客观题数据.xlsx" : "主观题数据.xlsx";
            String title = objective ? "客观题数据" : "主观题数据";
            new ExportExcel(title, objective ? ObjectiveQuestionDTO.class : SubjectiveQuestionDTO.class, 2)
                    .setDataList(list).write(response, fileName).dispose();
            return null;
        } catch (Exception e) {
            addMessage(redirectAttributes, "导出数据失败！失败信息：" + e.getMessage());
        }
        return "redirect:/admin/exam/paper";
    }

    @RequestMapping(value = "/import", method = RequestMethod.POST)
    @RoleRequire(Role.SCHOOL_ADMIN)
    public String importFile(HttpServletRequest request, MultipartFile file, @RequestParam Boolean objective,
            RedirectAttributes redirectAttributes) {
        int examId = getSessionExamId(request);
        // 每次导入都需要重新统分
        examService.updateNeedCalculate(examId, true);

        List<String> error = new LinkedList<String>();
        Map<String, SubjectQuestionDTO> map = parseQuestion(file, examId, objective, error);
        if (error.isEmpty()) {
            int success = 0;
            for (SubjectQuestionDTO dto : map.values()) {
                ExamSubject subject = subjectService.find(examId, dto.getSubjectCode());
                if (subject != null) {
                    if (dto.validate(error)) {
                        if (objective) {
                            questionService.deleteByExamAndSubjectAndObjective(examId, dto.getSubjectCode(), objective);
                            for (ExamQuestion question : dto.getQuestionList()) {
                                questionService.save(question);
                            }
                            subjectService.updateScore(examId, subject.getCode(), objective, dto.getTotalScore());
                        } else {
                            for (MarkGroup group : dto.getGroups().values()) {
                                MarkGroup old = groupService.findOne(examId, group.getSubjectCode(), group.getNumber());
                                // 已存在的评卷分组跳过
                                if (old == null && group.getQuestionMap() != null) {
                                    for (Entry<Integer, List<ExamQuestion>> entry : group.getQuestionMap().entrySet()) {
                                        // 已存在的大题跳过
                                        if (questionService.countByExamAndSubjectAndObjectiveAndMainNumber(examId,
                                                group.getSubjectCode(), objective, entry.getKey()) == 0) {
                                            questionService.save(entry.getValue());
                                        }
                                    }
                                    //有题目的分组才保存
                                    if(questionService.countByExamAndSubjectAndObjectiveAndGroupNumber(examId, group.getSubjectCode(), objective, group.getNumber())!=0){
                                        groupService.save(group);
                                    }
                                }
                            }
                            subjectService.updateScore(examId, subject.getCode(), objective,
                                    groupService.sumTotalScore(examId, dto.getSubjectCode()));
                        }
                        success++;
                    }
                } else {
                    error.add("[" + dto.getSubjectCode() + "] 科目代码不存在；");
                }
            }
            error.add(0, success + "个科目导入成功；");
            if (success > 0) {
                subjectService.updateTotalScore(examId);
            }
        }
        if (error.size() > 0) {
            error.add("<br\\> 导入完毕后请重新统分！");
            addMessage(redirectAttributes, StringUtils.join(error, "<br\\>"));
        }
        return "redirect:/admin/exam/paper";
    }

    private Map<String, SubjectQuestionDTO> parseQuestion(MultipartFile file, int examId, boolean objective,
            List<String> error) {
        Map<String, SubjectQuestionDTO> map = new HashMap<String, SubjectQuestionDTO>();
        try {
            ImportExcel excel = new ImportExcel(file, 1, 0);
            Class<? extends QuestionDTO> clazz = objective ? ObjectiveQuestionDTO.class : SubjectiveQuestionDTO.class;
            List<? extends QuestionDTO> list = excel.getDataList(clazz);
            if (list != null) {
                for (QuestionDTO dto : list) {
                    String subjectCode = StringUtils.trimToNull(dto.getSubjectCode());
                    if (subjectCode != null) {
                        SubjectQuestionDTO subject = map.get(subjectCode);
                        if (subject == null) {
                            subject = new SubjectQuestionDTO(examId, subjectCode, objective);
                            map.put(subjectCode, subject);
                        }
                        subject.addQuestion(dto.transform());
                    }
                }
            }
        } catch (Exception e) {
            log.error("parse question excel error", e);
            error.add("Excel文件解析失败");
        }
        return map;
    }

    @RequestMapping("/getPaperType")
    @ResponseBody
    public JSONArray query(HttpServletRequest request, @RequestParam String subjectCode) {
        int examId = getSessionExamId(request);
        JSONArray array = new JSONArray();
        List<String> list = this.questionService.getPaperType(examId, subjectCode);
        for (String paperType : list) {
            JSONObject obj = new JSONObject();
            obj.accumulate("paperType", paperType);
            array.add(obj);
        }
        return array;
    }
}
