package com.njzscloud.supervisory.wxPay.service.impl;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingRequest;
import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingReturnRequest;
import com.github.binarywang.wxpay.bean.profitsharing.result.ProfitSharingResult;
import com.github.binarywang.wxpay.bean.profitsharing.result.ProfitSharingReturnResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.ProfitSharingService;
import com.njzscloud.common.core.ex.Exceptions;
import com.njzscloud.supervisory.money.contant.MoneyChangeCategory;
import com.njzscloud.supervisory.money.contant.MoneyDetailType;
import com.njzscloud.supervisory.money.contant.PayStatus;
import com.njzscloud.supervisory.money.pojo.entity.MoneyAccountEntity;
import com.njzscloud.supervisory.money.pojo.entity.MoneyChangeDetailEntity;
import com.njzscloud.supervisory.money.service.MoneyAccountService;
import com.njzscloud.supervisory.money.service.MoneyChangeDetailService;
import com.njzscloud.supervisory.order.contant.SettlementWay;
import com.njzscloud.supervisory.order.pojo.result.PaymentContextResult;
import com.njzscloud.supervisory.wxPay.config.WxPayProperties;
import com.njzscloud.supervisory.wxPay.dto.RefundRequestDto;
import com.njzscloud.supervisory.wxPay.service.PaymentService;
import com.njzscloud.supervisory.wxPay.service.WeChatPayService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 退款服务实现类
 *
 * @author ljw
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PaymentServiceImpl implements PaymentService {

    // 分账比例：千分之一
    private static final int PROFIT_SHARING_RATIO = 1;
    private static final int PROFIT_SHARING_BASE = 1000;

    private final WxPayProperties properties;
    private final WeChatPayService wechatPayService;
    private final ProfitSharingService profitSharingService;
    private final MoneyAccountService moneyAccountService;
    private final MoneyChangeDetailService moneyChangeDetailService;

    /**
     * 执行分账（千分之一给特约商户）
     */
    @Override
    public void profitSharing(Long orderId, String transactionId, BigDecimal totalAmount) throws WxPayException {
        log.info("========== 开始执行分账 ==========");
        log.info("分账参数 - 订单ID：{}，交易ID：{}，总金额：{}元", orderId, transactionId, totalAmount);

        // 计算分账金额：总金额 * (1/1000)
        BigDecimal sharingAmount = totalAmount.multiply(BigDecimal.valueOf(PROFIT_SHARING_RATIO))
                .divide(BigDecimal.valueOf(PROFIT_SHARING_BASE), 2, RoundingMode.DOWN);

        log.info("分账金额计算 - 总金额：{}元，分账比例：{}/{}，分账金额：{}元",
                totalAmount, PROFIT_SHARING_RATIO, PROFIT_SHARING_BASE, sharingAmount);

        if (sharingAmount.compareTo(BigDecimal.ZERO) <= 0) {
            log.info("分账金额为0，跳过分账，订单ID：{}", orderId);
            log.info("========== 分账跳过结束 ==========");
            return;
        }

        log.info("分账商户信息 - 特约商户：{}，收款商户：{}，分账商户：{}", properties.getMchId(), properties.getSubMchId(),
                properties.getReceiverMchId());

        // 构建分账请求
        ProfitSharingRequest request = new ProfitSharingRequest();
        request.setTransactionId(transactionId);
        String outOrderNo = "PS_" + orderId + "_" + System.currentTimeMillis();
        request.setOutOrderNo(outOrderNo);

        log.info("分账请求构建 - 分账单号：{}，交易ID：{}", outOrderNo, transactionId);

        // 创建分账接收方JSON字符串
        // 仅分账给 receiver-mch-id（1649452354），比例为千分之一；收款方为 subMchId（不作为接收方再次出现）
        StringBuilder receiversJson = new StringBuilder("[");
        int receiverMoney = sharingAmount.multiply(BigDecimal.valueOf(100)).intValue();
        receiversJson.append("{\"type\":\"MERCHANT_ID\",\"account\":\"").append(properties.getReceiverMchId()).append("\",")
                .append("\"amount\":").append(receiverMoney)
                .append(",\"description\":\"系统分账108\"}");
        receiversJson.append("]");
        request.setReceivers(receiversJson.toString());
        // 指定分账发生在收款子商户下
        request.setSubMchId(properties.getSubMchId());

        // 计算子商户留存金额（用于日志）
        BigDecimal subMerchantAmount = totalAmount.subtract(sharingAmount);

        log.info("分账接收方配置 - 特约商户分账：{}元({}分)，子商户（留存）：{}元",
                sharingAmount, receiverMoney,
                subMerchantAmount);
        log.info("分账接收方JSON：{}", receiversJson);

        try {
            // 调用分账接口
            log.info("调用微信分账接口...");
            ProfitSharingResult result = profitSharingService.profitSharing(request);

            log.info("分账成功！订单ID：{}，总金额：{}元", orderId, totalAmount);
            log.info("分账详情 - 特约商户分账：{}元，子商户分账：{}元", sharingAmount, subMerchantAmount);
            log.info("分账结果 - 分账单号：{}，微信返回状态：{}", result.getOutOrderNo(), result);

            // 将分账单号保存到资金明细的扩展信息中
            try {
                MoneyChangeDetailEntity payDetail = moneyChangeDetailService.getByOrderIdAndType(orderId, MoneyDetailType.WX);
                if (payDetail != null && payDetail.getExtendInfo() != null) {
                    // 解析现有的extendInfo，添加分账单号
                    JSONObject extendJson = JSON.parseObject(payDetail.getExtendInfo());
                    extendJson.put("profitSharingOrderNo", outOrderNo);
                    payDetail.setExtendInfo(extendJson.toJSONString());
                    moneyChangeDetailService.updateById(payDetail);
                    log.info("分账单号已保存到资金明细，订单ID：{}，分账单号：{}", orderId, outOrderNo);
                }
            } catch (Exception e) {
                log.warn("保存分账单号到资金明细失败，订单ID：{}，分账单号：{}，错误：{}", orderId, outOrderNo, e.getMessage());
            }

            log.info("========== 分账执行成功 ==========");
        } catch (WxPayException e) {
            log.error("分账执行失败！订单ID：{}，错误信息：{}", orderId, e.getMessage(), e);
            log.error("失败详情 - 交易ID：{}，分账单号：{}，金额：{}元", transactionId, outOrderNo, totalAmount);
            throw e;
        }
    }

    /**
     * 申请退款
     */
    @Override
    public void refund(RefundRequestDto refundRequest, PaymentContextResult ctx, Boolean isChange) {
        try {
            log.info("开始处理退款申请，订单ID：{}，支付方式：{}，是否改价：{}",
                    refundRequest.getOrderId(), ctx.getOiPayWay(), isChange);
            // 根据支付方式处理退款
            if (SettlementWay.CASH.getVal().equals(ctx.getOiPayWay())) {

                // 微信退款 生成退款单号
                String orderSn = IdUtil.getSnowflake(0, 0).nextIdStr();
                // 微信退全款
                int money = ctx.getSettleMoney().multiply(new BigDecimal("100")).intValue();
                // 如果是改价，不一定退全额
                if (isChange) {
                    money = refundRequest.getRefundAmount().multiply(new BigDecimal("100")).intValue();
                }
                String notifyUrl = properties.getRefundNotifyUrl();
                log.info("发起微信退款，订单ID：{}，商户订单号：{}，退款单号：{}，退款金额：{}分，退款回调地址：{}",
                        refundRequest.getOrderId(), refundRequest.getOutTradeNo(), orderSn, money, notifyUrl);
                String refundId = wechatPayService.refund(refundRequest.getOutTradeNo(), orderSn, money, money, notifyUrl);
                log.info("微信退款申请成功，退款ID：{}", refundId);

                // 新建退款资金明细
                MoneyChangeDetailEntity newRefundDetail = new MoneyChangeDetailEntity()
                        .setType(MoneyDetailType.WX)
                        .setStatus(PayStatus.REFUNDING)
                        .setOrderId(refundRequest.getOrderId())
                        .setUserId(ctx.getDriverUserId())
                        // 退款为正数
                        .setDelta(refundRequest.getRefundAmount())
                        .setMoneyChangeCategory(MoneyChangeCategory.DingDanTuiKuan)
                        .setMemo("微信退款订单：" + orderSn);
                moneyChangeDetailService.save(newRefundDetail);

            } else if (SettlementWay.MONTH.getVal().equals(ctx.getOiPayWay()) || SettlementWay.BALANCE.getVal().equals(ctx.getOiPayWay())) {
                // 公司退款
                processCompanyRefund(refundRequest, ctx);
            }
        } catch (Exception e) {
            log.error("退款处理异常，订单ID：{}", refundRequest.getOrderId(), e);
        }
    }

    /**
     * 处理公司退款
     */
    private void processCompanyRefund(RefundRequestDto refundRequest, PaymentContextResult ctx) {

        // 恢复公司账户余额
        restoreCompanyBalance(ctx, refundRequest.getRefundAmount(), refundRequest.getOrderId(), refundRequest.getReason());

        log.info("公司退款成功，订单ID：{}，退款金额：{}", refundRequest.getOrderId(), refundRequest.getRefundAmount());
    }

    /**
     * 恢复公司账户余额
     */
    private void restoreCompanyBalance(PaymentContextResult ctx, BigDecimal refundAmount, Long orderId, String reason) {
        if (ctx.getCompanyUserId() == null || ctx.getCompanyAccountId() == null) {
            throw Exceptions.clierr("公司账户信息不完整，无法退款");
        }

        // 恢复公司账户余额
        BigDecimal oldBalance = ctx.getCompanyBalance();
        BigDecimal newBalance = oldBalance.add(refundAmount);
        MoneyAccountEntity companyAccount = new MoneyAccountEntity()
                .setId(ctx.getCompanyAccountId())
                .setMoney(newBalance);
        moneyAccountService.updateById(companyAccount);

        // 记录资金明细（这里需要实现资金明细记录功能）
        MoneyChangeDetailEntity changeDetail = new MoneyChangeDetailEntity()
                .setCompanyId(ctx.getTransCompanyId())
                .setOrderId(orderId)
                .setMoneyAccountId(companyAccount.getId())
                .setOldMoney(oldBalance)
                // 扣减为负数
                .setDelta(refundAmount)
                .setNewMoney(newBalance)
                .setMoneyChangeCategory(MoneyChangeCategory.DingDanTuiKuan)
                .setMemo(reason);

        moneyChangeDetailService.save(changeDetail);
        log.info("公司账户余额恢复成功，账户ID：{}，恢复金额：{}", ctx.getCompanyAccountId(), refundAmount);
    }

    /**
     * 分账回退
     */
    @Override
    public void profitSharingReturn(Long orderId, BigDecimal refundAmount) throws WxPayException {
        log.info("========== 开始执行分账回退 ==========");
        log.info("分账回退参数 - 订单ID：{}，退款金额：{}元", orderId, refundAmount);

        // 计算需要回退的分账金额：退款金额 * (1/1000)
        BigDecimal returnAmount = refundAmount.multiply(BigDecimal.valueOf(PROFIT_SHARING_RATIO))
                .divide(BigDecimal.valueOf(PROFIT_SHARING_BASE), 2, RoundingMode.DOWN);

        log.info("分账回退金额计算 - 退款金额：{}元，回退比例：{}/{}，回退金额：{}元",
                refundAmount, PROFIT_SHARING_RATIO, PROFIT_SHARING_BASE, returnAmount);

        if (returnAmount.compareTo(BigDecimal.ZERO) <= 0) {
            log.info("分账回退金额为0，跳过分账回退，订单ID：{}", orderId);
            log.info("========== 分账回退跳过结束 ==========");
            return;
        }

        log.info("分账回退商户信息 - 回退商户：{}，回退类型：MERCHANT_ID", properties.getReceiverMchId());

        // 构建分账回退请求
        ProfitSharingReturnRequest request = new ProfitSharingReturnRequest();
        String outReturnNo = "PSR_" + orderId + "_" + System.currentTimeMillis();
        request.setOutReturnNo(outReturnNo);
        request.setReturnAccountType("MERCHANT_ID");
        // 从分账商户回退
        request.setReturnAccount(properties.getReceiverMchId());
        request.setDescription("用户退款108");
        // 设置回退金额（分）
        int returnMoney = returnAmount.multiply(BigDecimal.valueOf(100)).intValue();
        request.setReturnAmount(returnMoney);
        // 指定回退操作针对的子商户（收款方）
        request.setSubMchId(properties.getSubMchId());

        // 从资金明细中获取原始分账单号
        String outOrderNo = null;
        try {
            MoneyChangeDetailEntity payDetail = moneyChangeDetailService.getByOrderIdAndType(orderId, MoneyDetailType.WX);
            if (payDetail != null && payDetail.getExtendInfo() != null) {
                JSONObject extendJson = JSON.parseObject(payDetail.getExtendInfo());
                outOrderNo = extendJson.getString("profitSharingOrderNo");
                log.info("从资金明细中获取到分账单号：{}，订单ID：{}", outOrderNo, orderId);
            }
        } catch (Exception e) {
            log.warn("从资金明细中获取分账单号失败，订单ID：{}，错误：{}", orderId, e.getMessage());
        }

        // 如果没有找到分账单号，使用模糊匹配（不推荐，可能会导致回退失败）
        if (outOrderNo == null) {
            outOrderNo = "PS_" + orderId + "_*";
            log.warn("未找到分账单号，使用模糊匹配：{}，订单ID：{}", outOrderNo, orderId);
        }

        request.setOutOrderNo(outOrderNo);

        log.info("分账回退请求构建 - 回退单号：{}，原始分账单号：{}，回退金额：{}元({}分)",
                outReturnNo, outOrderNo, returnAmount, returnMoney);

        try {
            // 调用分账回退接口
            log.info("调用微信分账回退接口...");
            ProfitSharingReturnResult result = profitSharingService.profitSharingReturn(request);

            log.info("分账回退成功！订单ID：{}，退款金额：{}元", orderId, refundAmount);
            log.info("分账回退详情 - 回退金额：{}元，从商户：{}回退", returnAmount, properties.getMchId());
            log.info("分账回退结果 - 回退单号：{}，微信返回状态：{}", result.getOutReturnNo(), result);
            log.info("========== 分账回退执行成功 ==========");
        } catch (WxPayException e) {
            log.error("分账回退执行失败！订单ID：{}，错误信息：{}", orderId, e.getMessage(), e);
            log.error("失败详情 - 退款金额：{}元，回退金额：{}元，回退单号：{}", refundAmount, returnAmount, outReturnNo);
            throw e;
        }
    }

    /**
     * 重新分账剩余金额（用于部分退款后）
     */
    @Override
    public void reProfitSharing(Long orderId, String transactionId, BigDecimal remainingAmount) throws WxPayException {
        log.info("========== 开始执行重新分账 ==========");
        log.info("重新分账参数 - 订单ID：{}，交易ID：{}，剩余金额：{}元", orderId, transactionId, remainingAmount);

        // 计算新的分账金额：剩余金额 * (1/1000)
        BigDecimal sharingAmount = remainingAmount.multiply(BigDecimal.valueOf(PROFIT_SHARING_RATIO))
                .divide(BigDecimal.valueOf(PROFIT_SHARING_BASE), 2, RoundingMode.DOWN);

        log.info("重新分账金额计算 - 剩余金额：{}元，分账比例：{}/{}，分账金额：{}元",
                remainingAmount, PROFIT_SHARING_RATIO, PROFIT_SHARING_BASE, sharingAmount);

        if (sharingAmount.compareTo(BigDecimal.ZERO) <= 0) {
            log.info("重新分账金额为0，跳过重新分账，订单ID：{}", orderId);
            log.info("========== 重新分账跳过结束 ==========");
            return;
        }

        log.info("重新分账商户信息 - 分账商户：{}，收款商户：{}", properties.getReceiverMchId(), properties.getSubMchId());

        // 构建重新分账请求
        ProfitSharingRequest request = new ProfitSharingRequest();
        request.setTransactionId(transactionId);
        String outOrderNo = "RE_PS_" + orderId + "_" + System.currentTimeMillis();
        request.setOutOrderNo(outOrderNo);

        log.info("重新分账请求构建 - 分账单号：{}，交易ID：{}", outOrderNo, transactionId);

        // 创建分账接收方JSON字符串（仅给分账接收方分一部分，收款子商户保持留存）
        StringBuilder receiversJson = new StringBuilder("[");
        int receiverMoney = sharingAmount.multiply(BigDecimal.valueOf(100)).intValue();
        receiversJson.append("{\"type\":\"MERCHANT_ID\",\"account\":\"").append(properties.getReceiverMchId()).append("\",")
                .append("\"amount\":").append(receiverMoney)
                .append(",\"description\":\"部分退款后重新分账-分账商户\"}");
        receiversJson.append("]");
        request.setReceivers(receiversJson.toString());
        // 指定分账发生在收款子商户下
        request.setSubMchId(properties.getSubMchId());

        BigDecimal subMerchantAmount = remainingAmount.subtract(sharingAmount);
        log.info("重新分账接收方配置 - 特约商户分账：{}元({}分)，子商户（留存）：{}元",
                sharingAmount, receiverMoney,
                subMerchantAmount);
        log.info("重新分账接收方JSON：{}", receiversJson);

        try {
            // 调用分账接口
            log.info("调用微信重新分账接口...");
            ProfitSharingResult result = profitSharingService.profitSharing(request);

            log.info("重新分账成功！订单ID：{}，剩余金额：{}元", orderId, remainingAmount);
            log.info("重新分账详情 - 特约商户分账：{}元，子商户分账：{}元", sharingAmount, subMerchantAmount);
            log.info("重新分账结果 - 分账单号：{}，微信返回状态：{}", result.getOutOrderNo(), result);
            log.info("========== 重新分账执行成功 ==========");
        } catch (WxPayException e) {
            log.error("重新分账执行失败！订单ID：{}，错误信息：{}", orderId, e.getMessage(), e);
            log.error("失败详情 - 交易ID：{}，分账单号：{}，剩余金额：{}元", transactionId, outOrderNo, remainingAmount);
            throw e;
        }
    }

    /**
     * 异步执行分账（支付成功后，支持重试）
     * 延迟10秒执行，避免订单处理中导致的分账失败
     */
    @Override
    @Async
    public void profitSharingAsync(Long orderId, String transactionId, BigDecimal totalAmount) {
        log.info("异步分账任务启动，订单ID：{}，交易ID：{}，总金额：{}元", orderId, transactionId, totalAmount);

        try {
            // 延迟10秒执行分账，避免 ORDER_NOT_READY 错误
            Thread.sleep(10000);
            log.info("延迟10秒后开始执行分账，订单ID：{}", orderId);

            // 调用同步分账方法
            profitSharing(orderId, transactionId, totalAmount);
            log.info("异步分账执行成功，订单ID：{}", orderId);

        } catch (InterruptedException e) {
            log.error("异步分账延迟被中断，订单ID：{}，错误：{}", orderId, e.getMessage());
            Thread.currentThread().interrupt(); // 恢复中断状态
        } catch (Exception e) {
            log.error("异步分账执行失败，订单ID：{}，交易ID：{}，总金额：{}元，错误：{}",
                    orderId, transactionId, totalAmount, e.getMessage(), e);
            // 异步执行失败不抛出异常，避免影响主流程
        }
    }


}
