package org.jeecg.modules.app.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.aliyun.oss.ServiceException;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.modules.pay.config.*;
import org.jeecg.modules.pay.serverPay.WXPayUtility;
import org.jeecg.modules.rabbitmq.DelayedMessageService;
import org.jeecg.modules.system.app.dto.receiptPaymentDetails.ReceiptPaymentDetailsInfoVo;
import org.jeecg.modules.system.app.entity.*;
import org.jeecg.modules.system.app.mapper.*;
import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.mapper.SysDepartMapper;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author wangzhiqiang
 * @Date 2025/8/21
 * @Desc 微信支付相关服务接口
 */
@Slf4j
@Service
public class WeChatPayService {

    @Resource
    private WechatPayV3Utils wechatPayV3Utils;

    @Resource
    private AppOrderMapper appOrderMapper;

    @Resource
    private AppOrderProInfoMapper appOrderProInfoMapper;

    @Resource
    private AppOrderRefundsInfoMapper appOrderRefundsInfoMapper;

    @Resource
    private SeparateAccountsMapper separateAccountsMapper;

    @Resource
    private SysDepartMapper sysDepartMapper;

    @Resource
    private AppProfitSharingInfoMapper appProfitSharingInfoMapper;

    @Resource
    private WeChatProfitSharingService weChatProfitSharingService;
    @Resource
    private ShopMoneyMapper shopMoneyMapper;
    // 声明一个可重入锁
    private final ReentrantLock lock = new ReentrantLock();

    /**
     * 小程序支付拉起
     *
     * @param params
     * @return
     * @throws ServiceException
     */
    public Map<String, String> wechatPay(JSONObject params) throws ServiceException {

        //发起请求
        JSONObject res = wechatPayV3Utils.sendPost(WechatUrlConstants.PAY_V3_JSAPI, params);
        log.info("wechatPay res:{}", res.toString());
        if (StrUtil.isEmpty(res.getString("prepay_id"))) {
            throw new ServiceException("支付发起失败");
        }

        StringBuilder sb = new StringBuilder();
        //返回给小程序拉起微信支付的参数
        Map<String, String> result = new HashMap<>();
        result.put("appId", WechatConstants.WECHAT_SUB_APPID); //小程序appid
        sb.append(result.get("appId")).append("\n");
        result.put("timeStamp", (new Date().getTime() / 1000) + ""); //时间戳
        sb.append(result.get("timeStamp")).append("\n");
        result.put("nonceStr", RandomStringUtils.randomAlphanumeric(32)); //32位随机字符串
        sb.append(result.get("nonceStr")).append("\n");
        result.put("package", "prepay_id=" + res.getString("prepay_id")); //预支付id 格式为 prepay_id=xxx
        sb.append(result.get("package")).append("\n");
        //签名
        result.put("paySign", wechatPayV3Utils.signRSA(sb.toString()));
        result.put("signType", "RSA"); //加密方式 固定RSA
        result.put("out_trade_no", params.getString("out_trade_no")); //商户订单号 此参数不是小程序拉起支付所需的参数 因此不参与签名

        return result;
    }

//    public static void main(String[] args) {
//        String s = "{\"mchid\":\"1523499681\",\"appid\":\"wx9b0396a7507e3d66\",\"out_trade_no\":\"4022961176\"," +
//                "\"transaction_id\":\"4200001859202306051015832415\",\"trade_type\":\"JSAPI\",\"trade_state\":\"SUCCESS\",\"trade_state_desc\":\"支付成功\",\"bank_type\":\"ICBC_DEBIT\",\"attach\":\"4022961176\",\"success_time\":\"2023-06-05T14:45:20+08:00\",\"payer\":{\"openid\":\"ok_fR5NmcrTnxFwiSlyd58_TuXrU\"},\"amount\":{\"total\":1,\"payer_total\":1,\"currency\":\"CNY\",\"payer_currency\":\"CNY\"}}";
//        JSONObject res = JSONObject.parseObject(s);
//        String payer_total = res.getJSONObject("amount").getString("payer_total");
//        BigDecimal bigDecimal = new BigDecimal(payer_total);
//        System.out.println(dealDateFormat(res.get("success_time").toString()));
//        //获取当前日期
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
//
//        String format = sdf.format(DateUtils.getNowDate());
//
//        System.out.println(format);
//    }

