package cn.iocoder.yudao.framework.common.util.number;


import cn.hutool.core.util.StrUtil;

import java.math.BigDecimal;
import java.math.BigInteger;

/**
 * @Desc:
 * @Author: aikai
 * @Date: 2025/04/11
 */
public class BigDecimalUtil {

    // 默认除法运算精度
    private static final int DEF_DIV_SCALE = 2;
    private static final BigDecimal ZERO = new BigDecimal(0);

    // 这个类不能实例化
    private BigDecimalUtil() {
    }

    // 是否大于0
    public static boolean isGreaterThanZero(Object value) {
        if (null == value) {
            value = BigDecimal.ZERO;
        }
        return getBigDecimal(value).compareTo(ZERO) > 0;
    }

    // 是否大于0
    public static boolean isGreaterThanOrEqualToZero(Object value) {
        if (null == value) {
            value = BigDecimal.ZERO;
        }
        return getBigDecimal(value).compareTo(ZERO) >= 0;
    }

    // 是否小于0
    public static boolean isLessThanZero(Object value) {
        if (null == value) {
            value = BigDecimal.ZERO;
        }
        return getBigDecimal(value).compareTo(ZERO) < 0;
    }

    // 是否小于等于0
    public static boolean isLessThanOrEqualToZero(Object value) {
        if (null == value) {
            value = BigDecimal.ZERO;
        }
        return getBigDecimal(value).compareTo(ZERO) <= 0;
    }

    // 是否大于
    public static boolean isGreaterThan(Object v1, Object v2) {
        if (null == v1) {
            v1 = BigDecimal.ZERO;
        }
        if (null == v2) {
            v2 = BigDecimal.ZERO;
        }
        return getBigDecimal(v1).compareTo(getBigDecimal(v2)) > 0;
    }

    // 是否大于等于
    public static boolean isGreaterThanOrEqualTo(Object v1, Object v2) {
        if (null == v1) {
            v1 = BigDecimal.ZERO;
        }
        if (null == v2) {
            v2 = BigDecimal.ZERO;
        }
        return getBigDecimal(v1).compareTo(getBigDecimal(v2)) >= 0;
    }


    // 是否小于
    public static boolean isLessThan(Object v1, Object v2) {
        if (null == v1) {
            v1 = BigDecimal.ZERO;
        }
        if (null == v2) {
            v2 = BigDecimal.ZERO;
        }
        return getBigDecimal(v1).compareTo(getBigDecimal(v2)) < 0;
    }

    // 是否小于等于
    public static boolean isLessThanOrEqualTo(Object v1, Object v2) {
        if (null == v1) {
            v1 = BigDecimal.ZERO;
        }
        if (null == v2) {
            v2 = BigDecimal.ZERO;
        }
        return getBigDecimal(v1).compareTo(getBigDecimal(v2)) <= 0;
    }

    // 是否等于
    public static boolean isEqualTo(Object v1, Object v2) {
        if (null == v1) {
            v1 = BigDecimal.ZERO;
        }
        if (null == v2) {
            v2 = BigDecimal.ZERO;
        }
        BigDecimal var1 = getBigDecimal(v1);
        BigDecimal var2 = getBigDecimal(v2);
        return var1.compareTo(var2) == 0;
    }

    public static boolean isEqZero(Object v1) {
        if (null == v1) {
            v1 = BigDecimal.ZERO;
        }
        BigDecimal var1 = getBigDecimal(v1);
        return var1.compareTo(BigDecimal.ZERO) == 0;
    }

    // 是否为空 /
    public static boolean isEmpty(Object obj) {
        if (null == obj) {
            return true;
        }
        if (isEqualTo(BigDecimal.ZERO, obj)) {
            return true;
        }
        return false;
    }

    public static boolean isNotEmpty(Object obj) {
        if (null == obj) {
            return false;
        }
        if (isEqualTo(BigDecimal.ZERO, obj)) {
            return false;
        }
        return true;
    }

