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

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringEscapeUtils;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

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.ExamQuestion;
import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
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.query.ExamStudentSearchQuery;
import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
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.MarkGroupService;
import cn.com.qmth.stmms.biz.exam.service.MarkerService;
import cn.com.qmth.stmms.biz.mark.model.PictureConfigItem;
import cn.com.qmth.stmms.biz.mark.service.MarkService;
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.enums.ScorePolicy;
import cn.com.qmth.stmms.common.utils.PictureUrlBuilder;
import cn.com.qmth.stmms.common.utils.RequestUtils;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;

@Controller("markGroupController")
@RequestMapping("/admin/exam/group")
public class MarkGroupController extends BaseExamController {

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

    @Autowired
    private ExamSubjectService subjectService;

    @Autowired
    private ExamQuestionService questionService;

    @Autowired
    private MarkGroupService groupService;

    @Autowired
    private MarkerService markerService;

    @Autowired
    private ExamStudentService studentService;

    @Autowired
    private CampusService campusService;

    @Autowired
    private MarkService markService;

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

    @RequestMapping
    public String list(HttpServletRequest request, Model model, @RequestParam String subjectCode) {
        WebUser wu = RequestUtils.getWebUser(request);
        int examId = getSessionExamId(request);
        ExamSubject subject = subjectService.find(examId, subjectCode);
        if (subject == null) {
            return "redirect:/admin/exam/mark";
        }
        if (wu.isSubjectHeader() && !subjectCode.equals(wu.getUser().getSubjectCode())) {
            return "redirect:/admin/exam/mark";
        }
        List<MarkGroup> list = groupService.findByExamAndSubject(examId, subjectCode);
        for (MarkGroup group : list) {
            group.setScoreList(questionService.findByExamAndSubjectAndObjectiveAndMainNumber(examId, subjectCode, false,
                    group.getNumber()));
            group.setMarkerCount(markerService.countByExamAndSubjectAndGroup(examId, subjectCode, group.getNumber()));
            group.setCurrentCount(markService.applyCount(group));
            int percent = group.getLibraryCount() > 0
                    ? (int) (group.getMarkedCount() * 100.00 / group.getLibraryCount())
                    : 0;
            group.setPercent(percent);
        }
        model.addAttribute("resultList", list);
        model.addAttribute("subject", subject);
        model.addAttribute("subjectList", getExamSubject(examId, wu));
        return "modules/exam/groupList";
    }

    @RequestMapping("/query")
    @ResponseBody
    public JSONArray query(HttpServletRequest request, @RequestParam String subjectCode,
            @RequestParam(required = false) Boolean withDouble) {
        int examId = getSessionExamId(request);
        JSONArray array = new JSONArray();
        List<MarkGroup> list = withDouble != null && withDouble
                ? groupService.findByExamAndSubjectWithDouble(examId, subjectCode)
                : groupService.findByExamAndSubject(examId, subjectCode);
        for (MarkGroup group : list) {
            JSONObject obj = new JSONObject();
            obj.accumulate("number", group.getNumber());
            obj.accumulate("title", group.getTitle());
            obj.accumulate("score", group.getTotalScore());
            array.add(obj);
        }
        return array;
    }

    @RequestMapping("/check-count")
    @RoleRequire(Role.SCHOOL_ADMIN)
    public String ckeckCount(HttpServletRequest request, Model model, RedirectAttributes redirectAttributes,
            @RequestParam String subjectCode) {
        int examId = getSessionExamId(request);
        ExamSubject subject = subjectService.find(examId, subjectCode);
        if (subject == null) {
            return "redirect:/admin/exam/mark";
        }
        markService.updateLibraryCount(examId, subjectCode);

        redirectAttributes.addAttribute("subjectCode", subjectCode);
        return "redirect:/admin/exam/group";
    }

