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.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.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.service.ExamQuestionService;
import cn.com.qmth.stmms.biz.exam.service.ExamSubjectPaperService;
import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
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.utils.ExportExcel;
import cn.com.qmth.stmms.common.utils.ImportExcel;

@Controller("examPaperController")
@RequestMapping("/admin/exam-param/paper")
public class ExamPaperController extends BaseParameterController {

    @Autowired
    private ExamSubjectService subjectService;

    @Autowired
    private ExamQuestionService questionService;

    @Autowired
    private ExamSubjectPaperService examSubjectPaperService;

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

    @RequestMapping
    public String list(Model model, HttpServletRequest request, ExamSubjectSearchQuery query,
            @RequestParam(required = false) Boolean upload) {
        int examId = getSessionExamId(request);
        if (examId > 0) {
            query.setExamId(examId);
            if (upload != null) {
                if (upload.booleanValue()) {
                    query.setLibraryCountGt(0);
                } else {
                    query.setLibraryCountEqual(0);
                }
            }
            query = subjectService.findByQuery(query);
            model.addAttribute("query", query);
            model.addAttribute("upload", upload);
            model.addAttribute("subjectList", getExamSubject(examId));
            model.addAttribute("levelList", subjectService.listLevel(examId));
            model.addAttribute("categoryList", subjectService.listCategory(examId));
            model.addAttribute("cardServer", cardServer);
            return "modules/exam/param/paperList";
        } else {
            return "redirect:/admin/exam/list";
        }
    }

    @RequestMapping("/detail")
    public String detail(Model model, HttpServletRequest request, @RequestParam String subjectCode,
            @RequestParam(required = false) Boolean objective) {
        int examId = getSessionExamId(request);
        if (examId > 0) {
            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/param/paperDetail";
            } else {
                return "redirect:/admin/exam-param/paper";
            }
        } else {
            return "redirect:/admin/exam/list";
        }
    }

    @RequestMapping("/clear")
    public String clear(Model model, HttpServletRequest request, @RequestParam String subjectCode) {
        int examId = getSessionExamId(request);
        if (examId > 0) {
            ExamSubject subject = subjectService.find(examId, subjectCode);
            if (subject != null) {
                questionService.deleteByExamAndSubject(examId, subjectCode);

                subject.setObjectiveScore(0d);
                subject.setSubjectiveScore(0d);
                subject.setTotalScore(0d);
                subjectService.save(subject);
            }
            return "redirect:/admin/exam-param/paper";
        } else {
            return "redirect:/admin/exam/list";
        }
    }

    @RequestMapping(value = "/template")
    public String importObjectiveTemplate(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-param/paper";
    }

    @RequestMapping(value = "/export")
    public String exportFile(HttpServletRequest request, HttpServletResponse response, @RequestParam Boolean objective,
            RedirectAttributes redirectAttributes) {
        int examId = getSessionExamId(request);
        if (examId == 0) {
            return "redirect:/admin/exam/list";
        }

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

        List<QuestionDTO> list = new LinkedList<QuestionDTO>();
        ExamQuestionSearchQuery query = new ExamQuestionSearchQuery();
        query.setExamId(examId);
        query.setObjective(objective);
        query.setSort(new Sort(Direction.ASC, "pk.subjectCode"));
        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())));
        }
        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-param/paper";
    }

    @RequestMapping(value = "/import", method = RequestMethod.POST)
    public String importFile(HttpServletRequest request, MultipartFile file, @RequestParam Boolean objective,
            RedirectAttributes redirectAttributes) {
        int examId = getSessionExamId(request);
        if (examId == 0) {
            return "redirect:/admin/exam/list";
        }

        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)) {
                        questionService.deleteByExamAndSubjectAndObjective(examId, dto.getSubjectCode(), objective);

                        // 删除通过页面操作生产的试卷结构表：eb_exam_subject_paper
                        examSubjectPaperService.deleteByExamAndCodeAndObjective(examId, dto.getSubjectCode(),
                                objective ? 1 : 0);

                        for (ExamQuestion question : dto.getQuestionList()) {
                            questionService.save(question);
                        }

                        subject.setScore(dto.getTotalScore(), objective);
                        subjectService.save(subject);
                        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-param/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);
            List<? extends QuestionDTO> list = excel
                    .getDataList(objective ? ObjectiveQuestionDTO.class : SubjectiveQuestionDTO.class);
            if (list != null) {
                for (QuestionDTO dto : list) {
                    if (dto.validate()) {
                        String subjectCode = dto.getSubjectCode();
                        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;
    }
}
