package org.jeecg.modules.pay.config;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;

/**
 * 金额分配工具类
 * @author wzq
 * @date 2025/09/28
 */
public class RatiosUtil {

    private static final int DEFAULT_SCALE = 10; // 默认计算精度
    private static final RoundingMode DEFAULT_ROUNDING = RoundingMode.HALF_UP;

    /**
     * 金额元转分字符串
     *
     * @param cny 元
     * @return
     */
    public static Integer amount_fee(BigDecimal cny) {
        BigDecimal b2 = new BigDecimal("100");
        return cny.multiply(b2).setScale(0, RoundingMode.DOWN).intValue();
    }

    /**
     * 按比例分配金额，自动标准化比例为总和100
     *
     * @param totalAmount 总金额（单位：元）
     * @param ratios      原始比例数组（支持任意总和）
     * @return 分配结果数组（保留两位小数）
     * @throws IllegalArgumentException 输入包含负数或零元素时抛出
     */
    public static BigDecimal[] allocate(BigDecimal totalAmount, BigDecimal... ratios) {
        validateRatios(ratios);
        BigDecimal[] normalizedRatios = normalizeRatios(ratios); // 标准化为总和100
        return allocateWithNormalizedRatios(totalAmount, normalizedRatios);
    }

    private static void validateRatios(BigDecimal[] ratios) {
        if (ratios == null || ratios.length == 0) {
            throw new IllegalArgumentException("比例数组不能为空");
        }
        for (BigDecimal ratio : ratios) {
            if (ratio.compareTo(BigDecimal.ZERO) < 0) {
                throw new IllegalArgumentException("比例不能为负数: " + ratio);
            }
        }
    }

    private static BigDecimal[] normalizeRatios(BigDecimal[] ratios) {
        BigDecimal sum = Arrays.stream(ratios)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        if (sum.compareTo(new BigDecimal("100")) != 0) {
            throw new ArithmeticException("标准化后比例总和必须为100");
        }

        BigDecimal[] normalized = new BigDecimal[ratios.length];
        BigDecimal remainder = BigDecimal.ZERO;
        for (int i = 0; i < ratios.length; i++) {
            // 精确计算标准化值（保留10位小数）
            normalized[i] = ratios[i].divide(sum, DEFAULT_SCALE, DEFAULT_ROUNDING);
            remainder = remainder.add(normalized[i]);
        }

        // 处理余数误差（精度补偿）
        BigDecimal expectedSum = BigDecimal.ONE;
        BigDecimal actualSum = remainder.stripTrailingZeros();
        if (!expectedSum.equals(actualSum)) {
            BigDecimal compensation = expectedSum.subtract(actualSum);
            normalized[0] = normalized[0].add(compensation);
        }
        return normalized;
    }

    private static BigDecimal[] allocateWithNormalizedRatios(BigDecimal totalAmount, BigDecimal[] ratios) {
        BigDecimal amountInCents = totalAmount.movePointRight(2);
        BigDecimal[] results = new BigDecimal[ratios.length];
        Arrays.fill(results, BigDecimal.ZERO);

        // 精确分配
        for (int i = 0; i < ratios.length; i++) {
            results[i] = amountInCents.multiply(ratios[i])
                    .setScale(0, RoundingMode.DOWN);
        }

        // 处理余数分配（原子操作保证线程安全）
        BigDecimal totalAllocated = Arrays.stream(results)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal remainder = amountInCents.subtract(totalAllocated);
        for (int i = 0; i < remainder.intValue(); i++) {
            results[i] = results[i].add(BigDecimal.ONE);
        }

        return Arrays.stream(results)
                .map(r -> r.movePointLeft(2).setScale(2, DEFAULT_ROUNDING))
                .toArray(BigDecimal[]::new);
    }
}
