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.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.bind.annotation.ResponseBody;
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.SubjectiveQuestionDTO;
import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
import cn.com.qmth.stmms.biz.exam.model.MarkStep;
import cn.com.qmth.stmms.biz.exam.model.SubjectiveBlock;
import cn.com.qmth.stmms.biz.exam.query.SubjectiveBlockSearchQuery;
import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
import cn.com.qmth.stmms.biz.exam.service.SubjectiveBlockService;
import cn.com.qmth.stmms.common.beanvalidator.BeanValidators;
import cn.com.qmth.stmms.common.utils.ExportExcel;
import cn.com.qmth.stmms.common.utils.ImportExcel;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

@Controller("subjectiveBlockController")
@RequestMapping("/admin/exam-param/subjective")
public class SubjectiveBlockController extends BaseParameterController {

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

    @Autowired
    private SubjectiveBlockService subjectiveBlockService;

    @Autowired
    private ExamSubjectService examSubjectService;

    @RequestMapping
    public String list(SubjectiveBlockSearchQuery 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 = subjectiveBlockService.findByQuery(query);

            for (SubjectiveBlock 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/subjectiveList";
        } else {
            return "redirect:/admin/exam/list";
        }
    }

    @RequestMapping("/list")
    @ResponseBody
    public JSONArray jsonList(SubjectiveBlockSearchQuery query, HttpServletRequest request) {
        int examId = getSessionExamId(request);
        JSONArray array = new JSONArray();
        if (examId > 0) {
            List<SubjectiveBlock> list = subjectiveBlockService.findBlockByExamIdAndSubjectCode(examId,
                    query.getSubjectCode());
            for (SubjectiveBlock block : list) {
                JSONObject obj = new JSONObject();
                obj.accumulate("id", block.getId());
                obj.accumulate("number", block.getNumber());
                obj.accumulate("title", block.getTitle());
            }
        }
        return array;
    }

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

            model.addAttribute("block", block);
            return "modules/exam/param/markStepList";
        } 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) {
            subjectiveBlockService.deleteBlockById(blockId);
            return "redirect:/admin/exam-param/subjective";
        } else {
            return "redirect:/admin/exam/list";
        }
    }

    @RequestMapping("/delete-step/{blockId}/{stepNumber}")
    public String deleteStep(Model model, HttpServletRequest request, @PathVariable Integer blockId,
            @PathVariable Integer stepNumber) {
        int examId = getSessionExamId(request);
        if (examId > 0) {
            SubjectiveBlock block = subjectiveBlockService.findBlockById(blockId, true);
            if (block != null && stepNumber != null && block.getMarkStepList() != null) {
                List<MarkStep> list = new LinkedList<MarkStep>();
                for (MarkStep step : block.getMarkStepList()) {
                    if (step.getNumber().intValue() != stepNumber.intValue()) {
                        list.add(step);
                    }
                }
                block.setMarkStepList(list);
                block.updateTotalScore();
                subjectiveBlockService.saveBlock(block);
            }
            return "redirect:/admin/exam-param/subjective/" + blockId;
        } else {
            return "redirect:/admin/exam/list";
        }
    }

    @RequestMapping(value = "/template")
    public String importFileTemplate(HttpServletResponse response, RedirectAttributes redirectAttributes) {
        try {
            String fileName = "主观题导入模板.xlsx";
            List<SubjectiveQuestionDTO> list = Lists.newArrayList();
            list.add(new SubjectiveQuestionDTO());
            new ExportExcel("主观题数据", SubjectiveQuestionDTO.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<SubjectiveQuestionDTO> list = ei.getDataList(SubjectiveQuestionDTO.class);
            Map<String, Map<String, SubjectiveBlock>> map = new HashMap<String, Map<String, SubjectiveBlock>>();
            for (SubjectiveQuestionDTO question : list) {
                buildBlock(question, map);
            }
            for (Entry<String, Map<String, SubjectiveBlock>> entry : map.entrySet()) {
                String subjectCode = entry.getKey();
                Map<String, SubjectiveBlock> blockMap = entry.getValue();
                if (blockMap.isEmpty()) {
                    continue;
                }
                ExamSubject subject = examSubjectService.find(examId, subjectCode);
                if (subject == null) {
                    failureMsg.append("<br/>" + subjectCode + " 导入失败：" + "科目不存在！");
                    continue;
                }

                subjectiveBlockService.deleteBlockByExamIdAndSubjectCode(examId, subjectCode);
                for (SubjectiveBlock block : blockMap.values()) {
                    try {
                        block.updateTotalScore();
                        block.setExamId(examId);
                        subjectiveBlockService.saveBlock(block);
                        successNum++;
                        questionNum += block.getMarkStepList().size();
                        subjectSet.add(subjectCode);
                    } catch (ConstraintViolationException ex) {
                        failureMsg.append("<br/>" + subjectCode + " " + block.getTitle() + " 导入失败：");
                        List<String> messageList = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
                        for (String message : messageList) {
                            failureMsg.append(message + "; ");
                            failureNum++;
                        }
                    } catch (Exception ex) {
                        failureMsg.append("<br/>" + subjectCode + " " + 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/subjective?repage";
    }

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

        Map<String, SubjectiveBlock> blockMap = map.get(subjectCode);
        if (blockMap == null) {
            blockMap = new HashMap<String, SubjectiveBlock>();
            map.put(subjectCode, blockMap);
        }
        SubjectiveBlock block = blockMap.get(key);
        if (block == null) {
            block = new SubjectiveBlock();
            block.setSubjectCode(question.getSubjectCode());
            block.setNumber(question.getMainNumber());
            block.setTitle(question.getTitle());
            block.setMarkStepList(new LinkedList<MarkStep>());
            blockMap.put(key, block);
        }

        MarkStep step = new MarkStep();
        step.setNumber(question.getSubNumber());
        step.setTitle(String.valueOf(question.getSubNumber()));
        step.setTotalScore(question.getTotalScore());
        step.setMin(0d);
        step.setMax(question.getTotalScore());
        step.setInterval(question.getTotalScore().toString().contains(".5") ? 0.5 : 1d);
        step.setDefaultScore(0d);
        step.setHasLevel(false);
        try {
            List<Double> list = new LinkedList<Double>();
            for (double score = step.getMin(); score <= step.getMax(); score += step.getInterval()) {
                list.add(score);
            }
            step.setScoreList(list);
        } catch (Exception e) {
        }
        block.getMarkStepList().add(step);
    }
}
