package top.imwork.commons.core.utils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;

/**
 * Copyright (C), 2015-2022
 * FileName: BigDecimalUtils
 * Author<作者姓名>:   stars
 * CreateTime<创建时间>:   2022/4/14 16:57
 * UpdateTime<修改时间>:   2022/4/14 16:57
 * Description〈功能简述〉: BigDecimal工具类
 * History<历史描述>:
 * Since<版本号>: 1.0.0
 */
public class DecimalUtils {

    public interface Operation {
        boolean calculate(BigDecimal a, BigDecimal b);
    }

    public static final Map<String, Operation> opMap = new HashMap<>();

    static {
        opMap.put(">", ((a, b) -> a.compareTo(b) > 0));
        opMap.put(">=", ((a, b) -> a.compareTo(b) > -1));
        opMap.put("<", ((a, b) -> a.compareTo(b) < 0));
        opMap.put("<=", ((a, b) -> a.compareTo(b) < 1));
        opMap.put("=", ((a, b) -> a.compareTo(b) == 0));
        opMap.put("!=", ((a, b) -> a.compareTo(BigDecimal.ZERO) == 0));
    }

    /**
     * 设置精度
     *
     * @param value 要设置的值
     * @param scale 精度
     * @param mode  进位类型
     * @return BigDecimal 精度转换后结果
     */
    public static BigDecimal scale(BigDecimal value, int scale, RoundingMode mode) {
        if (StringUtils.isEmpty(value)) {
            return value;
        } else if (StringUtils.isEmpty(mode)) {
            return value.setScale(scale, RoundingMode.HALF_UP);
        } else {
            return value.setScale(scale, mode);
        }
    }

    /**
     * 设置精度
     *
     * @param value 要设置的值
     * @param scale 精度
     * @param mode  进位类型
     * @return String 精度转换后结果
     */
    public static String reverseScale(BigDecimal value, int scale, RoundingMode mode) {
        BigDecimal reverseValue = scale(value, scale, mode);
        if (StringUtils.isEmpty(reverseValue)) {
            return null;
        }
        return reverseValue.toString();
    }

    /**
     * BigDecimal 加法
     *
     * @param a 被减数
     * @param b 减数
     * @return BigDecimal   计算结果
     */
    public static BigDecimal add(String a, String b) {
        if (NumberUtils.isNumber(a) && NumberUtils.isNumber(b)) {
            return new BigDecimal(a).add(new BigDecimal(b));
        }
        return null;
    }

    /**
     * BigDecimal 加法
     *
     * @param a 被减数
     * @param b 减数
     * @return BigDecimal   计算结果
     */
    public static BigDecimal add(BigDecimal a, BigDecimal b) {
        if (StringUtils.isEmpty(a) || StringUtils.isEmpty(b)) {
            return null;
        }
        return a.add(b);
    }

    /**
     * BigDecimal 减法
     *
     * @param a 被减数
     * @param b 减数
     * @return BigDecimal   计算结果
     */
    public static BigDecimal subtract(String a, String b) {
        if (NumberUtils.isNumber(a) && NumberUtils.isNumber(b)) {
            return new BigDecimal(a).subtract(new BigDecimal(b));
        }
        return null;
    }

    /**
     * BigDecimal 减法
     *
     * @param a 被减数
     * @param b 减数
     * @return BigDecimal   计算结果
     */
    public static BigDecimal subtract(BigDecimal a, BigDecimal b) {
        if (StringUtils.isEmpty(a) || StringUtils.isEmpty(b)) {
            return null;
        }
        return a.subtract(b);
    }

    /**
     * BigDecimal 除法
     *
     * @param a 被除数
     * @param b 除数
     * @return BigDecimal   计算结果
     */
    public static BigDecimal divide(String a, String b, Integer scale) {
        if (NumberUtils.isNumber(a) && NumberUtils.isNumber(b)) {
            if (new BigDecimal(b).compareTo(BigDecimal.ZERO) == 0) {
                return new BigDecimal(0);
            }
            if (scale == null) {
                scale = 4;
            }
            if (opMap.get("<").calculate(new BigDecimal(a), new BigDecimal(0)) && opMap.get("<").calculate(new BigDecimal(b), new BigDecimal(0))) {
                return new BigDecimal(a).divide(new BigDecimal(b), scale, RoundingMode.HALF_UP).negate();
            }
            return new BigDecimal(a).divide(new BigDecimal(b), scale, RoundingMode.HALF_UP);
        }
        return null;
    }

    /**
     * BigDecimal 除法
     *
     * @param a 被除数
     * @param b 除数
     * @return BigDecimal   计算结果
     */
    public static BigDecimal divide(BigDecimal a, BigDecimal b, Integer scale) {
        if (StringUtils.isEmpty(a) || StringUtils.isEmpty(b)) {
            return null;
        }
        if (b.compareTo(BigDecimal.ZERO) == 0) {
            return new BigDecimal(0);
        }
        if (scale == null) {
            scale = 4;
        }
        return a.divide(b, scale, RoundingMode.HALF_UP);
    }

    /**
     * BigDecimal 乘法
     *
     * @param a 被乘数
     * @param b 乘数
     * @return BigDecimal   计算结果
     */
    public static BigDecimal multiply(BigDecimal a, BigDecimal b, Integer scale) {
        if (StringUtils.isEmpty(a) || StringUtils.isEmpty(b)) {
            return null;
        }
        if (a.compareTo(BigDecimal.ZERO) == 0 || b.compareTo(BigDecimal.ZERO) == 0) {
            return new BigDecimal(0);
        }
        if (scale == null) {
            scale = 4;
        }
        BigDecimal value = a.multiply(b);
        return scale(value, scale, null);
    }

    /**
     * BigDecimal 乘法
     *
     * @param a 被乘数
     * @param b 乘数
     * @return BigDecimal   计算结果
     */
    public static String multiply(String a, String b, Integer scale) {
        if (StringUtils.isEmpty(a) || StringUtils.isEmpty(b)) {
            return null;
        }
        if (new BigDecimal(a).compareTo(BigDecimal.ZERO) == 0 || new BigDecimal(b).compareTo(BigDecimal.ZERO) == 0) {
            return new BigDecimal(0).toString();
        }
        if (scale == null) {
            scale = 4;
        }
        BigDecimal value = new BigDecimal(a).multiply(new BigDecimal(b));
        return reverseScale(value, scale, null);
    }
    private DecimalUtils() {
    }
}