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

import java.math.BigDecimal;
import java.util.*;
import java.util.Map.Entry;

import org.apache.commons.lang.StringUtils;

import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
import cn.com.qmth.stmms.biz.mark.model.MarkConfigItem;
import cn.com.qmth.stmms.common.enums.QuestionType;
import cn.com.qmth.stmms.common.utils.BigDecimalUtils;

public class SubjectQuestionDTO {

    private static final String NULL_PAPER_TYPE_PLACEHOLDER = "#";

    private int examId;

    private String subjectCode;

    private List<ExamQuestion> list;

    private double totalScore;

    private boolean objective;

    private Integer trialCount;

    private Map<String, List<ExamQuestion>> paperTypeList;

    private Map<Integer, MarkGroup> groups;

    public SubjectQuestionDTO(int examId, String subjectCode, boolean objective) {
        this.examId = examId;
        this.subjectCode = subjectCode;
        this.list = new LinkedList<ExamQuestion>();
        this.paperTypeList = new HashMap<>();
        this.groups = new HashMap<Integer, MarkGroup>();
        this.totalScore = 0d;
        this.objective = objective;
        this.trialCount = 0;
    }

    public void addQuestion(ExamQuestion question) {
        if (question != null) {
            question.setExamId(examId);
            list.add(question);

            if (objective) {
                String paperType = question.getPaperType();
                if (paperType == null) {
                    paperType = NULL_PAPER_TYPE_PLACEHOLDER;
                }
                List<ExamQuestion> list = paperTypeList.get(paperType);
                if (list == null) {
                    list = new ArrayList<>();
                    paperTypeList.put(paperType, list);
                }
                list.add(question);
            } else {
                MarkGroup group = groups.get(question.getGroupNumber());
                if (group == null) {
                    group = new MarkGroup(examId, subjectCode, question.getGroupNumber(),
                            MarkConfigItem.parse(question.getPicList()), 0d, question.getDoubleRate(),
                            question.getArbitrateThreshold(), question.getScorePolicy(), question.getMarkMode(),
                            question.getTrialCount(), false, false, 1, false);
                    group.setImportQuestionList(new LinkedList<>());
                    groups.put(question.getGroupNumber(), group);
                }
                group.getImportQuestionList().add(question);
                this.trialCount = question.getTrialCount() != null && question.getTrialCount() > 0
                        ? question.getTrialCount()
                        : 0;
                // group.setTotalScore(group.getTotalScore() +
                // question.getTotalScore());
                // totalScore += question.getTotalScore();
            }
        }
    }

    public List<ExamQuestion> getQuestionList() {
        return list;
    }

    public String getSubjectCode() {
        return subjectCode;
    }

    public double getTotalScore() {
        return totalScore;
    }

    public Map<Integer, MarkGroup> getGroups() {
        return groups;
    }

    public Integer getTrialCount() {
        return trialCount;
    }

    public void setTrialCount(Integer trialCount) {
        this.trialCount = trialCount;
    }

    public boolean validate(List<String> error, Map<Integer, String> titleMap) {
        if (list.size() > 0) {
            Set<String> numberSet = new HashSet<String>();
            // Map<Integer, Integer> groupNumberMap = new HashMap<>();
            try {
                // 基本字段合法性校验
                for (ExamQuestion question : list) {
                    if (StringUtils.isBlank(question.getMainTitle())) {
                        error.add("[" + subjectCode + "] 有大题名称为空的记录");
                        return false;
                    }
                    if (question.getMainTitle().length() > 30) {
                        error.add("[" + subjectCode + "] 有大题名称超过30个字的记录");
                        return false;
                    }
                    if (question.getMainNumber() == null || StringUtils.isBlank(question.getSubNumber())) {
                        error.add("[" + subjectCode + "] 有题号为空的记录");
                        return false;
                    }
                    if (!StringUtils.isNumeric(question.getSubNumber())) {
                        error.add("[" + subjectCode + "] 有小题号不是数字的记录");
                        return false;
                    }
                    if (question.getTotalScore() == null) {
                        error.add("[" + subjectCode + "] 有满分为空的记录");
                        return false;
                    }
                    if (countDecimalPlaces(question.getTotalScore()) > 2) {
                        error.add("[" + subjectCode + "] 有满分为小数超2位的记录");
                        return false;
                    }

                    if (!objective && countDecimalPlaces(question.getIntervalScore()) > 2) {
                        error.add("[" + subjectCode + "] 有间隔分为小数超2位的记录");
                        return false;
                    }
                    if (!objective && question.getIntervalScore() <= 0) {
                        error.add("[" + subjectCode + "] 有间隔分有小于等于0的记录");
                        return false;
                    }
                    if (objective && StringUtils.isBlank(question.getAnswer())) {
                        error.add("[" + subjectCode + "] 有答案为空的记录");
                        return false;
                    }
                    if (objective && question.getType() == null) {
                        error.add("[" + subjectCode + "] 大题号" + question.getMainNumber() + "有题型为空的记录");
                        return false;
                    }
                    if (QuestionType.TRUE_OR_FALSE.equals(question.getType())
                            && (!question.getAnswer().contains("A") && !question.getAnswer().contains("B"))) {
                        error.add("[" + subjectCode + "] 大题号" + question.getMainNumber() + "有判断题标答不为A或B的记录");
                        return false;
                    }
                    if (QuestionType.SINGLE.equals(question.getType()) && question.getAnswer().length() > 1) {
                        error.add("[" + subjectCode + "] 大题号" + question.getMainNumber() + "有单选题标答大于一个的记录");
                        return false;
                    }
                    String title = titleMap.get(question.getMainNumber());
                    if (title != null && !title.equals(question.getMainTitle())) {
                        error.add("[" + subjectCode + "] 大题号" + question.getMainNumber() + "有名称不一致的记录");
                        return false;
                    } else {
                        titleMap.put(question.getMainNumber(), question.getMainTitle());
                    }

                    // 不再限制一个大题只能属于一个评卷分组
                    // Integer groupNumber =
                    // groupNumberMap.get(question.getMainNumber());
                    // if (groupNumber != null &&
                    // !groupNumber.equals(question.getGroupNumber())) {
                    // error.add("[" + subjectCode + "] 大题号" +
                    // question.getMainNumber() + "有评卷分组不一致的记录");
                    // return false;
                    // } else {
                    // groupNumberMap.put(question.getMainNumber(),
                    // question.getGroupNumber());
                    // }

                    String number = question.getQuestionNumber();
                    if (objective) {
                        number = StringUtils.trimToEmpty(question.getPaperType()) + " " + number;
                    }
                    if (numberSet.contains(number)) {
                        error.add("[" + subjectCode + "] 题号" + number + "有重复记录");
                        return false;
                    } else {
                        numberSet.add(number);
                    }
                }

                // 客观题时额外校验不同试卷类型的总分需要一致
                if (objective) {
                    totalScore = -1;
                    List<ExamQuestion> questions = null;
                    for (Entry<String, List<ExamQuestion>> entry : paperTypeList.entrySet()) {
                        BigDecimal score = BigDecimal.ZERO;
                        for (ExamQuestion question : entry.getValue()) {
                            score = score.add(BigDecimal.valueOf(question.getTotalScore()));
                        }
                        if (totalScore == -1) {
                            totalScore = score.doubleValue();
                        } else if (totalScore != score.doubleValue()) {
                            error.add("[" + subjectCode + "] 多个试卷类型总分不一致");
                            return false;
                        }
                        if (questions != null) {
                            String message = check(questions, entry.getValue());
                            if (message != null) {
                                error.add("[" + subjectCode + "] 多个试卷类型" + message);
                                return false;
                            }
                        } else {
                            questions = entry.getValue();
                        }
                    }
                }
                return true;
            } finally {
                numberSet.clear();
                titleMap.clear();
                // groupNumberMap.clear();
            }
        } else {
            return false;
        }
    }

