package com.qxgmat.service.extend;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.qxgmat.data.constants.enums.QuestionDifficult;
import com.qxgmat.data.constants.enums.QuestionSubject;
import com.qxgmat.data.constants.enums.SettingKey;
import com.qxgmat.data.constants.enums.user.MessageType;
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.TextbookQuestionRelation;
import com.qxgmat.service.inline.RankService;
import com.qxgmat.service.inline.SettingService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

@Service
public class ToolsService {

    @Value("${examination.verbalA}")
    private Integer verbalA;

    @Value("${examination.verbalB}")
    private Integer verbalB;

    @Value("${examination.quantC}")
    private Integer quantC;

    @Value("${examination.quantD}")
    private Integer quantD;

    private Integer scoreMax = 51;

    private Integer scoreMin = 6;

    @Resource
    private SettingService settingService;

    @Resource
    private RankService rankService;

    /**
     * 根据练习时间设置计算考题考试时间
     *      setting: {struct: {difficult: ""}}
     * @param relationList
     * @return
     */
    public Integer computerTime(QuestionNoRelation[] relationList){
        Setting setting = settingService.getByKey(SettingKey.EXERCISE_TIME);
        JSONObject value = setting.getValue();

        Integer time = 0;
        for(QuestionNoRelation relation:relationList){
            JSONObject difficultMap = null;
            for (Integer struct : relation.getModuleStruct()){
                // 判断结构体
                difficultMap = value.getJSONObject(String.valueOf(struct));
                if (difficultMap != null) break;
            }
            if (difficultMap == null) continue;
            // 判断难度
            String t = difficultMap.getString(relation.getQuestion().getDifficult());
            if (t == null || t.isEmpty()) continue;
            time += Integer.valueOf(t);
        }
        return time;
    }

    /**
     * 根据练习时间设置获取单个考题时间
     *      setting: {struct: {difficult: ""}}
     * @param relation
     * @return
     */
    public Integer computerTime(QuestionNoRelation relation){
        Setting setting = settingService.getByKey(SettingKey.EXERCISE_TIME);
        JSONObject value = setting.getValue();

        JSONObject difficultMap = null;
        for (Integer struct : relation.getModuleStruct()){
            // 判断结构体
            difficultMap = value.getJSONObject(String.valueOf(struct));
            if (difficultMap != null) break;
        }
        if (difficultMap == null) return 0;
        // 判断难度
        String t = difficultMap.getString(relation.getQuestion().getDifficult());
        if (t == null || t.isEmpty()) return 0;
        return Integer.valueOf(t);
    }

    /**
     * 根据练习时间设置获取单个考题时间
     *      setting: {struct: {difficult: ""}}
     * @param relation
     * @return
     */
    public Integer computerTime(TextbookQuestionRelation relation){
        Setting setting = settingService.getByKey(SettingKey.TEXTBOOK_TIME);
        JSONObject value = setting.getValue();

        String t = value.getString("time");
        if (t == null || t.isEmpty()) return 0;
        return Integer.valueOf(t);
    }

    /**
     * 根据练习时间设置计算考题考试时间
     *      setting: {struct: {difficult: ""}}
     * @param relationList
     * @return
     */
    public Integer computerTime(TextbookQuestionRelation[] relationList){
        Setting setting = settingService.getByKey(SettingKey.TEXTBOOK_TIME);
        JSONObject value = setting.getValue();

        String t = value.getString("time");
        if (t == null || t.isEmpty()) return 0;
        return Integer.valueOf(t) * relationList.length;
    }

    /**
     * 根据长难句时间设置获取单个考题时间
     *      setting: {time: ""}
     * @param relation
     * @return
     */
    public Integer computerTime(SentenceQuestionRelation relation){
        Setting scoreSwitch = settingService.getByKey(SettingKey.SCORE_SWITCH);
        if (scoreSwitch.getValue().getBooleanValue("all")){
            // todo 计算全站平均时间
            return 0;
        } else {
            Setting setting = settingService.getByKey(SettingKey.SENTENCE_TIME);
            JSONObject value = setting.getValue();

            String t = value.getString("time");
            if (t == null || t.isEmpty()) return 0;
            return Integer.valueOf(t);
        }
    }