    @RequestMapping("/release")
    @RoleRequire(Role.SCHOOL_ADMIN)
    public String release(HttpServletRequest request, Model model, RedirectAttributes redirectAttributes,
            @RequestParam String subjectCode, @RequestParam Integer number) {
        int examId = getSessionExamId(request);
        MarkGroup group = groupService.findOne(examId, subjectCode, number);
        if (group == null) {
            return "redirect:/admin/exam/mark";
        }
        markService.releaseByGroup(group);

        redirectAttributes.addAttribute("subjectCode", subjectCode);
        return "redirect:/admin/exam/group";
    }

    @RequestMapping("/reset")
    @Transactional
    @RoleRequire(Role.SCHOOL_ADMIN)
    public String reset(HttpServletRequest request, Model model, RedirectAttributes redirectAttributes,
            @RequestParam String subjectCode, @RequestParam Integer number) {
        int examId = getSessionExamId(request);
        MarkGroup group = groupService.findOne(examId, subjectCode, number);
        if (group == null) {
            return "redirect:/admin/exam/mark";
        }
        markService.resetByGroup(group);

        redirectAttributes.addAttribute("subjectCode", subjectCode);
        return "redirect:/admin/exam/group";
    }

    @RequestMapping("/add")
    @RoleRequire(Role.SCHOOL_ADMIN)
    public String editSimple(HttpServletRequest request, Model model, @RequestParam String subjectCode) {
        int examId = getSessionExamId(request);
        ExamSubject subject = subjectService.find(examId, subjectCode);
        if (subject == null) {
            return "redirect:/admin/exam/mark";
        }
        MarkGroup group = new MarkGroup();
        group.setSubjectCode(subjectCode);
        model.addAttribute("group", group);
        model.addAttribute("scorePolicyList", ScorePolicy.values());
        return "modules/exam/groupAdd";
    }

    @RequestMapping("/edit-simple")
    @RoleRequire(Role.SCHOOL_ADMIN)
    public String editSimple(HttpServletRequest request, Model model, RedirectAttributes redirectAttributes,
            @RequestParam String subjectCode, @RequestParam Integer number) {
        int examId = getSessionExamId(request);
        MarkGroup group = groupService.findOne(examId, subjectCode, number);
        if (group != null) {
            String pictureConfig = buildPictureConfig(group);
            group.setPicList(pictureConfig);
            model.addAttribute("group", group);
            model.addAttribute("questions", questionService.findByExamAndSubjectAndObjectiveAndMainNumber(
                    group.getExamId(), group.getSubjectCode(), false, group.getNumber()));
            model.addAttribute("pictureConfig", pictureConfig);
            model.addAttribute("scorePolicyList", ScorePolicy.values());
            return "modules/exam/groupEditSimple";
        } else {
            redirectAttributes.addAttribute("subjectCode", subjectCode);
            return "redirect:/admin/exam/group";
        }
    }

    @RequestMapping("/edit-full")
    @RoleRequire(Role.SCHOOL_ADMIN)
    public String editFull(HttpServletRequest request, Model model, RedirectAttributes redirectAttributes,
            @RequestParam String subjectCode, @RequestParam Integer number) {
        int examId = getSessionExamId(request);
        MarkGroup group = groupService.findOne(examId, subjectCode, number);
        if (group != null) {
            String pictureConfig = buildPictureConfig(group);
            group.setPicList(pictureConfig);
            group.setScoreList(
                    questionService.findByExamAndSubjectAndObjectiveAndMainNumber(examId, subjectCode, false, number));
            model.addAttribute("group", group);
            model.addAttribute("pictureConfig", pictureConfig);
            model.addAttribute("scorePolicyList", ScorePolicy.values());
            return "modules/exam/groupEditFull";
        } else {
            redirectAttributes.addAttribute("subjectCode", subjectCode);
            return "redirect:/admin/exam/group";
        }
    }

    @RequestMapping("/delete")
    @Transactional
    @RoleRequire(Role.SCHOOL_ADMIN)
    public String delete(HttpServletRequest request, Model model, RedirectAttributes redirectAttributes,
            @RequestParam String subjectCode, @RequestParam Integer number) {
        int examId = getSessionExamId(request);
        MarkGroup group = groupService.findOne(examId, subjectCode, number);
        if (group != null) {
            markService.deleteGroup(group);
        }
        redirectAttributes.addAttribute("subjectCode", subjectCode);
        redirectAttributes.addAttribute("number", number);
        return "redirect:/admin/exam/group";
    }

