package cn.cecep.talroad.util.effective;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;

import static cn.cecep.talroad.util.effective.DateUtil.*;


/**
 * @author zhangshiji
 * @date 2022/9/15
 */
public class BasTargetUtil {
    //1
    public static final BigDecimal ONE = new BigDecimal(1);
    //半年月长度
    public static final BigDecimal HALF_YEAR = new BigDecimal(6);

    //年 月份数量
    public static final BigDecimal MONTH_LENGTH = new BigDecimal(12);
    //年 月份数量
    public static final int INT_MONTH_LENGTH = 12;
    //95百分位
    public static final BigDecimal PERCENT_95 = new BigDecimal(0.95);
    //o3年超标天数标准值
    public static final BigDecimal O38HSTAND = new BigDecimal(36);

    public static final String PM10 = "pm10";
    public static final String PM25 = "pm25";
    public static final String SO2 = "so2";
    public static final String NO2 = "no2";
    public static final String CO = "co";
    public static final String O3 = "o3";
    public static final String O38H = "o38h";
    public static final String GOODDYAS = "goodDays";
    public static final String HEAVYDAYS = "heavyDays";
    public static final String COOVERDAYS = "coOverDays";
    public static final String O38HOVERDAYS = "o38hOverDays";


    //年目标
    public static final int YEAR_TARGET = 3;
    //月目标
    public static final int MONTH_TARGET = 2;
    //日目标
    public static final int DAT_TARGET = 1;
    //秋防目标
    public static final int AUTUMN_TARGET = 4;
    //冬防目标
    public static final int WINTER_TARGET = 5;
    //秋冬防总计目标
    public static final int SUM_TARGET = 6;
    //不是闰年每月的天数
    public static final int[] NORMAL_MONTH = {31,29,31,30,31,30,31,31,30,31,30,31};
    //是闰年每月的天数
    public static final int[] LEAPYEAR_MONTH = {31,28,31,30,31,30,31,31,30,31,30,31};

    /**
     * 计算月度同比值
     *
     * @param thisYear 当前年数据
     * @param lastYear 环比年数据
     * @return 返回值带两位小数
     */
    public static BigDecimal monthTongBiPercent(BigDecimal thisYear, BigDecimal lastYear) {
        if (thisYear == null || lastYear == null) {
            return BigDecimal.ZERO;
        }
        if (thisYear != null && lastYear == null) {
            return BigDecimal.ZERO;
        }
        if (lastYear.compareTo(BigDecimal.ZERO)==0){
            return null;
        }
        BigDecimal result = (thisYear.subtract(lastYear)).divide(lastYear, 3, BigDecimal.ROUND_HALF_EVEN);
        return result;
    }


    /**
     * 最大限制等于（年度目标值乘以全年天数-当前累计值乘以过去天数）除以剩余天数
     *
     * @param targetValue 目标值
     * @param actualValue 累计值
     * @param type        1 本年 2本月 3明年秋冬防3个月 1-3月
     * @param type        1 本年 2本月 3冬防3个月 1-3月 4秋防 5总防
     * @return
     */
    public static BigDecimal thresholdToData(BigDecimal targetValue, BigDecimal actualValue, String type) {
        if (Objects.isNull(targetValue) || Objects.isNull(actualValue)) {
            return null;
        }
        Map timeType = getTimeType(type);
        BigDecimal quantity = targetValue.multiply(new BigDecimal(timeType.get("yearDay").toString()));
        BigDecimal grand = actualValue.multiply(new BigDecimal(timeType.get("formerlyDay").toString()));
        //进位取整
        if (Objects.isNull(timeType.get("residueDay"))||timeType.get("residueDay").toString().equals("0")){
            return null;
        }
        BigDecimal result = (quantity.subtract(grand)).divide(new BigDecimal(timeType.get("residueDay").toString()), 2, BigDecimal.ROUND_HALF_EVEN).setScale(0, BigDecimal.ROUND_HALF_EVEN);
        return result;
    }


