package com.qxgmat.service.extend;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.qxgmat.data.constants.enums.QuestionSubject;
import com.qxgmat.data.constants.enums.SettingKey;
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;

    @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){
        // todo 按人工还是手动
        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){
        // todo 按人工还是手动
        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;
    }

    /**
     * 根据考试设置，得到做题时间，做题数量
     *      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);
    }

    /**
     * 获取模考学科数据：
     *      { 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;
    }

    /**
     * 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;
    }

    /**
     * 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=[（550*0.3+550*0.5+550*0.4）+（650*0.6+650*0.8）+（750*0.9）]➗（3+2+1）
     * @param totalNumber
     * @param totalCorrect
     * @param difficultScore
     * @return
     */
    public float diffScore(Integer totalNumber, Integer totalCorrect, Integer difficultScore){
        Setting setting = settingService.getByKey(SettingKey.EXAMINATION_SCORE);
        JSONObject value = setting.getValue();
        if (value.getBooleanValue("difficult")){
            return difficultScore * (1- (float)totalCorrect / totalNumber);
        }else{
            return difficultScore;
        }
    }

    /**
     * 当这个结果低于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.floor((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();
    }
}
