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

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

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

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.google.common.collect.Lists;

import cn.com.qmth.stmms.admin.dto.ObjectiveQuestionDTO;
import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
import cn.com.qmth.stmms.biz.exam.model.ObjectiveBlock;
import cn.com.qmth.stmms.biz.exam.model.ObjectiveQuestion;
import cn.com.qmth.stmms.biz.exam.query.ObjectiveBlockSearchQuery;
import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
import cn.com.qmth.stmms.biz.exam.service.ObjectiveBlockService;
import cn.com.qmth.stmms.common.beanvalidator.BeanValidators;
import cn.com.qmth.stmms.common.utils.ExportExcel;
import cn.com.qmth.stmms.common.utils.ImportExcel;

@Controller("objectiveBlockController")
@RequestMapping("/admin/exam-param/objective")
public class ObjectiveBlockController extends BaseParameterController {

    @Autowired
    private ExamSubjectService examSubjectService;

    @Autowired
    private ObjectiveBlockService objectiveBlockService;

    @RequestMapping
    public String list(ObjectiveBlockSearchQuery query, Model model, HttpServletRequest request) {
        int examId = getSessionExamId(request);
        if (examId > 0) {
            query.setExamId(examId);
            if (StringUtils.isNotEmpty(query.getSubjectCode())) {
                if (",".equals(query.getSubjectCode())) {
                    query.setSubjectCode(null);
                }
            }
            query = objectiveBlockService.findByQuery(query);

            for (ObjectiveBlock block : query.getResult()) {
                ExamSubject subject = examSubjectService.find(examId, block.getSubjectCode());
                if (subject != null) {
                    block.setExamSubject(subject);
                }
            }
            model.addAttribute("query", query);
            model.addAttribute("subjectList", getExamSubject(examId));
            return "modules/exam/param/objectiveList";
        } else {
            return "redirect:/admin/exam/list";
        }
    }

    @RequestMapping("/{blockId}")
    public String listByBlock(Model model, HttpServletRequest request, @PathVariable Integer blockId) {
        int examId = getSessionExamId(request);
        if (examId > 0) {
            ObjectiveBlock block = objectiveBlockService.findBlockById(blockId, true);
            ExamSubject subject = examSubjectService.find(examId, block.getSubjectCode());
            block.setExamSubject(subject);

            model.addAttribute("block", block);
            return "modules/exam/param/objectiveQuestionList";
        } else {
            return "redirect:/admin/exam/list";
        }
    }

    @RequestMapping("/delete/{blockId}")
    public String deleteBlock(Model model, HttpServletRequest request, @PathVariable Integer blockId) {
        int examId = getSessionExamId(request);
        if (examId > 0) {
            ObjectiveBlock block = objectiveBlockService.findBlockById(blockId, false);
            if (block != null) {
                objectiveBlockService.deleteBlock(block);
            }
            return "redirect:/admin/exam-param/objective";
        } else {
            return "redirect:/admin/exam/list";
        }
    }

    @RequestMapping("/delete-question/{blockId}/{subNumber}")
    public String deleteStep(Model model, HttpServletRequest request, @PathVariable Integer blockId,
            @PathVariable Integer subNumber) {
        int examId = getSessionExamId(request);
        if (examId > 0) {
            ObjectiveBlock block = objectiveBlockService.findBlockById(blockId, true);
            if (block != null && subNumber != null && block.getQuestionList() != null) {
                List<ObjectiveQuestion> list = new LinkedList<ObjectiveQuestion>();
                for (ObjectiveQuestion question : block.getQuestionList()) {
                    if (question.getNumber().intValue() != subNumber.intValue()) {
                        list.add(question);
                    }
                }
                block.setQuestionList(list);
                block.updateQuestionCount();
                objectiveBlockService.saveBlock(block);
            }
            return "redirect:/admin/exam-param/objective/" + blockId;
        } else {
            return "redirect:/admin/exam/list";
        }
    }

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