    /**
     * 封装时间重复调用
     *
     * @param type
     * @return 1 本年 2本月 3冬防3个月 1-3月 4秋防10-12  5总防
     */
    private static Map getTimeType(String type) {
        Map<String, Object> map = new HashMap<>();
        int yearDay = 0; //全年天数
        int formerlyDay = 0; //过去天数 排除当天
        int residueDay = 0;  //剩余天数
        Date nowData = new Date();
        if ("1".equals(type)) {
            //本年天数
            yearDay = getDaysOfYear(nowData);
            int year = getYear(nowData);
            String firstDay = year + "-01-01";
            //过去了多少天 不能计算为当天时间
            formerlyDay = getDayDifferDay(stringToDate(firstDay, DATE_PATTERN), nowData) - 1;
            residueDay = yearDay - formerlyDay;
        } else if ("2".equals(type)) {
            yearDay = getDaysOfMonth(nowData);
            String firstDay = getFirstDay(false);
            //过去了多少天 不能计算为当天时间
            formerlyDay = getDayDifferDay(stringToDate(firstDay, DATE_PATTERN), nowData) - 1;
            residueDay = yearDay - formerlyDay;
        } else if ("3".equals(type)) {
            //三月份有31天
            int year = getYear(nowData) + 1;
            String firstDay = year + "-01-01";
            String endDay = year + "-03-31";
            yearDay = getDayDifferDay(stringToDate(firstDay, DATE_PATTERN), stringToDate(endDay, DATE_PATTERN));
            //过去了多少天 不能计算为当天时间
            formerlyDay = getDayDifferDay(stringToDate(firstDay, DATE_PATTERN), nowData) - 1 > 0 ? getDayDifferDay(stringToDate(firstDay, DATE_PATTERN), nowData) - 1 : 0;
            residueDay = yearDay - formerlyDay;
        } else if ("4".equals(type)) {
            //秋防10-12
            int year = getYear(nowData) + 1;
            String firstDay = year + "-10-01";
            String endDay = year + "-12-31";
            yearDay = getDayDifferDay(stringToDate(firstDay, DATE_PATTERN), stringToDate(endDay, DATE_PATTERN));
            //过去了多少天 不能计算为当天时间
            formerlyDay = getDayDifferDay(stringToDate(firstDay, DATE_PATTERN), nowData) - 1 > 0 ? getDayDifferDay(stringToDate(firstDay, DATE_PATTERN), nowData) - 1 : 0;
            residueDay = yearDay - formerlyDay;
        } else if ("5".equals(type)) {
            //总防6月
            int year = getYear(nowData) + 1;
            String firstDay = year + "-10-01";
            String endDay = (year + 1) + "-03-31";
            yearDay = getDayDifferDay(stringToDate(firstDay, DATE_PATTERN), stringToDate(endDay, DATE_PATTERN));
            //过去了多少天 不能计算为当天时间
            formerlyDay = getDayDifferDay(stringToDate(firstDay, DATE_PATTERN), nowData) - 1 > 0 ? getDayDifferDay(stringToDate(firstDay, DATE_PATTERN), nowData) - 1 : 0;
            residueDay = yearDay - formerlyDay;
        }

        map.put("yearDay", yearDay);
        map.put("formerlyDay", formerlyDay);
        map.put("residueDay", residueDay);
        return map;
    }