    /**
     * 根据长难句时间设置获取考题考试时间
     *      setting: {time: ""}
     * @param relationList
     * @return
     */
    public Integer computerTime(SentenceQuestionRelation[] relationList){
        Setting scoreSwitch = settingService.getByKey(SettingKey.SCORE_SWITCH);
        if (scoreSwitch.getValue().getBooleanValue("all")){
            // todo 计算全站平均时间
            return 0;
        } else {
            Setting setting = settingService.getByKey(SettingKey.SENTENCE_TIME);
            JSONObject value = setting.getValue();

            String t = value.getString("time");
            if (t == null || t.isEmpty()) return 0;
            return Integer.valueOf(t) * relationList.length;
        }
    }

    /**
     * 根据后台设置剔除时间,判断试题统计情况
     * @param question
     * @return
     */
    public boolean filterTime(UserQuestion question){
        Setting setting = settingService.getByKey(SettingKey.FILTER_TIME);
        JSONObject value = setting.getValue();
        if (value.getInteger("min")> question.getTime()) return false;
        if (value.getInteger("max") < question.getTime()) return false;
        return  true;
    }

    /**
     * 获取消息模版
     * @param messageType
     * @return
     */
    public JSONObject messageTemplate(MessageType messageType){
        Setting setting = settingService.getByKey(SettingKey.MESSAGE_TEMPLATE);
        JSONObject value = setting.getValue();
        return value.getJSONObject(messageType.type);
    }

    /**
     * 根据考试设置,得到做题时间,做题数量
     *      setting: {subject: { time: "", number: "" }}
     * @param order
     */
    public void examinationReportInit(UserReport userReport, JSONArray order){
        Setting setting = settingService.getByKey(SettingKey.EXAMINATION_TIME);
        JSONObject value = setting.getValue();
        Integer number = 0;
        Integer time = 0;
        for(String subject : order.toJavaList(String.class)){
            JSONObject one = value.getJSONObject(subject);
            if(one!= null && !one.isEmpty()){
                number += one.getInteger("number");
                time += one.getInteger("time");
            }
        }
        userReport.setQuestionNumber(number);
        userReport.setTime(time);
    }

    /**
     * 得到单个科目做题总时间
     * @param subject
     * @return
     */
    public Integer examinationSubjectTime(String subject){
        Setting setting = settingService.getByKey(SettingKey.EXAMINATION_TIME);
        JSONObject value = setting.getValue();
        JSONObject info = value.getJSONObject(subject);
        return info.getInteger("time");
    }

    /**
     * 得到单个科目做题总题数
     * @param subject
     * @return
     */
    public Integer examinationSubjectNumber(String subject){
        Setting setting = settingService.getByKey(SettingKey.EXAMINATION_TIME);
        JSONObject value = setting.getValue();
        JSONObject info = value.getJSONObject(subject);
        return info.getInteger("number");
    }

    /**
     * 获取模考学科数据:
     *      { time: '', number: '' }
     * @param subject
     * @return
     */
    public JSONObject examinationSubjectInit(QuestionSubject subject){
        Setting setting = settingService.getByKey(SettingKey.EXAMINATION_TIME);
        JSONObject value = setting.getValue();
        return value.getJSONObject(subject.key);
    }

    /**
     * Quant分数计算:系数c * Quant部分平均正确率 + 系数d * Quant部分题目平均难度
     * @param number
     * @param userNumber
     * @param difficultScore
     * @param correctNumber
     * @return
     */
//    public Integer quantScore(Integer number, Integer userNumber, Integer difficultScore, Integer correctNumber){
//        return quantC * correctNumber / number + quantD * difficultScore / userNumber;
//    }
    /**
     * Quant分数计算:17+平均正确率*19.45+平均难度*0.72
     * @param number
     * @param userNumber
     * @param difficultScore
     * @param correctNumber
     * @return
     */
    public Integer quantScore(Integer number, Integer userNumber, float difficultScore, Integer correctNumber){
        int score = (int)Math.round(17 + 19.45 * correctNumber / number + 0.72 * difficultScore / userNumber);
        if (score > scoreMax) return scoreMax;
        if (score < scoreMin) return scoreMin;
        return score;
    }