    @SuppressWarnings("unchecked")
    @RequestMapping("/save")
    @RoleRequire(Role.SCHOOL_ADMIN)
    public String save(HttpServletRequest request, Model model, RedirectAttributes redirectAttributes,
            @RequestParam String subjectCode, @RequestParam Integer number,
            @RequestParam(required = false) String title, @RequestParam(required = false) String picList,
            @RequestParam(required = false) String intervalScoreList, @RequestParam(required = false) String scoreList,
            @RequestParam(required = false) Double doubleRate,
            @RequestParam(required = false) Double arbitrateThreshold,
            @RequestParam(required = false) Integer scorePolicy) {
        int examId = getSessionExamId(request);
        MarkGroup group = groupService.findOne(examId, subjectCode, number);
        List<ExamQuestion> questionList = questionService.findByExamAndSubjectAndObjectiveAndMainNumber(examId,
                subjectCode, false, number);
        if (group != null) {
            // quick update
            picList = StringEscapeUtils.unescapeHtml(picList);
            JSONArray array = JSONArray.fromObject(picList);
            List<PictureConfigItem> list = JSONArray.toList(array, new PictureConfigItem(), new JsonConfig());
            // List<PictureConfigItem> list = PictureConfigItem.parse(picList);
            if (list != null && !list.isEmpty()) {
                groupService.updatePicList(examId, subjectCode, number, list);
            }
            List<Double> intervalScores = buildDoubleList(intervalScoreList);
            if (intervalScores.size() == questionList.size()) {
                for (int i = 0; i < questionList.size(); i++) {
                    ExamQuestion q = questionList.get(i);
                    q.setIntervalScore(intervalScores.get(i));
                    questionService.save(q);
                }
            }
            title = StringUtils.trimToNull(title);
            if (title != null) {
                groupService.updateTitle(examId, subjectCode, number, title);
            }
            if (doubleRate != null) {
            	groupService.updateDoubleRate(examId, subjectCode, number, doubleRate);
            }
            if (arbitrateThreshold != null) {
            	groupService.updateArbitrateThreshold(examId, subjectCode, number, arbitrateThreshold);
            }
            // advance update
            ScorePolicy policy = scorePolicy != null ? ScorePolicy.findByValue(scorePolicy) : null;
            List<Double> scores = buildDoubleList(scoreList);
            if (scores.size() > 0) {
                markService.updateGroup(group, scores, policy);
            }
            redirectAttributes.addAttribute("subjectCode", subjectCode);
            redirectAttributes.addAttribute("number", number);
            return "redirect:/admin/exam/group";
        } else {
            addMessage(redirectAttributes, "找不到对应大题");
            redirectAttributes.addAttribute("subjectCode", subjectCode);
            redirectAttributes.addAttribute("number", number);
            return "redirect:/admin/exam/group/edit-simple";
        }
    }