    public static Date dealDateFormat(String oldDateStr) {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
        try {
            Date date = df.parse(oldDateStr);
            return date;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 测试微信支付有优惠情况的数据获取
     *
     * @param args
     */
    public static void main(String[] args) {
        String obj = "{\"amount\":{\"currency\":\"CNY\",\"payer_currency\":\"CNY\",\"payer_total\":18300,\"total\":18400}," +
                "\"appid\":\"wx9b0396a7507e3d66\",\"attach\":\"20230915155102291908100\",\"bank_type\":\"PAB_CREDIT\",\"mchid\":\"1523499681\",\"out_trade_no\":\"20230915155102291908100\",\"payer\":{\"openid\":\"ok_fR5N24KGz9zQBCKNoWgzuT57Y\"},\"promotion_detail\":[{\"amount\":100,\"coupon_id\":\"50099133534\",\"currency\":\"CNY\",\"goods_detail\":[],\"merchant_contribute\":0,\"name\":\"平安信用卡9月专属\",\"other_contribute\":100,\"scope\":\"GLOBAL\",\"stock_id\":\"17950154\",\"type\":\"CASH\",\"wechatpay_contribute\":0}],\"success_time\":\"2023-09-15T15:51:23+08:00\",\"trade_state\":\"SUCCESS\",\"trade_state_desc\":\"支付成功\",\"trade_type\":\"JSAPI\",\"transaction_id\":\"4200001916202309158539287225\"}";

        JSONObject res = JSONObject.parseObject(obj);

        String payer_total = res.getJSONObject("amount").getString("payer_total");

        System.out.println(payer_total);

        String openid = res.getJSONObject("payer").getString("openid");

        System.out.println(openid);

        Date successTime = dealDateFormat(res.get("success_time").toString());

        System.out.println(successTime);

        BigDecimal discounts = new BigDecimal("0");

        String discountsName = "";

        if (ObjectUtil.isNotEmpty(res.getJSONArray("promotion_detail"))) {

            JSONArray jsonArray = res.getJSONArray("promotion_detail");

            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);

                if (ObjectUtil.isNotEmpty(jsonObject.getString("amount"))) {
                    discounts =
                            discounts.add(new BigDecimal(jsonObject.getString("amount")).divide(new BigDecimal("100")).setScale(2,
                                    RoundingMode.HALF_UP));
                }

                if (ObjectUtil.isNotEmpty(jsonObject.getString("name"))) {
                    if ("".equals(discountsName)) {
                        discountsName = jsonObject.getString("name");
                    } else {
                        discountsName = discountsName + "、" + jsonObject.getString("name");
                    }
                }
                System.out.println(res);
            }
        }

        System.out.println(discountsName);
        System.out.println(res.get("promotion_detail").toString());

    }


    @Autowired
    @Qualifier("businessTaskExecutor")
    private ThreadPoolTaskExecutor businessTaskExecutor;

    @Resource
    private DelayedMessageService delayedMessageService;

    public CompletableFuture<Void> executeTaskSendMessage() {
        // 使用 runAsync 并指定自定义线程池
        return CompletableFuture.runAsync(() -> {
            // 异步任务逻辑
            System.out.println("执行线程: " + Thread.currentThread().getName());
            System.out.println("执行无返回值任务");
        }, businessTaskExecutor);
    }

    /**
     * 异步发送订单过期延迟消息
     * 判断子订单过期时间是否在第二天凌晨4点之前，是则发送延迟消息
     * @param proInfoList 子订单列表
     * @return CompletableFuture<Void>
     */
    public CompletableFuture<Void> executeTaskSendMessage(List<AppOrderProInfo> proInfoList) {
        // 使用 runAsync 并指定自定义线程池
        return CompletableFuture.runAsync(() -> {
            // 异步任务逻辑
            log.info("异步发送订单过期延迟消息 - 执行线程: {}", Thread.currentThread().getName());

            // 计算第二天凌晨4点的时间戳
            Calendar tomorrow4AM = Calendar.getInstance();
            tomorrow4AM.add(Calendar.DAY_OF_MONTH, 1);
            tomorrow4AM.set(Calendar.HOUR_OF_DAY, 4);
            tomorrow4AM.set(Calendar.MINUTE, 0);
            tomorrow4AM.set(Calendar.SECOND, 0);
            tomorrow4AM.set(Calendar.MILLISECOND, 0);
            Date tomorrow4AMDate = tomorrow4AM.getTime();
            long tomorrow4AMMillis = tomorrow4AMDate.getTime();
            
            log.info("第二天凌晨4点时间：{}", DateUtil.formatDateTime(tomorrow4AMDate));
            
            int totalCount = 0;
            int sendCount = 0;
            int skipCount = 0;

            for (AppOrderProInfo orderProInfo : proInfoList) {
                totalCount++;
                try {
                    String expireTime = orderProInfo.getExpireTime();
                    
                    // 空值检查
                    if (expireTime == null || expireTime.trim().isEmpty()) {
                        log.warn("订单[{}]过期时间为空，跳过处理", orderProInfo.getId());
                        skipCount++;
                        continue;
                    }
                    
                    // 解析过期时间
                    Date expireDate = parseExpireTime(expireTime);
                    if (expireDate == null) {
                        log.warn("订单[{}]过期时间格式错误：{}", orderProInfo.getId(), expireTime);
                        skipCount++;
                        continue;
                    }
                    
                    long expireMillis = expireDate.getTime();
                    long currentMillis = System.currentTimeMillis();
                    
                    // 判断过期时间是否在第二天凌晨4点之前
                    if (expireMillis <= tomorrow4AMMillis && expireMillis > currentMillis) {
                        // 计算延迟时间（毫秒）
                        long delayMillis = expireMillis - currentMillis;
                        
                        // 检查是否超过int最大值
                        if (delayMillis > Integer.MAX_VALUE) {
                            log.warn("订单[{}]延迟时间过长：{}ms，超过int最大值", orderProInfo.getId(), delayMillis);
                            skipCount++;
                            continue;
                        }
                        
                        int delayTime = (int) delayMillis;
                        
                        log.info("发送延迟消息 - 订单ID：{}，订单编号：{}，过期时间：{}，延迟毫秒数：{}",
                            orderProInfo.getId(), orderProInfo.getOrderCode(), expireTime, delayTime);
                        
                        delayedMessageService.sendOrderExpireMessage(
                            orderProInfo.getId(),
                            delayTime
                        );
                        sendCount++;
                    } else {
                        log.debug("订单[{}]过期时间不在第二天凌晨4点之前，跳过。过期时间：{}", 
                            orderProInfo.getId(), expireTime);
                        skipCount++;
                    }
                    
                } catch (Exception e) {
                    log.error("处理订单[{}]延迟消息时发生异常", orderProInfo.getId(), e);
                    skipCount++;
                }
            }
            
            log.info("异步发送订单过期延迟消息完成 - 总数：{}，发送：{}，跳过：{}", totalCount, sendCount, skipCount);
            
        }, businessTaskExecutor);
    }
    
