package com.xhkjedu.sexam.utils;

import com.xhkjedu.sexam.model.reportstu.ERstudent;
import com.xhkjedu.utils.N_Utils;
import com.xhkjedu.vo.PageResult;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @ClassName StudyUtil
 * Description study模块用到的工具类
 * Author WN
 * Date 2022/2/21 10:01
 **/
@Slf4j
public class ExamUtil {
    // 默认除法运算精度
    private static final int DEF_DIV_SCALE = 2;
    public static Map<String, String> uriMap = new ConcurrentHashMap<>();

    /**
     * 提供（相对）精确的除法运算，当发生除不尽的情况时，精确到 小数点以后2位，以后的数字舍弃。
     *
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */
    public static double div(double v1, double v2) {
        return div(v1, v2, DEF_DIV_SCALE);
    }

    /**
     * 提供（相对）精确的除法运算。当发生除不尽的情况时，由scale参数指 定精度，以后的数字舍弃。
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 表示表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */
    public static double div(double v1, double v2, int scale) {
        try {
            if (scale < 0) {
                throw new IllegalArgumentException("The   scale   must   be   a   positive   integer   or   zero");
            }
            BigDecimal b1 = new BigDecimal(Double.toString(v1));
            BigDecimal b2 = new BigDecimal(Double.toString(v2));
            return b1.divide(b2, scale, BigDecimal.ROUND_DOWN).doubleValue();
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 两数相除向上取整
     *
     * @return java.lang.Integer
     * @Param [v1, v2]
     * @Author ywx
     * @Date 2022/8/23 13:43
     **/
    public static Integer divUp(double v1, double v2) {
        try {
            BigDecimal b1 = new BigDecimal(Double.toString(v1));
            BigDecimal b2 = new BigDecimal(Double.toString(v2));
            return b1.divide(b2, 0, BigDecimal.ROUND_UP).intValue();
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 提供精确的加法运算。
     *
     * @param v1 被加数
     * @param v2 加数
     * @return 两个参数的和
     */
    public static double add(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2).doubleValue();
    }

    /**
     * 提供精确的小数位四舍五入处理。
     *
     * @param v     需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static double round(double v, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The   scale   must   be   a   positive   integer   or   zero");
        }
        BigDecimal b = new BigDecimal(Double.toString(v));
        BigDecimal one = new BigDecimal("1");
        return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 提供精确的减法运算。
     *
     * @param v1 被减数
     * @param v2 减数
     * @return 两个参数的差
     */
    public static double sub(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2).doubleValue();
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     */
    public static double mul(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.multiply(b2).doubleValue();
    }

    //字符串转为时间戳(秒)
    public static long strToTimestamp(String str) {
        if (str == null || str == "") return 0;
        DateTimeFormatter ftf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime parse = LocalDateTime.parse(str, ftf);
        return LocalDateTime.from(parse).atZone(ZoneId.systemDefault()).toEpochSecond();
    }

    //两数相减
    public static long subtract(long a, long b) {
        BigInteger biginta = new BigInteger(a + "");
        BigInteger bigintb = new BigInteger(b + "");
        return biginta.subtract(bigintb).longValue();

    }

    //两数相减
    public static Integer subtractInt(Integer a, Integer b) {
        BigInteger biginta = new BigInteger(a + "");
        BigInteger bigintb = new BigInteger(b + "");
        return biginta.subtract(bigintb).intValue();

    }

    /**
     * 分数百分比
     *
     * @param v1 分数
     * @param v2 占比如80%写作0.8
     * @return
     */
    public static double getScoreRateScore(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));

        return b1.multiply(b2).setScale(0, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    //方差s^2=[(x1-x)^2 +...(xn-x)^2]/n 或者s^2=[(x1-x)^2 +...(xn-x)^2]/(n-1)
    public static double variance(List<Double> x) {
        if (N_Utils.isListEmpty(x)) return 0;
        int m = x.size();
        double sum = 0;
        for (int i = 0; i < m; i++) {//求和
            sum += x.get(i);
        }
        double dAve = sum / m;//求平均值
        double dVar = 0;
        for (int i = 0; i < m; i++) {//求方差
            dVar += (x.get(i) - dAve) * (x.get(i) - dAve);
        }
        return dVar / m;
    }

    //标准差σ=sqrt(s^2)
    public static double standardDiviation(List<Double> x) {
        if (N_Utils.isListEmpty(x)) return 0;
        return N_Utils.formatDouble(Math.sqrt(variance(x)), 2);
    }

    //标准分=（学生得分-年级平均分）/标准差
    public static double standardScore(Double score, Double avgscore, Double bzc) {
        double bzscore = div(sub(score, avgscore), bzc);
        return N_Utils.formatDouble(bzscore, 2);
    }

    /**
     * 根据本次排名和参数计算下次的目标
     *
     * @param countschool:本次排名
     * @param goalparam：进步目标参数
     * @return
     */
    public static Integer getUserGroupGoalByParam(Integer countschool, String goalparam) {
        if (countschool != null && (1 == countschool || 2 == countschool)) {//若本次是第一名或者第二名，则下次目标一定是第一名
            return 1;
        } else {
            BigDecimal count = countschool == null || N_Utils.isEmpty(goalparam) ? new BigDecimal(0) :
                    new BigDecimal(goalparam).multiply(new BigDecimal(countschool.toString()));//进步的名次
            Integer thiscount = countschool == null ? 0 : new BigDecimal(countschool.toString()).subtract(count).intValue();
            //舍弃小数点
            return thiscount;
        }
    }

    /**
     * double转String去掉结尾的.0
     *
     * @return java.lang.String
     * @Param [score]
     * @Author ywx
     * @Date 2022/9/27 9:50
     **/
    public static String doubleToStr(double score) {
        DecimalFormat df = new DecimalFormat("###################.###########");
        return df.format(score);
    }

    /**
     * 成绩单排序
     *
     * @return com.xhkjedu.vo.PageResult
     * @Param [stu, list]
     * @Author ywx
     * @Date 2022/9/29 16:59
     **/
    public static PageResult getCjdPageResult(ERstudent stu, List<Map> list) {
        Integer page = stu.getPage();
        Integer pageSize = stu.getPageSize();
        Integer start = (page - 1) * pageSize;
        PageResult pageResult = new PageResult();
        pageResult.setTotal(list.size());
        String subjectid = stu.getSubjectid();
        String fieldname = stu.getFieldname();
        Integer od = stu.getOd();
        //默认按全科的总分排序
        if (N_Utils.isEmpty(subjectid)) subjectid = "zf";
        if (N_Utils.isEmpty(fieldname)) fieldname = "score";
        if (N_Utils.isEmptyInteger(od)) od = 2;
        List<ERstudent> students = new ArrayList<>();
        for (Map s : list) {
            Integer studentid = (Integer) s.get("studentid");
            List<Map> subjects = (List<Map>) s.get("subjects");
            String finalSubjectid = subjectid;
            Map smap = subjects.stream().filter(s2 -> s2.get("subjectid").toString().equals(finalSubjectid))
                               .findFirst().orElse(null);
            Integer classrank = list.size();
            Integer schoolrank = list.size();
            Double score = 0.0;
            if (smap == null) {
                smap = new HashMap();
            } else {
                classrank = (Integer) smap.get("classrank");
                schoolrank = (Integer) smap.get("schoolrank");
                score = (Double) smap.get("score");
            }
            smap.put("studentid", studentid);
            ERstudent rstudent = new ERstudent();
            rstudent.setStudentid(studentid);
            rstudent.setClassrank(classrank);
            rstudent.setSchoolrank(schoolrank);
            rstudent.setScore(score);
            students.add(rstudent);
        }
        if ("classrank".equals(fieldname) && 1 == od) {
            students = students.stream().sorted(Comparator.comparing(ERstudent::getClassrank)).collect(Collectors.toList());
        } else if ("classrank".equals(fieldname) && 2 == od) {
            students = students.stream().sorted(Comparator.comparing(ERstudent::getClassrank).reversed())
                               .collect(Collectors.toList());
        } else if ("schoolrank".equals(fieldname) && 1 == od) {
            students = students.stream().sorted(Comparator.comparing(ERstudent::getSchoolrank)).collect(Collectors.toList());
        } else if ("schoolrank".equals(fieldname) && 2 == od) {
            students = students.stream().sorted(Comparator.comparing(ERstudent::getSchoolrank).reversed())
                               .collect(Collectors.toList());
        } else if ("score".equals(fieldname) && 1 == od) {
            students = students.stream().sorted(Comparator.comparing(ERstudent::getScore)).collect(Collectors.toList());
        } else {
            students = students.stream().sorted(Comparator.comparing(ERstudent::getScore).reversed())
                               .collect(Collectors.toList());
        }
        List<ERstudent> studentList = students.stream().skip(start).limit(pageSize).collect(Collectors.toList());
        List<Map> rstudentList = new ArrayList<>();
        Integer showrank = stu.getShowrank();
        for (ERstudent map : studentList) {
            Integer studentid = map.getStudentid();
            Map rs = list.stream().filter(s2 -> s2.get("studentid").equals(studentid)).findFirst().orElse(null);
            if (showrank != 3) {
                List<Map> subjects = (List<Map>) rs.get("subjects");
                for (Map s : subjects) {
                    if (showrank == 2) {
                        s.put("schoolrank", "0");
                        s.put("goal", "0");
                        s.put("nextgoal", "0");
                    } else if (showrank == 1){
                        s.put("classrank", "0");
                        s.put("classrankpre", "0");
                        s.put("schoolrank", "0");
                        s.put("goal", "0");
                        s.put("nextgoal", "0");
                    } else {
                        s.put("bzscore", "0");
                        s.put("score", "0");
                        s.put("classrank", "0");
                        s.put("classrankpre", "0");
                        s.put("schoolrank", "0");
                        s.put("goal", "0");
                        s.put("nextgoal", "0");
                    }
                }
            }
            rstudentList.add(rs);
        }
        pageResult.setList(rstudentList);
        return pageResult;
    }

    /*
     * 成绩单校排名排序
     * @Param [list]
     * @Author ywx
     * @Date 2022/10/23 11:49
     * @return java.util.List<java.util.Map>
     **/
    public static List<Map> listCjdOrder(List<Map> list, Integer showrank) {
        List<ERstudent> students = new ArrayList<>();
        for (Map s : list) {
            Integer studentid = (Integer) s.get("studentid");
            List<Map> subjects = (List<Map>) s.get("subjects");
            String finalSubjectid = "zf";
            Map smap = subjects.stream().filter(s2 -> s2.get("subjectid").toString().equals(finalSubjectid))
                    .findFirst().orElse(null);
            smap.put("studentid", studentid);
            ERstudent rstudent = new ERstudent();
            rstudent.setStudentid(studentid);
            rstudent.setSchoolrank((Integer) smap.get("schoolrank"));
            students.add(rstudent);
        }
        students = students.stream().sorted(Comparator.comparing(ERstudent::getSchoolrank)).collect(Collectors.toList());

        List<Map> rstudentList = new ArrayList<>();
        for (ERstudent map : students) {
            Integer studentid = map.getStudentid();
            Map rs = list.stream().filter(s2 -> s2.get("studentid").equals(studentid)).findFirst().orElse(null);
            if (showrank != 3) {
                List<Map> subjects = (List<Map>) rs.get("subjects");
                for (Map s : subjects) {
                    if (showrank == 2) {
                        s.put("schoolrank", "0");
                        s.put("goal", "0");
                        s.put("nextgoal", "0");
                    } else {
                        s.put("classrank", "0");
                        s.put("classrankpre", "0");
                        s.put("schoolrank", "0");
                        s.put("goal", "0");
                        s.put("nextgoal", "0");
                    }
                }
            }
            rstudentList.add(rs);
        }
        return rstudentList;
    }

    /**
     * @Description 得分率分组：1优秀率≥85%2良好率≥70%3合格率≥60%5低分率≥40%
     * @Param [scorerate]
     * @Return java.lang.Integer
     * @Author wn
     * @Date 2022/10/8 9:33
     **/
    public static Integer getScoreRateType(Double scorerate) {
        Integer ratetype = 0;
        if (scorerate != null) {
            if (scorerate >= 85) {
                ratetype = 1;
            } else if (scorerate >= 70) {
                ratetype = 2;
            } else if (scorerate >= 60) {
                ratetype = 3;
            }else if(scorerate < 60 && scorerate > 40){
                ratetype = 4;
            } else if (scorerate <= 40) {
                ratetype = 5;
            }
        }
        return ratetype;
    }

    /**
     * @Description 字符串转时间戳
     * @Param [time]
     * @Return int
     * @Author wn
     * @Date 2022/10/27 11:36
     **/
    public static long getTimestrToTimetamp(String time){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date();
        try {
            date = sdf.parse(time);
        }catch (Exception e){
            log.error("字符串转时间戳出错：" + e.getMessage());
        }
        return date.getTime()/1000;
    }

    /*
     * 去除字符串末尾的.0
     * @Param [obj]
     * @Author ywx
     * @Date 2022/11/7 10:46
     * @return java.lang.String
     **/
    public static String removeStrEnd0(Object obj){
        if (N_Utils.isEmpty(obj)) return "0";
        String str = obj.toString();
        if(str.endsWith(".0")){
            str=str.substring(0,str.lastIndexOf("."));
        }
        return str;
    }

    /**
     * 删除Html标签
     *
     * @param inputString
     * @return
     */
    public static String htmlRemoveTag(String inputString) {
        if (inputString == null)
            return null;
        String htmlStr = inputString; // 含html标签的字符串
        String textStr = "";
        java.util.regex.Pattern p_script;
        java.util.regex.Matcher m_script;
        java.util.regex.Pattern p_style;
        java.util.regex.Matcher m_style;
        java.util.regex.Pattern p_html;
        java.util.regex.Matcher m_html;
        try {
            //定义script的正则表达式{或<script[^>]*?>[\\s\\S]*?<\\/script>
            String regEx_script = "<[\\s]*?script[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?script[\\s]*?>";
            //定义style的正则表达式{或<style[^>]*?>[\\s\\S]*?<\\/style>
            String regEx_style = "<[\\s]*?style[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?style[\\s]*?>";
            String regEx_html = "<[^>]+>"; // 定义HTML标签的正则表达式
            p_script = Pattern.compile(regEx_script, Pattern.CASE_INSENSITIVE);
            m_script = p_script.matcher(htmlStr);
            htmlStr = m_script.replaceAll(""); // 过滤script标签
            p_style = Pattern.compile(regEx_style, Pattern.CASE_INSENSITIVE);
            m_style = p_style.matcher(htmlStr);
            htmlStr = m_style.replaceAll(""); // 过滤style标签
            p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE);
            m_html = p_html.matcher(htmlStr);
            htmlStr = m_html.replaceAll(""); // 过滤html标签
            textStr = htmlStr;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return textStr;// 返回文本字符串
    }

    //线程是否执行完
    public static void isAllDone(List<Future> futureList) {
        while (true) {
            if (N_Utils.isListNotEmpty(futureList)) {
                boolean isAllDone = true;
                for (Future future : futureList) {
                    if (null == future || !future.isDone()) {
                        isAllDone = false;
                    }
                }
                if (isAllDone) {
                    break;
                }
            }
        }
    }

    public static void main(String[] args) {

    }
}
