package org.jeecg.modules.pay.unionPay;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSONObject;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.jeecg.async.ThreadPoolProperties;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.modules.pay.config.WeChatProfitSharingService;
import org.jeecg.modules.pay.config.WechatReceiver;
import org.jeecg.modules.system.app.entity.AppProfitSharingInfo;
import org.jeecg.modules.system.util.SecurityUtil;

import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

public class SM3Util {
    private static final String ENCODING = "UTF-8";

//    public static void main(String[] args) throws Exception {
//        String srcStr = "今天天气很晴朗";
//        String key = "zjqzjq";
//        // ******************************自定义密钥加密及校验*****************************************
//        String hexStrByKey = SM3Util.encrypt(srcStr, key);
//        System.out.println("带密钥加密后的密文：" + hexStrByKey);
//
//        System.out.println("明文(带密钥)与密文校验结果：" + SM3Util.verify(srcStr, key, hexStrByKey));
//
//        // ******************************无密钥的加密及校验******************************************
//        String hexStrNoKey = SM3Util.encrypt(srcStr);
//        System.out.println("不带密钥加密后的密文：" + hexStrNoKey);
//
//        System.out.println("明文(不带密钥)与密文校验结果：" + SM3Util.verify(srcStr, hexStrNoKey));
//
//    }

    private static final BigDecimal MIN_THRESHOLD = new BigDecimal("0.01"); // 最小阈值

    /**
     * 计算千分之6并处理临界值
     *
     * @param input 输入金额（单位：元）
     * @return 计算结果（保留两位小数，不足0.01按0.01计算）
     * @throws IllegalArgumentException 输入为null或负数时抛出
     */
    public static BigDecimal calculate(BigDecimal input, BigDecimal multiplier) {
        if (input == null) {
            throw new IllegalArgumentException("输入金额不能为null");
        }
        if (input.compareTo(BigDecimal.ZERO) < 0) {
            throw new IllegalArgumentException("输入金额不能为负数");
        }

        // 精确乘法运算（保留4位中间精度）
        BigDecimal product = input.multiply(multiplier)
                .setScale(4, RoundingMode.HALF_UP);

        // 临界值判断与补偿
        return product.compareTo(MIN_THRESHOLD) < 0
                ? MIN_THRESHOLD
                : product.setScale(2, RoundingMode.DOWN);
    }

    public static void main(String[] args) throws Exception {

        BigDecimal price = new BigDecimal("0.3");

        BigDecimal FEE = calculate(price, new BigDecimal("0.006"));

        price = price.subtract(FEE);

        BigDecimal total1 = price;
        BigDecimal[] ratios1 = {new BigDecimal("89.4"), new BigDecimal("0"), new BigDecimal("10.6")}; // 总和100 → 直接分配
        System.out.println("示例1结果：" + Arrays.toString(allocate(total1, ratios1)));
        System.out.println(amount_fee(new BigDecimal(0.01)).multiply(new BigDecimal(0.06)).setScale(0, RoundingMode.UP));
    }

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

    /**
     * 按比例分配金额，自动标准化比例为总和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 final int DEFAULT_SCALE = 10; // 默认计算精度
    private static final RoundingMode DEFAULT_ROUNDING = RoundingMode.UP;

    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);
    }

    /**
     * 加密
     *
     * @param src 明文
     * @param key 密钥
     * @return
     * @throws Exception
     */
    public static String encrypt(String src, String key) throws Exception {
        return ByteUtils.toHexString(getEncryptByKey(src, key));
    }


    /**
     * SM3加密方式之： 根据自定义密钥进行加密，返回加密后长度为32位的16进制字符串
     *
     * @param src 源数据
     * @param key 密钥
     * @return
     * @throws Exception
     */
    public static byte[] getEncryptByKey(String src, String key) throws Exception {
        byte[] srcByte = src.getBytes(ENCODING);
        byte[] keyByte = key.getBytes(ENCODING);
        KeyParameter keyParameter = new KeyParameter(keyByte);
        SM3Digest sm3 = new SM3Digest();
        HMac hMac = new HMac(sm3);
        hMac.init(keyParameter);
        hMac.update(srcByte, 0, srcByte.length);
        byte[] result = new byte[hMac.getMacSize()];
        hMac.doFinal(result, 0);
        return result;
    }

    /**
     * 利用源数据+密钥校验与密文是否一致
     *
     * @param src       源数据
     * @param key       密钥
     * @param sm3HexStr 密文
     * @return
     * @throws Exception
     */
    public static boolean verify(String src, String key, String sm3HexStr) throws Exception {
        byte[] sm3HashCode = ByteUtils.fromHexString(sm3HexStr);
        byte[] newHashCode = getEncryptByKey(src, key);
        return Arrays.equals(newHashCode, sm3HashCode);
    }

    /**
     * SM3加密方式之：不提供密钥的方式 SM3加密，返回加密后长度为64位的16进制字符串
     *
     * @param src 明文
     * @return
     */
    public static String encrypt(String src) {
        return ByteUtils.toHexString(getEncryptBySrcByte(src.getBytes()));
    }

    /**
     * 返回长度为32位的加密后的byte数组
     *
     * @param srcByte
     * @return
     */
    public static byte[] getEncryptBySrcByte(byte[] srcByte) {
        SM3Digest sm3 = new SM3Digest();
        sm3.update(srcByte, 0, srcByte.length);
        byte[] encryptByte = new byte[sm3.getDigestSize()];
        sm3.doFinal(encryptByte, 0);
        return encryptByte;
    }

    /**
     * 校验源数据与加密数据是否一致
     *
     * @param src       源数据
     * @param sm3HexStr 16进制的加密数据
     * @return
     * @throws Exception
     */
    public static boolean verify(String src, String sm3HexStr) throws Exception {
        byte[] sm3HashCode = ByteUtils.fromHexString(sm3HexStr);
        byte[] newHashCode = getEncryptBySrcByte(src.getBytes(ENCODING));
        return Arrays.equals(newHashCode, sm3HashCode);
    }
}