    /**
     *   达标监控-年目标中，CO超标天数：如果设定CO年度目标，那CO日均值超过目标值即为超标，如果没有设定目标值，CO日均值超过去年CO年均值即为超标。O3-8H超标天数：O3-8H日数据超过年度设定目标值即为超标。
     *   6CO剩余控制天数 = (总超标天)等于（全年-全年*0.95）  取整- 超标天数？  O3-8H剩余控制天数=36- 超标天数？
     *   O3的超标天数是固定的。  CO是计算的。
     * @param exceedDay  累计超标天数
     * @param divisor    因子
     * @param type      1 本年
     * @return
     */
    public static BigDecimal thresholdToExceed(BigDecimal exceedDay, String divisor, String type) {
        BigDecimal result=BigDecimal.ZERO;
        if (Objects.isNull(exceedDay)){
              switch (divisor) {
                  case CO:
                      BigDecimal decimal = new BigDecimal(getDaysOfYear(new Date()));
                      BigDecimal decimalCo = decimal.multiply(new BigDecimal(0.95)).setScale(0, BigDecimal.ROUND_HALF_EVEN);
                      result = decimal.subtract(decimalCo);
                      break;
                  case O3:
                      result = new BigDecimal(36);
                      break;
                  case O38H:
                      result = new BigDecimal(36);
                      break;
              }
        }else {
            switch (divisor) {
                case CO:
                    BigDecimal decimal = new BigDecimal(getDaysOfYear(new Date()));
                    BigDecimal exceed  = decimal.subtract(decimal.multiply(new BigDecimal(0.95)).setScale(0, BigDecimal.ROUND_HALF_EVEN));
                    result =exceed.subtract(exceedDay);
                    break;
                case O3:
                    result = new BigDecimal(36).subtract(exceedDay);
                    break;
                case O38H:
                    result = new BigDecimal(36).subtract(exceedDay);
                    break;
            }
        }
        return result;
    }