    public int countDecimalPlaces(double number) {
        String num = Double.toString(number);
        int decimalPointIndex = num.indexOf('.');
        if (decimalPointIndex == -1) {
            return 0;
        }
        return num.length() - decimalPointIndex - 1;
    }

    private String check(List<ExamQuestion> questions, List<ExamQuestion> value) {
        if (questions.size() != value.size()) {
            return "题目总数不一致";
        }
        Map<Integer, Integer> subCountMap = new HashMap<Integer, Integer>();
        Map<Integer, Double> mainScoreMap = new HashMap<Integer, Double>();
        int maniCount = 0;
        for (ExamQuestion question : questions) {
            if (question.getTotalScore() != 0) {
                Integer subCount = subCountMap.get(question.getMainNumber());
                if (subCount != null) {
                    subCountMap.put(question.getMainNumber(), subCount + 1);
                    Double mainScore = mainScoreMap.get(question.getMainNumber());
                    mainScoreMap.put(question.getMainNumber(),
                            BigDecimalUtils.add(mainScore, question.getTotalScore()));
                } else {
                    subCountMap.put(question.getMainNumber(), 1);
                    mainScoreMap.put(question.getMainNumber(), question.getTotalScore());
                    maniCount++;
                }
            }
        }

        Map<Integer, Integer> subCountMap1 = new HashMap<Integer, Integer>();
        Map<Integer, Double> mainScoreMap1 = new HashMap<Integer, Double>();
        int maniCount1 = 0;
        for (ExamQuestion question : value) {
            if (question.getTotalScore() != 0) {
                Integer subCount = subCountMap1.get(question.getMainNumber());
                if (subCount != null) {
                    subCountMap1.put(question.getMainNumber(), subCount + 1);
                    Double mainScore = mainScoreMap1.get(question.getMainNumber());
                    mainScoreMap1.put(question.getMainNumber(),
                            BigDecimalUtils.add(mainScore, question.getTotalScore()));
                } else {
                    subCountMap1.put(question.getMainNumber(), 1);
                    mainScoreMap1.put(question.getMainNumber(), question.getTotalScore());
                    maniCount1++;
                }
            }
        }
        if (maniCount != maniCount1) {
            return "大题数量不一致";
        }
        for (Integer mainNumber : subCountMap.keySet()) {
            if (!subCountMap.get(mainNumber).equals(subCountMap1.get(mainNumber))) {
                return "小题数量不一致";
            }
            if (!mainScoreMap.get(mainNumber).equals(mainScoreMap1.get(mainNumber))) {
                return "大题总分不一致";
            }
        }
        return null;
    }

    public boolean validateGroupNumber(List<String> error) {
        Map<String, Integer> trialMap = new HashMap<String, Integer>();
        for (ExamQuestion question : list) {
            if (question.getGroupNumber() == null || question.getGroupNumber() < 0) {
                error.add("[" + subjectCode + "] 有评卷分组为空的记录");
                return false;
            }
            Integer trialCount = trialMap.get(question.getSubjectCode());
            if (trialCount == null) {
                trialCount = question.getTrialCount();
                trialMap.put(question.getSubjectCode(), question.getTrialCount());
            }
            if (question.getTrialCount() != trialCount) {
                error.add("[" + subjectCode + "] 有试评数量不一致的记录");
                return false;
            }
        }
        return true;
    }

}