    /**
     * Verbal分数计算:系数a * Verbal部分题目平均正确率 + 系数b * Verbal部分题目平均难度
     * @param number
     * @param userNumber
     * @param difficultScore
     * @param correctNumber
     * @return
     */
//    public Integer verbalScore(Integer number, Integer userNumber, Integer difficultScore, Integer correctNumber){
//        return verbalA * correctNumber / number + verbalB * difficultScore / userNumber;
//    }
    /**
     * Verbal分数计算:23.59 + 平均正确率*29.6+平均难度*1.72
     * @param number
     * @param userNumber
     * @param difficultScore
     * @param correctNumber
     * @return
     */
    public Integer verbalScore(Integer number, Integer userNumber, float difficultScore, Integer correctNumber){
        int score = (int)Math.round(23.59 + 29.6 * correctNumber / number + 1.72 * difficultScore / userNumber);
        if (score > scoreMax) return scoreMax;
        if (score < scoreMin) return scoreMin;
        return score;
    }

    /**
     * IR分数计算:最高8分
     * @param number
     * @param userNumber
     * @param difficultScore
     * @param correctNumber
     * @return
     */
    public int irScore(Integer number, Integer userNumber, Integer difficultScore, Integer correctNumber){
        switch(correctNumber){
            case 0:
            case 1:
                return 1;
            case 2:
                return 2;
            case 3:
            case 4:
                return 3;
            case 5:
                return 4;
            case 6:
                return 5;
            case 7:
                return 6;
            case 8:
                return 7;
            case 9:
            default:
                return 8;
        }
    }

    /**
     * avg diff correct= [500 + 10*(1-0.7)+500+10*(1-0.6)+500+10*(1-0.5)
     * +600+10*(1-0.4)+600+10*(1-0.7)+700+10*(1-0.1)+700+10*(1-0.9)] / (3+2+2)
     *      { all: '' }
     * @param totalNumber
     * @param totalCorrect
     * @param questionDifficult
     * @return
     */
    public float diffScore(Integer totalNumber, Integer totalCorrect, QuestionDifficult questionDifficult){
        Setting setting = settingService.getByKey(SettingKey.SCORE_SWITCH);
        JSONObject value = setting.getValue();
        if (value.getBooleanValue("all")){
            Integer difficultScore = QuestionDifficult.GetScore(questionDifficult);
            return difficultScore + 10 * (1 - (float)totalCorrect / totalNumber);
        }else{
            return QuestionDifficult.GetScoreBase(questionDifficult);
        }
    }

    /**
     * 当这个结果低于500的时候统一显示为500,
     * 高于500时,是多少就显示多少,且必须为10的倍数,722=720,754=750,756=760
     * 四舍五入
     * @param totalDiffScore
     * @param number
     * @return
     */
    public int avgDiffScore(float totalDiffScore, Integer number){
        int avg = (int)(totalDiffScore / number);
        if (avg < 500){
            return 500;
        }
        return (int) (Math.round((int)(avg / 10)) * 10);
    }

    /**
     * 得出V小分和Q小分后根据总分-小分excel对应表(我方提供)算出最后考试的总分
     * @param quantScore
     * @param verbalScore
     * @return
     */
    public Rank totalScore(Integer quantScore, Integer verbalScore){
        Rank rank = rankService.search(quantScore, verbalScore);
        return rank != null ? rank : new Rank();
    }

    /**
     * 根据模考分数获取排名
     * @param score
     * @return
     */
    public Rank scoreRank(JSONObject score){
        Rank rank = rankService.search(score.getInteger("quant"), score.getInteger("verbal"));
        return rank != null ? rank : new Rank();
    }
}