    @RequestMapping(value = "/import", method = RequestMethod.POST)
    public String importFile(HttpServletRequest request, MultipartFile file, RedirectAttributes redirectAttributes) {
        int examId = getSessionExamId(request);
        try {
            int successNum = 0;
            int questionNum = 0;
            int failureNum = 0;
            Set<String> subjectSet = new HashSet<String>();
            StringBuilder failureMsg = new StringBuilder();
            ImportExcel ei = new ImportExcel(file, 1, 0);
            List<ObjectiveQuestionDTO> list = ei.getDataList(ObjectiveQuestionDTO.class);
            Map<String, Map<String, ObjectiveBlock>> map = new HashMap<String, Map<String, ObjectiveBlock>>();
            // Map<String, Integer> config = exam.getObjectiveBlockMap();
            for (ObjectiveQuestionDTO question : list) {
                buildBlock(question, map);
            }
            for (Entry<String, Map<String, ObjectiveBlock>> entry : map.entrySet()) {
                String subjectCode = entry.getKey();
                Map<String, ObjectiveBlock> blockMap = entry.getValue();
                if (blockMap.isEmpty()) {
                    continue;
                }

                if (validateBlockMap(examId, subjectCode, blockMap, failureMsg)) {
                    objectiveBlockService.deleteBlockByExamIdAndSubjectCode(examId, subjectCode);
                    for (ObjectiveBlock block : blockMap.values()) {
                        try {
                            block.setExamId(examId);
                            objectiveBlockService.saveBlock(block);
                            successNum++;
                            questionNum += block.getQuestionCount();
                            subjectSet.add(subjectCode);
                        } catch (ConstraintViolationException ex) {
                            failureMsg.append("<br/>" + block.getSubjectCode() + " " + block.getTitle() + " 导入失败：");
                            List<String> messageList = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
                            for (String message : messageList) {
                                failureMsg.append(message + "; ");
                                failureNum++;
                            }
                        } catch (Exception ex) {
                            failureMsg.append("<br/>" + block.getSubjectCode() + " " + block.getTitle() + " 导入失败："
                                    + ex.getMessage());
                        }
                    }
                }
            }
            if (failureNum > 0) {
                failureMsg.insert(0, "，失败 " + failureNum + " 个大题，导入信息如下：");
            }
            addMessage(redirectAttributes, "已成功导入 " + subjectSet.size() + " 个科目, " + successNum + " 个大题，" + questionNum
                    + "个小题  " + failureMsg);
        } catch (Exception e) {
            addMessage(redirectAttributes, "导入客观题失败！失败信息：" + e.getMessage());
        }
        return "redirect:" + "/admin/exam-param/objective?repage";
    }

    private boolean validateBlockMap(int examId, String subjectCode, Map<String, ObjectiveBlock> blockMap,
            StringBuilder failureMsg) {
        ExamSubject subject = examSubjectService.find(examId, subjectCode);
        if (subject == null) {
            failureMsg.append("<br/>" + subjectCode + " 导入失败：" + "科目不存在！");
            return false;
        }

        boolean validate = true;

        for (ObjectiveBlock block : blockMap.values()) {
            block.updateQuestionCount();
        }
        return validate;
    }

    private void buildBlock(ObjectiveQuestionDTO questionDTO, Map<String, Map<String, ObjectiveBlock>> map) {
        if (questionDTO == null || !questionDTO.validate()) {
            return;
        }
        String subjectCode = questionDTO.getSubjectCode();
        String key = questionDTO.getSubjectCode() + "-" + questionDTO.getMainNumber();

        Map<String, ObjectiveBlock> blockMap = map.get(subjectCode);
        if (blockMap == null) {
            blockMap = new HashMap<String, ObjectiveBlock>();
            map.put(subjectCode, blockMap);
        }
        ObjectiveBlock block = blockMap.get(key);
        if (block == null) {
            block = new ObjectiveBlock();
            block.setSubjectCode(questionDTO.getSubjectCode());
            block.setNumber(questionDTO.getMainNumber());
            block.setTitle(questionDTO.getTitle());
            block.setSingle(false);
            block.setQuestionScore(questionDTO.getTotalScore());
            block.setMissScore(0d);
            block.setQuestionList(new LinkedList<ObjectiveQuestion>());

            blockMap.put(key, block);
        }

        ObjectiveQuestion question = new ObjectiveQuestion();
        question.setNumber(questionDTO.getSubNumber());
        question.setTitle(questionDTO.getSubNumber().toString());
        question.setAnswer(questionDTO.getAnswer());
        block.getQuestionList().add(question);
    }

}