    /**
     * 提供精确的加法运算。
     *
     * @param v1 被加数
     * @param v2 加数
     * @return 两个参数的和
     */
    public static BigDecimal add(Object v1, Object v2) {
        if (null == v1) {
            v1 = BigDecimal.ZERO;
        }
        if (null == v2) {
            v2 = BigDecimal.ZERO;
        }
        return getBigDecimal(v1).add(getBigDecimal(v2));
    }

    /**
     * 提供精确的减法运算。
     *
     * @param v1 被减数
     * @param v2 减数
     * @return 两个参数的差
     */
    public static BigDecimal sub(Object v1, Object v2) {
        if (null == v1) {
            v1 = BigDecimal.ZERO;
        }
        if (null == v2) {
            v2 = BigDecimal.ZERO;
        }
        return getBigDecimal(v1).subtract(getBigDecimal(v2));
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     */
    public static BigDecimal mul(Object v1, Object v2) {
        if (null == v1) {
            v1 = BigDecimal.ZERO;
        }
        if (null == v2) {
            v2 = BigDecimal.ZERO;
        }
        return getBigDecimal(v1).multiply(getBigDecimal(v2));
    }

    /**
     * 提供精确的乘法运算
     *
     * @param v1
     * @param arg
     * @return 多数
     */
    public static BigDecimal mostMul(Object v1, Object... arg) {
        if (v1 == null) {
            v1 = BigDecimal.ZERO;
        }
        for (Object obj : arg) {
            if (obj == null) {
                obj = BigDecimal.ZERO;
            }
            v1 = getBigDecimal(v1).multiply(getBigDecimal(obj));

        }
        return (BigDecimal) v1;
    }

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

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

    public static BigDecimal div(Object v1, Object v2, int scale, int roundingMode) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        return getBigDecimal(v1).divide(getBigDecimal(v2), scale, roundingMode);
    }

    /**
     * Object转BigDecimal类型
     *
     * @param value 要转的object类型
     * @return 转成的BigDecimal类型数据
     */
    public static BigDecimal getBigDecimal(Object value) {
        BigDecimal ret = null;
        if (value != null) {
            if (value instanceof BigDecimal) {
                ret = (BigDecimal) value;
            } else if (value instanceof String) {
                if (StrUtil.isEmpty((String) value)) {
                    value = "0";
                }
                ret = new BigDecimal((String) value);
            } else if (value instanceof BigInteger) {
                ret = new BigDecimal((BigInteger) value);
            } else if (value instanceof Number) {
                ret = new BigDecimal(value.toString());
            } else if (value instanceof Integer) {
                ret = new BigDecimal((Integer) value);
            } else {
                throw new ClassCastException("Not possible to coerce [" + value + "] from class " + value.getClass() + " into a BigDecimal.");
            }
        } else {
            return BigDecimal.ZERO;
        }
        return ret;
    }

    /**
     * 差
     *
     * @param i
     * @param arg
     * @return
     */
    public static BigDecimal subs(BigDecimal i, BigDecimal... arg) {
        BigDecimal difference = i;
        for (BigDecimal b : arg) {
            difference = difference.subtract(b);
        }
        return difference;
    }

    public static BigDecimal getZeroMax(BigDecimal bigDecimal) {
        if (isLessThanZero(bigDecimal)) {
            return ZERO;
        }
        return bigDecimal;
    }


    /**
     * 和
     *
     * @param i
     * @param arg
     * @return
     */
    public static BigDecimal adds(BigDecimal i, BigDecimal... arg) {
        BigDecimal bigDecimal = i;
        if (bigDecimal == null) {
            bigDecimal = BigDecimal.ZERO;
        }
        for (BigDecimal b : arg) {
            if (b == null) {
                b = BigDecimal.ZERO;
            }
            bigDecimal = bigDecimal.add(b);
        }
        return bigDecimal;
    }
}