    @SuppressWarnings("unchecked")
    @RequestMapping("/insert")
    @Transactional
    @RoleRequire(Role.SCHOOL_ADMIN)
    public String insert(HttpServletRequest request, Model model, RedirectAttributes redirectAttributes,
            @RequestParam String subjectCode, @RequestParam Integer number,
            @RequestParam(required = false) String title, @RequestParam(required = false) String picList,
            @RequestParam(required = false) String scoreList, @RequestParam(required = false) Double doubleRate,
            @RequestParam(required = false) Double arbitrateThreshold,
            @RequestParam(required = false) Integer scorePolicy) {
        int examId = getSessionExamId(request);
        MarkGroup group = groupService.findOne(examId, subjectCode, number);
        if (group != null) {
            addMessage(redirectAttributes, "大题号不能重复");
            redirectAttributes.addAttribute("subjectCode", subjectCode);
            return "redirect:/admin/exam/group/add";
        } else if (StringUtils.isBlank(picList)) {
            addMessage(redirectAttributes, "图片范围必须设置");
            redirectAttributes.addAttribute("subjectCode", subjectCode);
            return "redirect:/admin/exam/group/add";
        } else {
            // create group
            picList = StringEscapeUtils.unescapeHtml(picList);
            JSONArray array = JSONArray.fromObject(picList);
            List<PictureConfigItem> list = JSONArray.toList(array, new PictureConfigItem(), new JsonConfig());
            group = new MarkGroup(examId, subjectCode, number, StringUtils.trimToNull(title), list, 0d, doubleRate,
                    arbitrateThreshold, scorePolicy);
            List<Double> scores = buildDoubleList(scoreList);
            if (group.getTitle() != null && group.getPicList() != null && scores.size() > 0) {
                // clear and replace exam_question
                questionService.deleteByExamAndSubjectAndObjectiveAndMainNumber(examId, subjectCode, false, number);
                int i = 0;
                double totalScore = 0d;
                for (Double score : scores) {
                    i++;
                    totalScore += score;
                    ExamQuestion question = new ExamQuestion();
                    question.setExamId(examId);
                    question.setSubjectCode(subjectCode);
                    question.setMainTitle(group.getTitle());
                    question.setMainNumber(number);
                    question.setSubNumber(i);
                    question.setObjective(false);
                    question.setTotalScore(score);
                    question.setIntervalScore(1d);
                    questionService.save(question);
                }
                group.setTotalScore(totalScore);
                groupService.save(group);
                subjectService.updateScore(examId, subjectCode);
                redirectAttributes.addAttribute("subjectCode", subjectCode);
                return "redirect:/admin/exam/group";
            } else {
                addMessage(redirectAttributes, "参数有误");
                redirectAttributes.addAttribute("subjectCode", subjectCode);
                return "redirect:/admin/exam/group/add";
            }
        }
    }

    private List<Double> buildDoubleList(String content) {
        List<Double> list = new ArrayList<Double>();
        content = StringUtils.trimToNull(content);
        if (content != null) {
            String[] values = StringUtils.split(content, ",");
            if (values != null) {
                for (String value : values) {
                    try {
                        Double number = Double.valueOf(value);
                        if (number != null) {
                            list.add(number);
                        }
                    } catch (Exception e) {
                        continue;
                    }
                }
            }
        }
        return list;
    }

    @RequestMapping("/getPictureConfig")
    @RoleRequire(Role.SCHOOL_ADMIN)
    public String get(HttpServletRequest request, Model model, RedirectAttributes redirectAttributes,
            @RequestParam String subjectCode, @RequestParam Integer number) {
        int examId = getSessionExamId(request);
        ExamStudentSearchQuery query = new ExamStudentSearchQuery();
        query.setExamId(examId);
        query.setSubjectCode(subjectCode);
        query.setUpload(true);
        List<ExamStudent> examStudents = studentService.findByQuery(query).getResult();
        MarkGroup group = null;
        if (number != null) {
            group = groupService.findOne(examId, subjectCode, number);
        }
        if (examStudents.size() > 0) {
            model.addAttribute("picUrls", buildPicUrl(examStudents.get(0)));
            model.addAttribute("pictureConfig", buildPictureConfig(group));
            model.addAttribute("imageServer", imageServer);
            return "modules/mark/picConfig";
        } else {
            addMessage(redirectAttributes, "参数有误");
            redirectAttributes.addAttribute("subjectCode", subjectCode);
            return "redirect:/admin/exam/group";
        }
    }

    private String buildPictureConfig(MarkGroup group) {
        String json = "";
        if (group != null) {
            try {
                ObjectMapper mapper = new ObjectMapper();
                json = mapper.writeValueAsString(group.getPictureConfigList());
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        return json;
    }

    private List<String> buildPicUrl(ExamStudent examStudent) {
        Campus campus = campusService.findBySchoolAndName(examStudent.getSchoolId(), examStudent.getCampusName());
        List<String> picUrls = PictureUrlBuilder.getSliceUrls(examStudent.getExamId(), campus.getId(),
                examStudent.getSubjectCode(), examStudent.getExamNumber(), examStudent.getSliceCount());
        return picUrls;
    }
}
