package com.smppw.utils;

import com.smppw.common.pojo.enums.Frequency;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;

/**
 * @author Zheng SongLiang
 */
public class MathUtils {

    public static final String DIGIT = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    /**
     * 获取年化收益率，用365.25 / 区间天数
     *
     * @param values      收益序列
     * @param dateList    日期序列
     * @param ifAnnualize 是否年化
     * @return /
     */
    public static Double getAnnualReturn(List<Double> values, List<String> dateList, boolean ifAnnualize) {
        Double intervalReturn = getIntervalReturn(values);

        int n = dateList.size();
        if (intervalReturn == null || n < 2) {
            return null;
        }

        if (!ifAnnualize) {
            return intervalReturn;
        }

        String firstDate = dateList.get(0);
        String lastDate = dateList.get(n - 1);

        int dateDis = DateUtil.getDateDistance(firstDate, lastDate, Frequency.Daily, false);

        return Math.pow(1 + intervalReturn, 365.25 / dateDis) - 1;
    }

    public static Double getIntervalReturn(List<Double> values) {
        return getIntervalReturn(values, false, null);
    }

    public static Double getIntervalReturn(List<Double> values, boolean ifAnnualize, Frequency frequency) {
        CommonUtil.removeNull(values);
        if (values.isEmpty())
            return null;
        double intervalReturn = 1D;
        for (Double v : values) {
            intervalReturn *= v + 1;
        }
        intervalReturn -= 1;

        if (!ifAnnualize)
            return intervalReturn;
        else
            return Math.pow(intervalReturn + 1, frequency.getNum() / values.size()) - 1;
    }

    public static double roundOff(double dou, int decimal) {
        return MathUtils.round(dou, decimal, BigDecimal.ROUND_HALF_UP);
    }

    private static double round(double dou, int decimal, int model) {
        if (isInvalidateFloat(dou))
            return dou;
        BigDecimal bd = new BigDecimal(dou);
        BigDecimal bd1 = bd.setScale(decimal, model);
        dou = bd1.doubleValue();
        return dou;
    }

    private static boolean isInvalidateFloat(double dou) {
        return Double.isNaN(dou) || Double.isInfinite(dou);
    }

    public static String fromTen2TargetDecimal(long num, int base) {
        return Long.toString(num, base).toUpperCase();
    }

    public static long fromTargetDecimal2Ten(String str, int base) {
        return Long.valueOf(str, base);
    }

    public static String fromTen2TargetDecimal(BigInteger num, int base) {
        String str = "";
        if (num.shortValue() == 0) {
            return "";
        } else {
            BigInteger valueOf = BigInteger.valueOf(base);
            str = fromTen2TargetDecimal(num.divide(valueOf), base);
            return str + MathUtils.DIGIT.charAt(num.mod(valueOf).shortValue());
        }
    }

    /**
     * 以 2 为底, d 的对数
     */
    public static double log2(int d) {
        return Math.log(d) / Math.log(2);
    }

    public static double add(double a1, double b1) {
        BigDecimal a2 = new BigDecimal(Double.toString(a1));
        BigDecimal b2 = new BigDecimal(Double.toString(b1));
        return a2.add(b2).doubleValue();
    }

    // 相减
    public static double sub(double a1, double b1) {
        BigDecimal a2 = new BigDecimal(Double.toString(a1));
        BigDecimal b2 = new BigDecimal(Double.toString(b1));
        return a2.subtract(b2).doubleValue();
    }

    // 相乘
    public static double mul(double a1, double b1) {
        BigDecimal a2 = new BigDecimal(Double.toString(a1));
        BigDecimal b2 = new BigDecimal(Double.toString(b1));
        return a2.multiply(b2).doubleValue();
    }

    // 相除
    public static double div(double a1, double b1, int scale) {
        // scale参数为除不尽时，指定精度。
        if (scale < 0) {
            throw new IllegalArgumentException("error");
        }
        BigDecimal a2 = new BigDecimal(Double.toString(a1));
        BigDecimal b2 = new BigDecimal(Double.toString(b1));
        return a2.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    public static double div(double a1, double b1) {
        return div(a1, b1, 8);
    }

    /**
     * 基准净值计算（归一）
     *
     * @param v1 其实起始点
     * @param v2 计算界点
     * @return 归一结果
     */
    public static double normalize(double v1, double v2) {
        if (v1 == 0.0d) {
            return 0.0d;
        }
        return v2 / v1;
    }

}
