package com.qxgmat.service.extend;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.nuliji.tools.Transform;
import com.nuliji.tools.exception.ParameterException;
import com.qxgmat.data.constants.enums.QuestionContentType;
import com.qxgmat.data.constants.enums.QuestionType;
import com.qxgmat.data.constants.enums.SettingKey;
import com.qxgmat.data.constants.enums.module.PaperModule;
import com.qxgmat.data.constants.enums.module.QuestionModule;
import com.qxgmat.data.dao.entity.*;
import com.qxgmat.data.relation.entity.QuestionNoRelation;
import com.qxgmat.data.relation.entity.SentenceQuestionRelation;
import com.qxgmat.data.relation.entity.UserReportLimitRelation;
import com.qxgmat.data.relation.entity.UserReportRelation;
import com.qxgmat.service.*;
import com.qxgmat.service.annotation.*;
import com.qxgmat.service.inline.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class QuestionFlowService {

    @Resource
    private ExercisePaperService exercisePaperService;

    @Resource
    private PreviewService previewService;

    @Resource
    private ExaminationPaperService examinationPaperService;

    @Resource
    private QuestionNoService questionNoService;

    @Resource
    private QuestionService questionService;

    @Resource
    private SentenceQuestionService sentenceQuestionService;

    @Resource
    private SentencePaperService sentencePaperService;

    @Resource
    private TextbookQuestionService textbookQuestionService;

    @Resource
    private TextbookPaperService textbookPaperService;

    @Resource
    private UsersService usersService;

    @Resource
    private UserReportService userReportService;

    @Resource
    private UserPaperService userPaperService;

    @Resource
    private UserQuestionService userQuestionService;

    @Resource
    private ToolsService toolsService;

    // 初始化试卷的callback，根据试卷模块进行后续处理
    private Map<PaperModule, InitPaper> initPaperCallback = new HashMap<>();

    // 初始化报告的callback，根据试卷模块进行后续处理
    private Map<PaperModule, InitReport> initReportCallback = new HashMap<>();

    // 初始化题目，根据试卷模块进行选题处理
    private Map<PaperModule, InitQuestion> nextCallback = new HashMap<>();

    // 提交答题的callback，根据试题模块正确判断
    private Map<QuestionModule, SubmitQuestion> submitCallback = new HashMap<>();

    // 提交答题的callback，根据试题模块后续统计，会过滤满足剔除条件
    private Map<QuestionModule, SubmitAfterQuestion> submitAfterCallback = new HashMap<>();

    // 完成试卷的callback，根据试卷模块进行后续处理
    private Map<PaperModule, StatReport> finishCallback = new HashMap<>();

    public QuestionFlowService(){
        initPaperCallback.put(PaperModule.EXERCISE, (paper, id)->{
           exercisePaperService.initUserPaper(paper, id);
            // 获取考题时间
            List<QuestionNoRelation> relationList = questionNoService.listWithRelationByIds(paper.getQuestionNoIds());
            Integer time = toolsService.computerTime(relationList);
            paper.setTime(time);
        });
        initPaperCallback.put(PaperModule.PREVIEW, (paper, id)->{
            // 后台主动修改，无需变更
        });
        initPaperCallback.put(PaperModule.ERROR, (paper, id)->{
            // 用户主动添加，无需变更
        });
        initPaperCallback.put(PaperModule.COLLECT, (paper, id)->{
            // 用户主动添加，无需变更
        });
        initPaperCallback.put(PaperModule.SENTENCE, (paper, id)->{
            sentencePaperService.initUserPaper(paper, id);
        });
        initPaperCallback.put(PaperModule.TEXTBOOK, (paper, id)->{
            textbookPaperService.initUserPaper(paper, id);
        });

        initReportCallback.put(PaperModule.EXERCISE, (report, paper)->{
            JSONObject setting = report.getSetting();
            if (setting.getBoolean("disorder")){
                // 随机试题
                report.setQuestionNoIds(this.randomQuestionNoIds(paper.getQuestionNoIds()));
            }
        });
        initReportCallback.put(PaperModule.PREVIEW, (report, paper)->{
            JSONObject setting = report.getSetting();
            if (setting.getBoolean("disorder")){
                // 随机试题
                report.setQuestionNoIds(this.randomQuestionNoIds(paper.getQuestionNoIds()));
            }
        });
        initReportCallback.put(PaperModule.COLLECT, (report, paper)->{
            JSONObject setting = report.getSetting();
            if (setting.getBoolean("disorder")){
                // 随机试题
                report.setQuestionNoIds(this.randomQuestionNoIds(paper.getQuestionNoIds()));
            }
        });
        initReportCallback.put(PaperModule.ERROR, (report, paper)->{
            JSONObject setting = report.getSetting();
            if (setting.getBoolean("disorder")){
                // 随机试题
                report.setQuestionNoIds(this.randomQuestionNoIds(paper.getQuestionNoIds()));
            }
        });
        initReportCallback.put(PaperModule.SENTENCE, (paper, report)->{
            // 无特殊设置
        });
        initReportCallback.put(PaperModule.TEXTBOOK, (paper, report)->{
            // 无特殊设置
        });

        nextCallback.put(PaperModule.EXERCISE, (question, report, lastQuestion)->{
            Integer questionNoId = this.nextId(report.getQuestionNoIds(), lastQuestion!=null ? lastQuestion.getQuestionNoId():null);
            if (questionNoId == 0) return false;
            this.bindQuestionNo(question, questionNoId);
            // 设定最后一次练习记录
            usersService.edit(User.builder().id(question.getUserId()).latestExercise(report.getPaperId()).build());
            return true;
        });
        nextCallback.put(PaperModule.PREVIEW, (question, report, lastQuestion)->{
            Integer questionNoId = this.nextId(report.getQuestionNoIds(), lastQuestion!=null ? lastQuestion.getQuestionNoId():null);
            if (questionNoId == 0) return false;
            this.bindQuestionNo(question, questionNoId);
            return true;
        });
        nextCallback.put(PaperModule.COLLECT, (question, report, lastQuestion)->{
            Integer questionNoId = this.nextId(report.getQuestionNoIds(), lastQuestion!=null ? lastQuestion.getQuestionNoId():null);
            if (questionNoId == 0) return false;
            this.bindQuestionNo(question, questionNoId);
            return true;
        });
        nextCallback.put(PaperModule.ERROR, (question, report, lastQuestion)->{
            Integer questionNoId = this.nextId(report.getQuestionNoIds(), lastQuestion!=null ? lastQuestion.getQuestionNoId():null);
            if (questionNoId == 0) return false;
            this.bindQuestionNo(question, questionNoId);
            // 设定最后一次错题记录
            usersService.edit(User.builder().id(question.getUserId()).latestError(report.getPaperId()).build());
            return true;
        });
        nextCallback.put(PaperModule.SENTENCE, (question, report, lastQuestion)->{
            Integer questionNoId = this.nextId(report.getQuestionNoIds(), lastQuestion!=null ? lastQuestion.getQuestionNoId():null);
            if (questionNoId == 0) return false;
            SentenceQuestion relation = sentenceQuestionService.get(questionNoId);
            question.setQuestionNoId(relation.getId());
            question.setQuestionId(relation.getQuestionId());
            question.setTime(0);
            return true;
        });
        nextCallback.put(PaperModule.TEXTBOOK, (question, report, lastQuestion)->{
            Integer questionNoId = this.nextId(report.getQuestionNoIds(), lastQuestion!=null ? lastQuestion.getQuestionNoId():null);
            if (questionNoId == 0) return false;
            SentenceQuestion relation = sentenceQuestionService.get(questionNoId);
            question.setQuestionNoId(relation.getId());
            question.setQuestionId(relation.getQuestionId());
            question.setTime(0);
            return true;
        });

        submitCallback.put(QuestionModule.BASE, (userQuestion)->{
            // 判断答题情况
            JSONObject userAnswer = userQuestion.getUserAnswer();
            Question question = questionService.get(userQuestion.getQuestionId());
            JSONObject answer = question.getAnswer();

            String type = question.getContent().getString("type");
            QuestionContentType contentType = QuestionContentType.ValueOf(type);
            JSONArray userQuestions = userAnswer.getJSONArray("questions");
            JSONArray questions = answer.getJSONArray("questions");
            for(int i = 0; i< questions.size(); i++){
                JSONObject userOne = userQuestions.getJSONObject(i);
                JSONObject one = questions.getJSONObject(i);
                switch(contentType){
                    case DOUBLE:
                        JSONArray userDoubleList = userOne.getJSONArray("double");
                        JSONArray doubleList = one.getJSONArray("double");
//                        if(JSONObject.toJSON(userDoubleList) != JSONObject.toJSON(doubleList)){
//                            return false;
//                        }

                        for(int j = 0; j < doubleList.size(); j++){
                            JSONArray singleList = doubleList.getJSONArray(j);
                            JSONArray userSingleList = userDoubleList.getJSONArray(i);
                            for (int k = 0; k < singleList.size(); k++){
                                if (userSingleList.getBoolean(k) != singleList.getBoolean(k)){
                                    return false;
                                }
                            }
                        }
                        break;
                    case SINGLE:
                    case INLINE:
                    default:
                        JSONArray userSingleList = userOne.getJSONArray("single");
                        JSONArray singleList = one.getJSONArray("single");
//                        if(JSONObject.toJSON(userSingleList) != JSONObject.toJSON(singleList)){
//                            return false;
//                        }
                        for(int j = 0; j < singleList.size(); j++){
                            if (userSingleList.getBoolean(j) != singleList.getBoolean(j)){
                                return false;
                            }
                        }
                }
            }
            return true;
        });
        submitCallback.put(QuestionModule.SENTENCE, (userQuestion)->{
            // 判断答题情况
            JSONObject userAnswer = userQuestion.getUserAnswer();
            Question question = questionService.get(userQuestion.getQuestionId());
            JSONObject answer = question.getAnswer();

            boolean correct = true;
            JSONObject detail = new JSONObject();

            boolean subjectCorrect = this.sentenceAnswer(userAnswer.getJSONArray("subject"), answer.getJSONArray("subject"));
            detail.put("subject", subjectCorrect);
            correct = correct & subjectCorrect;

            boolean predicateCorrect = this.sentenceAnswer(userAnswer.getJSONArray("predicate"), answer.getJSONArray("predicate"));
            detail.put("predicate", predicateCorrect);
            correct = correct & predicateCorrect;

            boolean objectCorrect = this.sentenceAnswer(userAnswer.getJSONArray("object"), answer.getJSONArray("object"));
            detail.put("object", objectCorrect);
            correct = correct & objectCorrect;

            boolean optionsCorrect = this.sentenceAnswer(userAnswer.getJSONArray("options"), answer.getJSONArray("options"));
            detail.put("options", optionsCorrect);
//            correct = correct & optionsCorrect;

            userQuestion.setDetail(detail);
            // 主谓宾判断正确，答题正确
            return correct;
        });

        submitAfterCallback.put(QuestionModule.BASE, (userQuestion, question)->{
            // 作文不统计
            if (!question.getQuestionType().equals(QuestionType.AWA.key)){
                return;
            }
            // 更新题目及题目编号统计
            questionNoService.accumulation(userQuestion);
            questionService.accumulation(userQuestion);
            // 统计答案分布
            JSONObject answerDistributed = question.getAnswerDistributed();
            JSONObject answer = question.getAnswer();
            JSONObject userAnswer = userQuestion.getUserAnswer();

            String type = question.getContent().getString("type");
            QuestionContentType contentType = QuestionContentType.ValueOf(type);
            JSONArray userQuestions = userAnswer.getJSONArray("questions");
            JSONArray questions = answer.getJSONArray("questions");
            JSONArray distributed = answerDistributed.getJSONArray("questions");
            if (distributed == null || distributed.isEmpty()){
                distributed = new JSONArray();
                answerDistributed.put("questions", distributed);
            }
            for(int i = 0; i< questions.size(); i++){
                JSONObject userOne = userQuestions.getJSONObject(i);
                JSONObject one = questions.getJSONObject(i);
                JSONObject target = distributed.getJSONObject(i);
                if (target == null || target.isEmpty()){
                    target = new JSONObject();
                    distributed.add(i, target);
                }
                switch(contentType){
                    case DOUBLE:
                        JSONArray userDoubleList = userOne.getJSONArray("double");
                        JSONArray doubleList = one.getJSONArray("double");
                        JSONArray doubleResult = target.getJSONArray("double");
                        if (doubleResult == null || doubleResult.isEmpty()){
                            doubleResult = new JSONArray();
                            target.put("double", doubleResult);
                        }
                        for(int j = 0; j < doubleList.size(); j++){
                            JSONArray singleList = doubleList.getJSONArray(j);
                            JSONArray userSingleList = userDoubleList.getJSONArray(i);
                            JSONArray singleResult = doubleResult.getJSONArray(j);
                            if (singleResult == null){
                                singleResult = new JSONArray(0);
                                doubleResult.set(j, singleResult);
                            }
                            for (int k = 0; k < singleList.size(); k++){
                                if (singleResult.get(k) == null){
                                    singleResult.set(k, 0);
                                }
                                if (userSingleList.getBoolean(k)){
                                    singleResult.set(k, singleResult.getIntValue(k)+1);
                                }
                            }
                        }
                        break;
                    case SINGLE:
                    case INLINE:
                    default:
                        JSONArray userSingleList = userOne.getJSONArray("single");
                        JSONArray singleList = one.getJSONArray("single");
                        JSONArray singleResult = target.getJSONArray("single");
                        if (singleResult == null || singleResult.isEmpty()){
                            singleResult = new JSONArray();
                            target.put("single", singleResult);
                        }
                        for(int j = 0; j < singleList.size(); j++){
                            if (singleResult.get(j) == null){
                                singleResult.set(j, 0);
                            }
                            if (userSingleList.getBoolean(j)){
                                singleResult.set(j, singleResult.getIntValue(j)+1);
                            }
                        }

                }
            }
            questionService.edit(Question.builder().id(question.getId())
                    .answer(answerDistributed)
                    .build());

        });
        submitAfterCallback.put(QuestionModule.SENTENCE, (userQuestion, question)->{
            // 更新题目及题目编号统计
            questionService.accumulation(userQuestion);
            sentenceQuestionService.accumulation(userQuestion);
        });

        finishCallback.put(PaperModule.EXERCISE, (report, questionList)->{
            report.setDetail(this.statExerciseReport(report, questionList));
        });
        finishCallback.put(PaperModule.PREVIEW, (report, questionList)->{
            report.setDetail(this.statExerciseReport(report, questionList));
        });
        finishCallback.put(PaperModule.COLLECT, (report,questionList)->{
            report.setDetail(this.statExerciseReport(report, questionList));
        });
        finishCallback.put(PaperModule.ERROR, (report, questionList)->{
            report.setDetail(this.statExerciseReport(report, questionList));
        });
        finishCallback.put(PaperModule.SENTENCE, (report, questionList)->{
            report.setDetail(this.statSentenceReport(report, questionList));
        });
        finishCallback.put(PaperModule.EXAMINATION, (report, questionList)->{

        });
        finishCallback.put(PaperModule.TEXTBOOK, (report, questionList)->{

        });
    }


    /**
     * 开始新一轮做题
     * @param userId
     * @param module
     * @param paperId
     * @param setting
     * @return
     */
    @Transactional
    public UserReportRelation start(Integer userId, PaperModule module, Integer paperId, JSONObject setting){
        UserPaper paper = userPaperService.getByPaper(userId, module, paperId, initPaperCallback.get(module));
        // 查找对应的report是否有，如果没有或reset为1，则添加
        if (paper.getIsReset() > 0) {
            paper.setIsReset(0);
            userPaperService.edit(paper);
        }
        // 记录考试设置
        UserReport userReport = userReportService.addByPaper(paper, setting, initReportCallback.get(module));

        return relationReport(userReport);
    }

    /**
     * 继续做题：判断是否可以继续
     * @param userId
     * @param userReportId
     * @return
     */
    public UserReportRelation continueReport(Integer userId, Integer userReportId){
        UserReport userReport = userReportService.get(userReportId);
        if (!userReport.getUserId().equals(userId)){
            throw new ParameterException("试卷不存在");
        }
        if (userReport.getDetail() != null && userReport.getFinishTime() != null){
            throw new ParameterException("做题结束");
        }
        if (userReport.getUserNumber()>=userReport.getQuestionNumber()){
            throw new ParameterException("答题结束，请提交完成");
        }

        return relationReport(userReport);
    }

    /**
     * 获取单个report信息：基础
     * @param userId
     * @param userReportId
     * @return
     */
    public UserReportRelation baseReport(Integer userId, Integer userReportId){
        UserReport userReport = userReportService.get(userReportId);
        if (!userReport.getUserId().equals(userId)){
            throw new ParameterException("试卷不存在");
        }

        return relationReport(userReport);
    }

    /**
     * 获取report的下一道题
     * @param userId
     * @param userReportId
     * @return
     */
    public UserQuestion next(Integer userId, Integer userReportId){
        UserQuestion userQuestion = userQuestionService.getLastByReport(userId, userReportId);
        // 查找未完成的questionId
        if (userQuestion==null || userQuestion.getUserTime() >0){
            // 创建新的question
            UserReport report = userReportService.get(userReportId);
            if (!report.getUserId().equals(userId)){
                throw new ParameterException("试卷不存在");
            }
            userQuestion = userQuestionService.addByReport(report, userQuestion, nextCallback.get(PaperModule.ValueOf(report.getPaperModule())));
        }

        return userQuestion;
    }

    /**
     * 提交试题
     * @param userId
     * @param userQuestionId
     * @param answer
     * @return
     */
    @Transactional
    public Boolean submit(Integer userId, Integer userQuestionId, Integer time, JSONObject answer){
        UserQuestion userQuestion = userQuestionService.get(userQuestionId);
        if (!userQuestion.getUserId().equals(userId)){
            throw new ParameterException("题目不存在");
        }
        userQuestion.setTime(time);
        userQuestion.setUserAnswer(answer);

        UserReport userReport = userReportService.get(userQuestion.getReportId());

        // 根据report模块获取试题所属模块
        QuestionModule module = QuestionModule.WithPaper(PaperModule.ValueOf(userReport.getPaperModule()));
        SubmitQuestion callback = submitCallback.get(module);
        Boolean result = callback.callback(userQuestion);
        userQuestion.setIsCorrect(result ? 1 : 0);
        userQuestionService.edit(userQuestion);

        // 根据剔除逻辑判断是否统计
        if (toolsService.filterTime(userQuestion)){
            Question question = questionService.get(userQuestion.getQuestionId());
            SubmitAfterQuestion afterCallback = submitAfterCallback.get(module);
            afterCallback.callback(userQuestion, question);
        }

        // 更新对应report记录
        userReportService.accumulation(userQuestion);
        return true;
    }

    /**
     * 完成试卷，进行试卷分析
     * @param userId
     * @param userReportId
     * @return
     */
    @Transactional
    public Boolean finish(Integer userId, Integer userReportId){
        UserReport userReport = userReportService.get(userReportId);
        if (!userReport.getUserId().equals(userId)){
            throw new ParameterException("试卷不存在");
        }
        if (!userReport.getQuestionNumber().equals(userReport.getUserNumber())){
            throw new ParameterException("试卷未完成");
        }
        if (userReport.getDetail() != null && userReport.getFinishTime() != null){
            throw new ParameterException("做题结束");
        }
        userReport.setFinishTime(new Date());
        List<UserQuestion> userQuestionList = userQuestionService.listByReport(userId, userReportId);
        // 分析做题结果
        StatReport callback = finishCallback.get(PaperModule.ValueOf(userReport.getPaperModule()));
        callback.callback(userReport, userQuestionList);
        userReportService.edit(userReport);

        // 统计: 更新对应paper记录
        userPaperService.accumulation(userReport);
        return true;
    }

    /**
     * 重新开始一份试卷：设定试卷reset=1，列表不绑定最后一次考试记录
     * @param paperId
     * @param userId
     * @return
     */
    public Boolean restart(Integer paperId, Integer userId){
        return userPaperService.reset(paperId, userId);
    }

    /**
     * 获取报告题目列表
     * @param userReportId
     * @param userId
     * @return
     */
    public List<UserQuestion> listByReport(Integer userReportId, Integer userId){

        List<UserQuestion> userQuestionList = userQuestionService.listByReport(userId, userReportId);
        return userQuestionList;
    }

    /**
     * 乱序生成题目列表
     * @param questionNoIds
     * @return
     */
    private Integer[] randomQuestionNoIds(Integer[] questionNoIds){
        Integer[] ran = new Integer[questionNoIds.length];
        List<Integer> base = Arrays.stream(questionNoIds).collect(Collectors.toList());
        int length = base.size();
        for(int i = 0; i < ran.length; i++){
            ran[i] = base.remove((int)(Math.random()*length));
            length -= 1;
        }
        return ran;
    }

    /**
     * 顺序获取下一题
     * @param ids
     * @param id
     * @return
     */
    private Integer nextId(Integer[] ids, Integer id){
        if (id == null) return ids[0];
        boolean flag = false;
        for(Integer a : ids){
            if (a.equals(id)){
                flag = true;
                continue;
            }
            if (flag){
                return a;
            }
        }
        return 0;
    }

    /**
     * 关联绑定questionNo类型试题
     * @param question
     * @param questionNoId
     */
    private void bindQuestionNo(UserQuestion question, Integer questionNoId){
        QuestionNoRelation relation = questionNoService.getWithRelation(questionNoId);
        question.setQuestionNoId(relation.getId());
        question.setQuestionId(relation.getQuestionId());
        Integer time = toolsService.computerTime(relation);
        question.setTime(time);
    }

    /**
     * 获取报表关联试卷
     * @param p
     * @return
     */
    private UserReportRelation relationReport(UserReport p){
        UserReportRelation relation = Transform.convert(p, UserReportRelation.class);

        UserPaper paper = userPaperService.get(p.getPaperId());
        relation.setPaper(paper);
        return relation;
    }

    /**
     * 长难句单个选项答案判断
     * @param userAnswer
     * @param answer
     * @return
     */
    private Boolean sentenceAnswer(JSONArray userAnswer, JSONArray answer){
        // 数量一致，并且都包含
        if (userAnswer.size() == answer.size()){
            for(Object s : userAnswer){
                if (!answer.contains(s)){
                    return false;
                }
            }
        }else{
            return false;
        }
        return true;
    }

    /**
     * 根据练习报告格式，统计信息
     * @param report
     * @param questionList
     * @return
     */
    private JSONObject statExerciseReport(UserReport report, List<UserQuestion> questionList){
        UserPaper paper = userPaperService.get(report.getPaperId());
        Collection questionNoIds = Transform.getIds(questionList, UserQuestion.class, "questionNoId");
        Map<Number, QuestionNoRelation> relationMap = questionNoService.mapWithRelationByIds((Integer[])questionNoIds.toArray());

        // report
        JSONObject detail = new JSONObject();
        JSONArray pace = new JSONArray();
        for (UserQuestion userQuestion : questionList){
            // 每题用时
            JSONObject one = new JSONObject();
            one.put("time", userQuestion.getTime());
            one.put("userTime", userQuestion.getUserTime());
            one.put("no", userQuestion.getNo());
            pace.add(one);
        }
        detail.put("pace", pace);

        JSONObject difficultMap  = new JSONObject();
        for (UserQuestion userQuestion:questionList){
            // 难度正确度
            QuestionNoRelation relation = relationMap.get(userQuestion.getQuestionNoId());
            String d = relation.getQuestion().getDifficult();
            JSONObject t = difficultMap.getJSONObject(d);
            if (t == null){
                t = new JSONObject();
                t.put("key", d);
                t.put("userNumber", 1);
                t.put("userCorrect", userQuestion.getIsCorrect());
                t.put("totalNumber", relation.getTotalNumber());
                t.put("totalCorrect", relation.getTotalCorrect());
                difficultMap.put(d, t);
            }else{
                t.put("userNumber", t.getInteger("userNumber") + 1);
                t.put("userCorrect", t.getInteger("userCorrect") + userQuestion.getIsCorrect());
                t.put("totalNumber", t.getInteger("totalNumber") + relation.getTotalNumber());
                t.put("totalCorrect", t.getInteger("totalCorrect") + relation.getTotalCorrect());
            }
        }
        JSONArray difficult = new JSONArray();
        difficult.addAll(difficultMap.values());
        detail.put("difficult", difficult);

        JSONObject placeMap = new JSONObject();
        for (UserQuestion userQuestion:questionList){
            // 考点用时，以及正确度
            QuestionNoRelation relation = relationMap.get(userQuestion.getQuestionNoId());
            String d = relation.getQuestion().getPlace();
            JSONObject t = placeMap.getJSONObject(d);
            if (t == null){
                t = new JSONObject();
                t.put("key", d);
                t.put("userNumber", 1);
                t.put("userCorrect", userQuestion.getIsCorrect());
                t.put("userTime", userQuestion.getUserTime());
                placeMap.put(d, t);
            }else{
                t.put("userNumber", t.getInteger("userNumber") + 1);
                t.put("userCorrect", t.getInteger("userCorrect") + userQuestion.getIsCorrect());
                t.put("userTime", t.getInteger("userTime") + userQuestion.getUserTime());
            }
        }
        JSONArray place = new JSONArray();
        place.addAll(placeMap.values());
        detail.put("place", place);

        JSONObject limit = new JSONObject();
        // 限时统计考试正确度
        UserReportLimitRelation relation = userReportService.statLimit(report.getPaperModule(), report.getModuleId());
        limit.put("userNumber", relation.getUserNumber());
        limit.put("userCorrect", relation.getUserCorrect());
        detail.put("limit", limit);

        JSONObject info = new JSONObject();
        // 基本信息
        info.put("times", paper.getTimes() + 1); // paper还未计数
        info.put("finishTime", report.getFinishTime());
        info.put("userTime", report.getUserTime());
        info.put("time", report.getTime());
        info.put("questionNumber", report.getQuestionNumber());
        info.put("userNumber", report.getUserNumber());
        info.put("userCorrect", report.getUserCorrect());
        Integer totalNumber = 0;
        Integer totalCorrect = 0;
        Integer totalTime = 0;
        for (QuestionNoRelation questionNoRelation : relationMap.values()){
            totalNumber += questionNoRelation.getTotalNumber();
            totalCorrect += questionNoRelation.getTotalCorrect();
            totalTime += questionNoRelation.getTotalTime();
        }
        Integer correctTime = 0;
        Integer incorrectTime = 0;
        for (UserQuestion userQuestion : questionList){
            if (userQuestion.getIsCorrect() > 0){
                correctTime += userQuestion.getUserTime();
            }else{
                incorrectTime += userQuestion.getUserTime();
            }
        }

        info.put("totalNumber", totalNumber);
        info.put("totalCorrect", totalCorrect);
        info.put("totalTime", totalTime);
        info.put("correctTime", correctTime);
        info.put("incorrectTime", incorrectTime);
        detail.put("info", info);
        return detail;
    }

    /**
     * 根据长难句报告格式，统计信息
     * @param report
     * @param questionList
     * @return
     */
    private JSONObject statSentenceReport(UserReport report, List<UserQuestion> questionList){
        UserPaper paper = userPaperService.get(report.getPaperId());
        Collection questionNoIds = Transform.getIds(questionList, UserQuestion.class, "questionNoId");
        Map<Number, SentenceQuestionRelation> relationMap = sentenceQuestionService.mapWithRelationByIds((Integer[])questionNoIds.toArray());

        // report
        JSONObject detail = new JSONObject();
        JSONObject ability = new JSONObject();
        Integer struct = 0;
        Integer logic = 0;
        Integer speed = 0;
        for (UserQuestion userQuestion:questionList){
            SentenceQuestionRelation relation = relationMap.get(userQuestion.getQuestionNoId());
            if (userQuestion.getIsCorrect() > 0){
                struct += 1;
            }
            if (userQuestion.getUserTime() < userQuestion.getTime()){
                speed += 1;
            }
            JSONObject questionDetail = userQuestion.getDetail();
            if (questionDetail.getBoolean("options")){
                logic += 1;
            }
        }
        ability.put("struct", struct * 100 / report.getQuestionNumber());
        ability.put("logic", logic * 100 / report.getQuestionNumber());
        ability.put("speed", speed * 100 / report.getQuestionNumber());
        ability.put("score", (struct * 40 + logic * 30 + speed * 30) / report.getQuestionNumber());
        detail.put("ability", ability);

        JSONObject info = new JSONObject();
        // 基本信息
        info.put("times", paper.getTimes() + 1); // paper还未计数
        info.put("finishTime", report.getFinishTime());
        info.put("userTime", report.getUserTime());
        info.put("time", report.getTime());
        info.put("questionNumber", report.getQuestionNumber());
        info.put("userNumber", report.getUserNumber());
        info.put("userCorrect", report.getUserCorrect());
        Integer totalNumber = 0;
        Integer totalCorrect = 0;
        Integer totalTime = 0;
        for (SentenceQuestionRelation questionNoRelation : relationMap.values()){
            totalNumber += questionNoRelation.getTotalNumber();
            totalCorrect += questionNoRelation.getTotalCorrect();
            totalTime += questionNoRelation.getTotalTime();
        }
        Integer correctTime = 0;
        Integer incorrectTime = 0;
        for (UserQuestion userQuestion : questionList){
            if (userQuestion.getIsCorrect() > 0){
                correctTime += userQuestion.getUserTime();
            }else{
                incorrectTime += userQuestion.getUserTime();
            }
        }

        info.put("totalNumber", totalNumber);
        info.put("totalCorrect", totalCorrect);
        info.put("totalTime", totalTime);
        info.put("correctTime", correctTime);
        info.put("incorrectTime", incorrectTime);
        detail.put("info", info);
        return detail;
    }
}