    /**
     * 解析过期时间字符串
     * 支持格式：yyyy-MM-dd、yyyy-MM-dd HH:mm、yyyy-MM-dd HH:mm:ss
     * @param expireTime 过期时间字符串
     * @return Date对象，解析失败返回null
     */
    private Date parseExpireTime(String expireTime) {
        try {
            // yyyy-MM-dd 格式，转换为当天23:59:59
            if (expireTime.matches("^\\d{4}-\\d{2}-\\d{2}$")) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                Date date = sdf.parse(expireTime);
                Calendar cal = Calendar.getInstance();
                cal.setTime(date);
                cal.set(Calendar.HOUR_OF_DAY, 23);
                cal.set(Calendar.MINUTE, 59);
                cal.set(Calendar.SECOND, 59);
                return cal.getTime();
            }
            // yyyy-MM-dd HH:mm 格式
            else if (expireTime.matches("^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}$")) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
                return sdf.parse(expireTime);
            }
            // yyyy-MM-dd HH:mm:ss 格式
            else if (expireTime.matches("^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$")) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                return sdf.parse(expireTime);
            }
        } catch (ParseException e) {
            log.error("解析过期时间失败：{}", expireTime, e);
        }
        return null;
    }

    /**
     * 小程序微信支付回调
     *
     * @param request
     * @return
     */
    public Map<String, String> wechatPayNotify(HttpServletRequest request) {
        Map<String, String> result = new HashMap<>(2);
        //验签及解析返回数据
        JSONObject res = wechatPayV3Utils.getCallbackData(request);
        if (res == null) {
            result.put("code", "FAIL");
            result.put("message", "失败");
            return result;
        }
        log.info("最终拿到的微信支付通知数据：" + res);
        String orderCode = res.getString("out_trade_no");
        if (lock.tryLock()) {
            // 处理支付成功后的业务 例如 将订单状态修改为已支付 具体参数键值可参考文档 注意！！！ 微信可能会多次发送重复的通知 因此要判断业务是否已经处理过了 避免重复处理
            try {
                //查询订单，判断是否已修改为已支付状态
                AppOrder appOrder = appOrderMapper.selectOne(Wrappers.<AppOrder>lambdaQuery().eq(AppOrder::getOrderCode, orderCode).last("limit 1"));
                if (ObjectUtil.isNotEmpty(appOrder) && appOrder.getCallbackStatus() == 1) {
                    result.put("code", "SUCCESS");
                    result.put("message", "OK");
                    result.put("orderCode", orderCode);
                    return result;
                }
                if (ObjectUtil.isNotEmpty(appOrder)) {
                    if (Objects.equals(appOrder.getOrderStatus(), CommonConstant.ORDER_STATUS_0)) {
                        appOrder.setOrderStatus(CommonConstant.ORDER_STATUS_1);
                        appOrder.setPayStatus(CommonConstant.ORDER_STATUS_1);
                        appOrder.setPayTime(new Date());
                        appOrder.setPayType(CommonConstant.STATUS_0_INT);
                        appOrder.setPayId(res.getString("transaction_id"));
                        appOrder.setPayTime(dealDateFormat(res.getString("success_time")));

                        List<AppOrderProInfo> proInfoList = appOrderProInfoMapper.selectList(Wrappers.<AppOrderProInfo>lambdaQuery().eq(AppOrderProInfo::getOrderId, appOrder.getId()));
                        if (ObjectUtil.isNotEmpty(proInfoList)) {
                            for (AppOrderProInfo appOrderProInfo : proInfoList) {
                                appOrderProInfo.setOrderStatus(CommonConstant.ORDER_STATUS_1);
                                appOrderProInfoMapper.updateById(appOrderProInfo);
                            }
                        }
                        appOrder.setCallbackStatus(CommonConstant.STATUS_1_INT);
                        appOrderMapper.updateById(appOrder);
                        //创建预分账详情
                        if (appOrder.getOrProfitSharing() == 1) {
                            addProfitSharingInfos(appOrder);
                        }

                        //发送延迟消息
                        executeTaskSendMessage(proInfoList);

                        ShopMoney shopMoney = shopMoneyMapper.selectOne(Wrappers.<ShopMoney>lambdaQuery()
                                .eq(ShopMoney::getOrgCode, appOrder.getOrgCode())
                                .last("limit 1")
                                .orderByDesc(ShopMoney::getCreateTime));
                        if(null == shopMoney){
                            shopMoney = new ShopMoney()
                                    .setBeforeChange(BigDecimal.ZERO)
                                    .setAfterChange(BigDecimal.ZERO);
                        }
                        shopMoneyMapper.insert(new ShopMoney()
                                .setOrgCode(appOrder.getOrgCode())
                                .setIncomeType(2)
                                .setMoneyType(2)
                                .setOrderCode(appOrder.getOrderCode())
                                .setBeforeChange(shopMoney.getAfterChange())
                                .setAfterChange(shopMoney.getAfterChange().add(appOrder.getPrice()))
                                .setMoneyChange(appOrder.getPrice())
                                .setChangeInfo(1)
                                .setCreateTime(new Date()));

                    }
                }
                result.put("code", "SUCCESS");
                result.put("message", "OK");
                result.put("orderCode", orderCode);
                return result;
            } catch (Exception e) {
                log.error("微信支付回调异常：" + e.getMessage());
                result.put("code", "FAIL");
                result.put("message", "失败");
                return result;
            }finally {
                lock.unlock();
            }
        }else {
            result.put("code", "FAIL");
            result.put("message", "失败");
            return result;
        }
    }

    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 void addProfitSharingInfos(AppOrder appOrder) {
        List<AppOrderProInfo> orderProInfoList = appOrderProInfoMapper.selectList(Wrappers.lambdaQuery(AppOrderProInfo.class).eq(AppOrderProInfo::getOrderId, appOrder.getId()).eq(AppOrderProInfo::getType, CommonConstant.ORDER_PRO_INFO_TYPE_6));
        BigDecimal insurePrice = BigDecimal.ZERO;
        if (CollUtil.isNotEmpty(orderProInfoList)) {
            BigDecimal reduce = orderProInfoList.stream().map(AppOrderProInfo::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
            insurePrice = insurePrice.add(reduce);
        }
        log.info("------------------------------------------------保险金额：{}", insurePrice);
        //创建预分账详情
        String orgCode = appOrder.getOrgCode();
        SysDepart depart = sysDepartMapper.selectOne(Wrappers.lambdaQuery(SysDepart.class).eq(SysDepart::getOrgCode, orgCode).last("limit 1"));
        String deptId = depart.getId();
        if(depart.getSystemType() == 2){
            deptId = depart.getParentId();
        }
        //平台(不进行分账)
        if (depart.getSystemType() != 0) {
            SeparateAccounts separateAccounts = separateAccountsMapper.selectOne(Wrappers.lambdaQuery(SeparateAccounts.class).eq(SeparateAccounts::getDeptId, deptId));
            //获取分账比例
            BigDecimal PT = separateAccounts.getPtSeparateAccounts();
            BigDecimal SH = separateAccounts.getShSeparateAccounts();
            BigDecimal MD = separateAccounts.getMdSeparateAccounts();
            //分账金额(支付金额-保险金额)
            BigDecimal price = appOrder.getPrice().subtract(insurePrice);
            //微信手续费,不足1分按1分算(当计算值小于0.01时强制提升至0.01)
//            BigDecimal FEE = calculate(price, new BigDecimal("0.006"));

//            price = price.subtract(FEE).subtract(insurePrice);
            price = price.subtract(insurePrice);
            log.info("------------------------------------------------分账金额：{}", price);

            //商户（分账给平台）
            if (depart.getSystemType() == 1) {
                BigDecimal[] allocate = RatiosUtil.allocate(price, new BigDecimal[]{SH, PT});
                //商户所得金额
                AppProfitSharingInfo SHAppProfitSharingInfo = new AppProfitSharingInfo();
                SHAppProfitSharingInfo.setOrderId(appOrder.getId());
                SHAppProfitSharingInfo.setOrgCode(orgCode);
                SHAppProfitSharingInfo.setMchId(depart.getMchId());
                SHAppProfitSharingInfo.setMchName(depart.getMchName());
                SHAppProfitSharingInfo.setType(1);
                SHAppProfitSharingInfo.setRatio(SH);
                SHAppProfitSharingInfo.setPreAmount(RatiosUtil.amount_fee(allocate[0]));
                SHAppProfitSharingInfo.setCumulative(addProfitSharingInfos(SHAppProfitSharingInfo.getOrgCode()));
                appProfitSharingInfoMapper.insert(SHAppProfitSharingInfo);

                //平台所得金额（金额*比例-微信手续费）
                Integer procedureFee = RatiosUtil.amount_fee(allocate[2].add(insurePrice));
                log.info("------------------------------------------------平台所得金额：{},{}", allocate[2], procedureFee);
                AppProfitSharingInfo PTAppProfitSharingInfo = getPtAppProfitSharingInfo(appOrder, PT, procedureFee, insurePrice);
                if (allocate[2] != null && ((allocate[2].add(insurePrice)).compareTo(BigDecimal.ZERO) == 0)) {
                    PTAppProfitSharingInfo.setAmount(RatiosUtil.amount_fee(BigDecimal.ZERO));
                    PTAppProfitSharingInfo.setDescription("分账金额为0,请自行处理");
                }
                PTAppProfitSharingInfo.setCumulative(addProfitSharingInfos(PTAppProfitSharingInfo.getOrgCode()));
                appProfitSharingInfoMapper.insert(PTAppProfitSharingInfo);
            }
            //门店（分账给平台及商户）
            if (depart.getSystemType() == 2) {
                BigDecimal[] allocate = RatiosUtil.allocate(price, MD, SH, PT);
                //门店所得金额
                AppProfitSharingInfo MDAppProfitSharingInfo = new AppProfitSharingInfo();
                MDAppProfitSharingInfo.setOrderId(appOrder.getId());
                MDAppProfitSharingInfo.setOrgCode(orgCode);
                MDAppProfitSharingInfo.setMchId(depart.getMchId());
                MDAppProfitSharingInfo.setMchName(depart.getMchName());
                MDAppProfitSharingInfo.setType(1);
                MDAppProfitSharingInfo.setRatio(MD);
                MDAppProfitSharingInfo.setPreAmount(RatiosUtil.amount_fee(allocate[0]));
                log.info("------------------------------------------------门店所得金额：{}", allocate[0]);
                MDAppProfitSharingInfo.setCumulative(addProfitSharingInfos(MDAppProfitSharingInfo.getOrgCode()));
                appProfitSharingInfoMapper.insert(MDAppProfitSharingInfo);
                //商户所得金额
                SysDepart pdept =
                        sysDepartMapper.selectOne(Wrappers.lambdaQuery(SysDepart.class).eq(SysDepart::getId, depart.getParentId()).last("limit 1"));
                AppProfitSharingInfo SHAppProfitSharingInfo = new AppProfitSharingInfo();
                SHAppProfitSharingInfo.setOrderId(appOrder.getId());
                SHAppProfitSharingInfo.setOrgCode(pdept.getOrgCode());
                SHAppProfitSharingInfo.setMchId(pdept.getMchId());
                SHAppProfitSharingInfo.setMchName(pdept.getMchName());
                SHAppProfitSharingInfo.setType(2);
                SHAppProfitSharingInfo.setRatio(SH);
                SHAppProfitSharingInfo.setPreAmount(RatiosUtil.amount_fee(allocate[1]));
                log.info("------------------------------------------------商户所得金额：{}", allocate[1]);
                if (allocate[1] != null && allocate[1].compareTo(BigDecimal.ZERO) == 0) {
                    SHAppProfitSharingInfo.setAmount(RatiosUtil.amount_fee(BigDecimal.ZERO));
                    SHAppProfitSharingInfo.setDescription("分账金额为0,请自行处理");
                }
                SHAppProfitSharingInfo.setCumulative(addProfitSharingInfos(SHAppProfitSharingInfo.getOrgCode()));
                appProfitSharingInfoMapper.insert(SHAppProfitSharingInfo);

                //平台所得金额（金额*比例-微信手续费）
                Integer procedureFee = RatiosUtil.amount_fee(allocate[2].add(insurePrice));
                log.info("------------------------------------------------平台所得金额：{},{}", allocate[2], procedureFee);
                AppProfitSharingInfo PTAppProfitSharingInfo = getPtAppProfitSharingInfo(appOrder, PT, procedureFee, insurePrice);
                if (allocate[2] != null && ((allocate[2].add(insurePrice)).compareTo(BigDecimal.ZERO) == 0)) {
                    PTAppProfitSharingInfo.setAmount(RatiosUtil.amount_fee(BigDecimal.ZERO));
                    PTAppProfitSharingInfo.setDescription("分账金额为0,请自行处理");
                }
                PTAppProfitSharingInfo.setCumulative(addProfitSharingInfos(PTAppProfitSharingInfo.getOrgCode()));
                appProfitSharingInfoMapper.insert(PTAppProfitSharingInfo);
            }
        }
    }

    /**
     * <p>添加累计分账</p>
     * @author SheepHy
     *
     */
    public int addProfitSharingInfos(String orgCode) {
        List<AppProfitSharingInfo> success = appProfitSharingInfoMapper.selectList(Wrappers.<AppProfitSharingInfo>lambdaQuery()
                .eq(AppProfitSharingInfo::getOrgCode, orgCode)
                .eq(AppProfitSharingInfo::getStatus, "SUCCESS"));
        int cumulativeSum = 0;
        for (AppProfitSharingInfo item : success) {
            cumulativeSum = cumulativeSum + item.getPreAmount();
        }
        return cumulativeSum;
    }

    @NotNull
    private static AppProfitSharingInfo getPtAppProfitSharingInfo(AppOrder appOrder, BigDecimal PT, Integer procedureFee, BigDecimal insurePrice) {
        AppProfitSharingInfo PTAppProfitSharingInfo = new AppProfitSharingInfo();
        PTAppProfitSharingInfo.setOrderId(appOrder.getId());
        PTAppProfitSharingInfo.setOrgCode(WechatConstants.SUB_ORG_CODE);
        PTAppProfitSharingInfo.setMchId(WechatConstants.WECHAT_SUB_MCH_ID);
        PTAppProfitSharingInfo.setMchName(WechatConstants.WECHAT_SUB_MCH_NAME);
        PTAppProfitSharingInfo.setType(2);
        PTAppProfitSharingInfo.setRatio(PT);
        PTAppProfitSharingInfo.setInsureAmount(RatiosUtil.amount_fee(insurePrice));
        PTAppProfitSharingInfo.setPreAmount(procedureFee);
        return PTAppProfitSharingInfo;
    }

    /**
     * 通过商户订单号查询订单在微信侧支付状态
     *
     * @param out_trade_no 发起支付时创建的商户订单号
     * @return null代表查询失败 SUCCESS-成功 USERPAYING和ACCEPT为中间态 其他为支付失败
     */
    public JSONObject orderQueryByOutTradeNo(String out_trade_no, String subMchId) {
        String url = WechatUrlConstants.PAY_V3_QUERY_OUT;
        url = url.replace("{out_trade_no}", WXPayUtility.urlEncode(out_trade_no));
        Map<String, Object> args = new HashMap<>();
        args.put("sp_mchid", WechatConstants.WECHAT_SP_MCH_ID);
        args.put("sub_mchid", subMchId);
        url = url + "?" + WXPayUtility.urlEncode(args);
        JSONObject res = wechatPayV3Utils.sendGet(url);
        return res;
    }

    /**
     * 申请退款
     *
     * @param appOrder
     * @param refundAmount
     * @param reason
     */
    public void refundOrder(AppOrder appOrder, List<AppOrderProInfo> appOrderProInfoList, BigDecimal refundAmount, String reason,Integer type) {

        log.info("进入退款接口------>");
        log.info("执行操作的 原支付交易对应的商户订单号：{}", appOrder.getOrderCode());

        SysDepart depart = sysDepartMapper.selectOne(Wrappers.lambdaQuery(SysDepart.class).eq(SysDepart::getOrgCode, appOrder.getOrgCode()).last("limit 1"));

        //退款单号
        String out_refund_no = generateOrderNumber(1);
        // 创建退款订单
        AppOrderRefundsInfo appOrderRefundsInfo = new AppOrderRefundsInfo();
        if (type == 1 || type == 3){
            appOrderRefundsInfo.setOrderId(appOrder.getId());
            //项目只有单商品退款
            appOrderRefundsInfo.setOrderProInfoId(appOrderProInfoList.get(0).getId());
            appOrderRefundsInfo.setOrderCode(appOrder.getOrderCode());
            appOrderRefundsInfo.setOutRefundNo(out_refund_no);
            appOrderRefundsInfo.setTransactionId(appOrder.getTransactionId());
            appOrderRefundsInfo.setReason(reason);
            appOrderRefundsInfo.setAmount(refundAmount);
            appOrderRefundsInfo.setType(type);
            appOrderRefundsInfo.setCreateTime(new Date());
        }
        if (type == 2){
            appOrderRefundsInfo.setOrderId(appOrder.getId());
            //项目只有单商品退款
            appOrderRefundsInfo.setOrderCode(appOrder.getOrderCode());
            appOrderRefundsInfo.setOutRefundNo(out_refund_no);
            appOrderRefundsInfo.setTransactionId(appOrder.getTransactionId());
            appOrderRefundsInfo.setReason(reason);
            appOrderRefundsInfo.setAmount(refundAmount);
            appOrderRefundsInfo.setType(type);
            appOrderRefundsInfo.setCreateTime(new Date());
        }

        JSONObject params = new JSONObject();
        params.put("sub_mchid", depart.getMchId());
        params.put("out_trade_no", appOrder.getOrderCode());//商户订单号
        params.put("out_refund_no", out_refund_no);//商户退款单号
        params.put("reason", reason);//退款原因
        params.put("notify_url", WechatUrlConstants.PAY_V3_REFUND_NOTIFY);//退款通知

        JSONObject amount = new JSONObject();
        amount.put("refund", RatiosUtil.amount_fee(refundAmount));//退款金额
        amount.put("currency", "CNY");
        amount.put("total", RatiosUtil.amount_fee(appOrder.getPrice()));//原订单金额
        params.put("amount", amount);
        // 执行请求POST 请求发送到微信退款接口
        JSONObject res = wechatPayV3Utils.sendPost(WechatUrlConstants.PAY_V3_REFUND, params);

        log.info("最终拿到的微信支付通知数据：" + res);

        final String status = res.getString("status");
        switch (status) {
            case "SUCCESS":
                log.info("订单：{},退款成功！原因：{}", appOrder.getOrderCode(), reason);
                //修改订单状态
                appOrder.setAfterSaleStatus(CommonConstant.NUMBER_1);
                appOrder.setRefundType(CommonConstant.NUMBER_2);
                appOrderMapper.updateById(appOrder);
                if (ObjectUtil.isNotEmpty(appOrderProInfoList)){
                    for (AppOrderProInfo appOrderProInfo : appOrderProInfoList) {
                        appOrderProInfo.setOrderStatus(CommonConstant.ORDER_STATUS_6);
                        appOrderProInfo.setAfterSaleStatus(CommonConstant.NUMBER_2);
                        appOrderProInfoMapper.updateById(appOrderProInfo);
                    }
                }
                break;
            case "CLOSED":
                log.info("退款关闭");
                break;
            case "PROCESSING":
                log.info("退款处理中");
                //修改订单状态
                appOrder.setAfterSaleStatus(CommonConstant.NUMBER_1);
                appOrder.setRefundType(CommonConstant.NUMBER_2);
                appOrderMapper.updateById(appOrder);
                if (ObjectUtil.isNotEmpty(appOrderProInfoList)){
                    for (AppOrderProInfo appOrderProInfo : appOrderProInfoList) {
                        appOrderProInfo.setOrderStatus(CommonConstant.ORDER_STATUS_5);
                        appOrderProInfo.setAfterSaleStatus(CommonConstant.NUMBER_1);
                        appOrderProInfoMapper.updateById(appOrderProInfo);
                    }
                    List<AppOrderProInfo> orderProInfoList =
                            appOrderProInfoMapper.selectList(Wrappers.<AppOrderProInfo>lambdaQuery().eq(AppOrderProInfo::getOrderId, appOrder.getId()));
                    boolean isAllRefund = true;
                    for (AppOrderProInfo appOrderProInfo : orderProInfoList) {
                        if (appOrderProInfo.getAfterSaleStatus() != 1) {
                            isAllRefund = false;
                            break;
                        }
                    }
                    if (isAllRefund) {
                        log.info("修改订单：{},支付状态为退款中", appOrder.getOrderCode());
                        appOrder.setOrderStatus(CommonConstant.ORDER_STATUS_5);
                        appOrderMapper.updateById(appOrder);
                    }
                }
                break;
            case "ABNORMAL":
                log.info("订单：{},退款异常", appOrder.getOrderCode());
                break;
        }
        appOrderRefundsInfo.setRefundId(res.getString("refund_id"));
        appOrderRefundsInfo.setNotifyRequest(res.toString());
        appOrderRefundsInfo.setTransactionId(res.getString("transaction_id"));
        appOrderRefundsInfo.setAcceptedTime(new Date());
        appOrderRefundsInfoMapper.insert(appOrderRefundsInfo);
    }

    /**
     * @return String 订单号
     * @Author SheepHy
     * @Description 订单编号生成逻辑
     * @Date 17:18 2025/7/15
     * @params 类型：0-（D:订单） 1-（T:退单） 2-（B:保单）
     **/
    private String generateOrderNumber(int type) {
        String format = DateUtil.format(new Date(), "yyyyMMddHHmmss");
        int nextInt = ThreadLocalRandom.current().nextInt(1000, 10000);

        if (type == 0) {
            return "D" + format + nextInt;
        } else {
            return "T" + format + nextInt;
        }
    }

    public Map<String, Object> refundOrderNotify(String jsonData) throws IOException, GeneralSecurityException {
        //转为map格式
        Map jsonMap = JSONObject.parseObject(jsonData, Map.class);

        //退款成功后返回一个加密字段resource,以下为解密
        //解密需要从resource参数中，获取到ciphertext，nonce，associated_data这三个参数进行解密
        String resource = JSONObject.toJSONString(jsonMap.get("resource"));
        JSONObject object = JSONObject.parseObject(resource);

        String ciphertext = String.valueOf(object.get("ciphertext"));
        String nonce = String.valueOf(object.get("nonce"));
        String associated_data = String.valueOf(object.get("associated_data"));

        String resultStr = decryptToString(associated_data.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
        Map<String, String> reqInfo = JSONObject.parseObject(resultStr, Map.class);

        log.info("微信返回的退款通知数据：{}", reqInfo);

        String refund_status = reqInfo.get("refund_status");//退款状态
        String out_trade_no = reqInfo.get("out_trade_no"); //订单号

        Map<String, Object> parm = new HashMap<>();
        if (!StringUtils.isEmpty(refund_status) && "SUCCESS".equals(refund_status)) {

            List<AppOrderProInfo> appOrderProInfoList = new ArrayList<>();

            //查询订单
            AppOrder order = appOrderMapper.selectOne(Wrappers.<AppOrder>lambdaQuery().eq(AppOrder::getOrderCode, out_trade_no).last("limit 1"));
            if (ObjectUtil.isNotEmpty(order)) {
                if (order.getOrderStatus() == 0) {
                    order.setOrderStatus(CommonConstant.ORDER_STATUS_1);
                    order.setPayStatus(CommonConstant.ORDER_STATUS_1);
                    order.setPayTime(new Date());
                    order.setPayType(CommonConstant.STATUS_0_INT);
                    order.setCallbackStatus(CommonConstant.STATUS_1_INT);
                    appOrderMapper.updateById(order);
                    List<AppOrderProInfo> proInfoList = appOrderProInfoMapper.selectList(Wrappers.<AppOrderProInfo>lambdaQuery().eq(AppOrderProInfo::getOrderId, order.getId()));
                    if (ObjectUtil.isNotEmpty(proInfoList)) {
                        for (AppOrderProInfo appOrderProInfo : proInfoList) {
                            if (appOrderProInfo.getOrderStatus() == 5) {
                                appOrderProInfo.setOrderStatus(CommonConstant.ORDER_STATUS_6);
                                appOrderProInfoMapper.updateById(appOrderProInfo);
                                appOrderProInfoList.add(appOrderProInfo);
                            }
                        }
                    }
                }
            }

            for (AppOrderProInfo appOrderProInfo : appOrderProInfoList) {
                // 创建退款订单
                AppOrderRefundsInfo appOrderRefundsInfo = appOrderRefundsInfoMapper.selectOne(Wrappers.lambdaQuery(AppOrderRefundsInfo.class)
                        .eq(AppOrderRefundsInfo::getOrderId, order.getId())
                        .eq(AppOrderRefundsInfo::getOrderProInfoId, appOrderProInfo.getId())
                );

                if (ObjectUtil.isNotEmpty(appOrderRefundsInfo)) {
                    //        appOrderRefundsInfo.setRefundId();
                    appOrderRefundsInfo.setSuccessTime(new Date());
//        appOrderRefundsInfo.setNotifyRequest();
                    appOrderRefundsInfoMapper.updateById(appOrderRefundsInfo);
                }
            }
            parm.put("code", "SUCCESS");
            parm.put("message", "成功");
        } else {
            parm.put("code", "FAIL");
            parm.put("message", "失败");
            throw new RuntimeException("退款失败");
        }
        return parm;  //返回给前端的参数
    }

    private ReceiptPaymentDetailsInfoVo getChangeMoney(ReceiptPaymentDetailsInfoVo receiptPaymentDetailsInfoVo, String orgCode, String deptId, Integer deptType, BigDecimal changeMoney) {
        receiptPaymentDetailsInfoVo.setDeptId(deptId);
        receiptPaymentDetailsInfoVo.setDeptType(deptType);
        receiptPaymentDetailsInfoVo.setOrgCode(orgCode);
        receiptPaymentDetailsInfoVo.setChangeMoney(changeMoney);
        return receiptPaymentDetailsInfoVo;
    }

    private BigDecimal getBigDecimal(BigDecimal bigDecimal1 ,BigDecimal bigDecimal2 ){
        if (bigDecimal2.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("扣款金额必须大于0");
        }

        if (bigDecimal1.compareTo(bigDecimal2) < 0) {
            throw new IllegalArgumentException("余额不足");
        }

        return bigDecimal1.subtract(bigDecimal2);
    }

    //退款回调  解密数据
    public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext) throws GeneralSecurityException, IOException {
        try {
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            // 这里的apiV3key是你的商户ApiV3密钥
            SecretKeySpec key = new SecretKeySpec(WechatConstants.WECHAT_MCH_SECRET_V3.getBytes(), "AES");
            GCMParameterSpec spec = new GCMParameterSpec(128, nonce);//规定为128
            cipher.init(Cipher.DECRYPT_MODE, key, spec);
            cipher.updateAAD(associatedData);
            return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), StandardCharsets.UTF_8);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new IllegalStateException(e);
        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
            throw new IllegalArgumentException(e);
        }
    }
}