    /**
     * 捕获异常
     *
     * @param startDate
     * @param endDate
     * @return
     */
    private static int getDayDifferDay(Date startDate, Date endDate) {
        try {
            int dayDiffer = getDayDiffer(startDate, endDate);
            return dayDiffer;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return 0;
    }

//    public static BigDecimal getPercentile(BigDecimal[] A, BigDecimal p) {
//        if (A == null)
//            return null;
//        BigDecimal res = BigDecimal.ZERO;
//        Arrays.sort(A); // 从小到大排序
//        double x = (A.length - 1) * p;
//        int i = (int) x; // 取出整数部分
//        double j = x - i; // 还没找到最精确的取double数的小数部分的方法，有可能会有误差
//        res = (1 - j) * A[i] + j * A[i + 1];
//        return res;
//    }

    //百分位数
    private static double getPercentile(int[] array, double percentile) {
        Arrays.sort(array);
        double x = (array.length - 1) * percentile;
        int i = (int) x;
        double j = x - i;
        return (1 - j) * array[i] + j * array[i + 1];
    }
    //百分位数
    public static double percentile(double[] data,double p){
        int n = data.length;
        Arrays.sort(data);
        double px =  p*(n-1);
        int i = (int) Math.floor(px);
        double g = px - i;
        if(g==0){
            return data[i];
        }else{
            return (1-g)*data[i]+g*data[i+1];
        }
    }
    /***
     * 百分位数
     * @param data
     * @param p
     * @return
     */
    public static BigDecimal percentile(BigDecimal[] data, BigDecimal p){
        if (data.length == 0||data==null){
            return null;
        }
        double[] doubles = new double[data.length];
        for (int i = 0; i < data.length; i++) {
            doubles[i]=data[i].doubleValue();
        }
        double percentile = percentile(doubles, p.doubleValue());
        return  new BigDecimal(percentile);
    }

    /**
     * 去年同期：全年剩余天数的监测值总和除以剩余天数
     *
     * @param remainingSum 全年剩余天数的监测值总和
     * @param type         1 本年 2本月 3冬防3个月 1-3月 4秋防 5总防
     * @return
     */
    public static BigDecimal periodLastYear(BigDecimal remainingSum, String type) {
        if (Objects.isNull(remainingSum)) {
            return null;
        }
        Map timeType = getTimeType(type);
        //进位取整
        if (Objects.isNull(timeType.get("residueDay"))||timeType.get("residueDay").toString().equals("0")){
            return null;
        }
        BigDecimal result = remainingSum.divide(new BigDecimal(timeType.get("residueDay").toString()), 4, BigDecimal.ROUND_HALF_EVEN).setScale(0, BigDecimal.ROUND_HALF_EVEN);
        return result;
    }

//    /**
//     * 不用  同比变化率：（去年同期-最大限制）/去年同期 *100
//     * @param threshold 最大限制
//     * @param lastYear  去年同期
//     * @return
//     */
//    public static BigDecimal comparedChange(BigDecimal threshold, BigDecimal lastYear) {
//        if (Objects.isNull(lastYear) || Objects.isNull(threshold)) {
//            return null;
//        }
//        if (lastYear.compareTo(BigDecimal.ZERO)==0){
//            return BigDecimal.ZERO;
//        }
//        BigDecimal result = (lastYear.subtract(threshold)).divide(lastYear, 6, BigDecimal.ROUND_HALF_EVEN).multiply(new BigDecimal(100));
//        return result;
//    }

    /**
     *  同比变化率：（今年同期-去年同期）/去年同期 *100
     * @param threshold 今年同期
     * @param lastYear  去年同期
     * @return
     */
    public static BigDecimal comparedChange(BigDecimal threshold, BigDecimal lastYear) {
        if (Objects.isNull(lastYear) || Objects.isNull(threshold)) {
            return null;
        }
        if (lastYear.compareTo(BigDecimal.ZERO)==0){
            return BigDecimal.ZERO;
        }
        BigDecimal result = (threshold.subtract(lastYear)).divide(lastYear, 6, BigDecimal.ROUND_HALF_EVEN).multiply(new BigDecimal(100));
        return result;
    }


    /**
     * 同比改善率：今年-去年/去年  在乘以 -1*100 求百分比
     * @param threshold 今年
     * @param lastYear  去年
     * @return
     */
    public static BigDecimal comparedImprovement (BigDecimal threshold, BigDecimal lastYear) {
        if (Objects.isNull(lastYear) || Objects.isNull(threshold)) {
            return null;
        }
        if (lastYear.compareTo(BigDecimal.ZERO)==0){
            return null;
        }
        return  (threshold.subtract(lastYear)).divide(lastYear, 6, BigDecimal.ROUND_HALF_EVEN).multiply(new BigDecimal(-100));
    }

    /**
     * 10到12月为月度目标中的10、11、12加和求平均。
     *
     * @param target 今年 10到12月总和
     * @return
     */
    public static BigDecimal comparedTarget(BigDecimal target) {
        if (Objects.isNull(target)) {
            return null;
        }
        //进位取整
        BigDecimal result = target.divide(new BigDecimal(3), 2, BigDecimal.ROUND_HALF_EVEN).setScale(0, BigDecimal.ROUND_HALF_EVEN);
        return result;
    }


    /**
     * 次年1月到3月为，秋冬防总目标乘以六减去10、11、12月份的月度目标总和除以三
     *
     * @param targetGoal    总目标
     * @param targetMonthly 10、11、12月份的月度目标总和
     * @return
     */
    public static BigDecimal comparedMonthly(BigDecimal targetGoal, BigDecimal targetMonthly) {
        if (Objects.isNull(targetGoal) || Objects.isNull(targetMonthly)) {
            return null;
        }
        BigDecimal multiply = targetGoal.multiply(new BigDecimal(6));
        BigDecimal subtract = multiply.subtract(targetMonthly);
        BigDecimal result = subtract.divide(new BigDecimal(3), 2, BigDecimal.ROUND_HALF_EVEN).setScale(0, BigDecimal.ROUND_HALF_EVEN);
        return result;
    }

    /**
     * 原      根据不同因子，PM2.5、SO2、NO2同比变化率小于5%为“有望达标”，5%-10%“有压力”，10%以上为“不可达标”
     *         PM10同比变化率小于10%为“有望达标”，10%-20%“有压力”，20%以上为“不可达标”
     *
     * 现     根据不同因子，PM2.5、SO2、NO2同比变化率大于-5%为“有望达标”，-5%到-10%“有压力”，-10%以下为“不可达标”
     *       PM10同比变化率大于-10%为“有望达标”，-10%到-20%“有压力”，-20%以下为“不可达标”
     * @param divisor  因子
     * @param gradient 同比变化率
     * @return
     */
    public static String comparedGradient(String divisor, BigDecimal gradient) {
        BigDecimal[][] rangeIndex = {
                {new BigDecimal(-10), new BigDecimal(-20)}, //PM10
                {new BigDecimal(-5), new BigDecimal(-10)}, //PM25
                {new BigDecimal(-5), new BigDecimal(-10)}, //O3
                {new BigDecimal(-5), new BigDecimal(-10)}, //SO2
                {new BigDecimal(-5), new BigDecimal(-10)}, //NO2
                {new BigDecimal(-5), new BigDecimal(-10)}, //CO
        };
//        1有望达标 2有压力 3不可达标
        String[] names = {"3", "2", "1"};

        if (Objects.isNull(divisor) || Objects.isNull(gradient)) {
            return null;
        }
        String result = "";
        switch (divisor) {
            case PM10:
                result = obtainFactor(gradient, rangeIndex[0], names);
                break;
            case PM25:
                result = obtainFactor(gradient, rangeIndex[1], names);
                break;
            case O3:
                result = obtainFactor(gradient, rangeIndex[2], names);
                break;
            case SO2:
                result = obtainFactor(gradient, rangeIndex[3], names);
                break;
            case NO2:
                result = obtainFactor(gradient, rangeIndex[4], names);
                break;
            case CO:
                result = obtainFactor(gradient, rangeIndex[5], names);
                break;
        }
        return result;
    }


    /**
     * 根据不同因子,返回不同名称
     *
     * @param gradient
     * @param data
     * @param names
     * @return
     */
    private static String obtainFactor(BigDecimal gradient, BigDecimal[] data, String[] names) {
        String result = "";
        if (gradient.compareTo(data[0]) == -1) {
            result = names[0];
        } else if (gradient.compareTo(data[1]) < 1) {
            result = names[1];
        } else {
            result = names[2];
        }
        return result;
    }


    /**
     * 达标差距： 目标值-累计值
     *
     * @param thisData    累计值
     * @param targetValue 目标值
     * @return
     */
    public static BigDecimal getStandardData(BigDecimal thisData, BigDecimal targetValue) {
        if (Objects.isNull(thisData) || Objects.isNull(targetValue)) {
            return null;
        } else if (Objects.isNull(thisData) && Objects.nonNull(targetValue)) {
            return targetValue;
        } else if (Objects.nonNull(thisData) && Objects.isNull(targetValue)) {
            return thisData.multiply(new BigDecimal(-1));
        } else if (Objects.nonNull(thisData) && Objects.nonNull(targetValue)) {
            BigDecimal subtract = targetValue.subtract(thisData);
            return subtract;
        }
        return null;
    }


    public static void main(String[] args) {
//        BigDecimal decimal = thresholdToData(new BigDecimal(2), new BigDecimal(1), "3");
//        System.out.println(decimal);

//        String s = comparedGradient(CO, new BigDecimal(11));
//        System.out.println(s);

        Map timeType = getTimeType("5");
        System.out.println(timeType);
    }

    /**
     * 根据年份判断每月的天数
     *
     * @param year 年份
     * @return
     */
    public static int[] yearMonthDays(int year) {
        //与或
        if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
        {
            return NORMAL_MONTH;
        } else {
            return LEAPYEAR_MONTH;
        }
    }

    /**
     * o38h 处理日数据
     * @param cumulativeDataList
     * @return
     */
   /* public static BigDecimal calcO38HData(List<QEnvgasAreaHour> cumulativeDataList) {
        if (CollectionUtils.isEmpty(cumulativeDataList)||cumulativeDataList.size()<8){
            return null;
        }
        cumulativeDataList.stream().sorted(Comparator.comparing(QEnvgasAreaHour::getData_time).reversed()).collect(Collectors.toList());
        List<BigDecimal> list = new ArrayList<>();
        int data=cumulativeDataList.size()-8;
        for (int i = 0; i <= data; i++) {
            List<QEnvgasAreaHour> airQualityData = cumulativeDataList.subList(i, 8+i);
            List<BigDecimal> collect = airQualityData.stream().filter(e -> Objects.nonNull(e) && Objects.nonNull(e.getO3())).map(QEnvgasAreaHour::getO3).collect(Collectors.toList());
            BigDecimal dataValue = AirDataConverseUtil.decimalAvgValue(collect);
            list.add(dataValue);
        }
        BigDecimal decimal = AirDataConverseUtil.decimalAvgValue(list.stream().filter(e->e!=null).collect(Collectors.toList()));
        return decimal;
    }
*/

}
