package shop.alien.store.strategy.payment.impl;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import shop.alien.entity.result.R;
import shop.alien.entity.store.RefundRecord;
import shop.alien.store.service.RefundRecordService;
import shop.alien.store.strategy.payment.PaymentStrategy;
import shop.alien.store.util.WXPayUtility;
import shop.alien.util.common.UniqueRandomNumGenerator;
import shop.alien.util.common.constant.PaymentEnum;
import shop.alien.util.system.OSUtil;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 微信支付策略
 *
 * @author lyx
 * @date 2025/11/20
 */

@Slf4j
@Component
@RequiredArgsConstructor
public class WeChatPaymentStrategyImpl implements PaymentStrategy {

    private final RefundRecordService refundRecordService;

    @Value("${payment.wechatPay.host}")
    private String wechatPayApiHost;

    @Value("${payment.wechatPay.prePayPath}")
    private String prePayPath;

    @Value("${payment.wechatPay.searchOrderByTransactionIdPath}")
    private String searchOrderByTransactionIdPath;

    @Value("${payment.wechatPay.searchOrderByOutTradeNoPath}")
    private String searchOrderByOutTradeNoPath;

    @Value("${payment.wechatPay.refundPath}")
    private String refundPath;

    /**
     * 微信支付应用id
     */
    @Value("${payment.wechatPay.business.appId}")
    private String appId;

    /**
     * 微信支付商户id
     */
    @Value("${payment.wechatPay.business.mchId}")
    private String mchId;

    /**
     * 微信支付商户私钥路径
     */
    @Value("${payment.wechatPay.business.win.privateKeyPath}")
    private String privateWinKeyPath;

    /**
     * 微信支付商户私钥路径（Linux环境）
     */
    @Value("${payment.wechatPay.business.linux.privateKeyPath}")
    private String privateLinuxKeyPath;

    /**
     * 微信支付公钥路径
     */
    @Value("${payment.wechatPay.business.win.wechatPayPublicKeyFilePath}")
    private String wechatWinPayPublicKeyFilePath;

    /**
     * 微信支付公钥路径（Linux环境）
     */
    @Value("${payment.wechatPay.business.linux.wechatPayPublicKeyFilePath}")
    private String wechatLinuxPayPublicKeyFilePath;

    /**
     * 微信支付商户证书序列号
     */
    @Value("${payment.wechatPay.business.merchantSerialNumber}")
    private String merchantSerialNumber;

    /**
     * 微信支付API V3密钥
     */
    @Value("${payment.wechatPay.business.apiV3key}")
    private String apiV3key;

    /**
     * 微信支付公钥id
     */
    @Value("${payment.wechatPay.business.wechatPayPublicKeyId}")
    private String wechatPayPublicKeyId;

    @Value("${payment.wechatPay.business.prePayNotifyUrl}")
    private String prePayNotifyUrl;

    @Value("${payment.wechatPay.business.refundNotifyUrl}")
    private String refundNotifyUrl;

    private PrivateKey privateKey;
    private PublicKey wechatPayPublicKey;

    private static String POSTMETHOD = "POST";
    private static String GETMETHOD = "GET";

    @PostConstruct
    public void setWeChatPaymentConfig() {
        String privateKeyPath;
        String wechatPayPublicKeyFilePath;
        if ("windows".equals(OSUtil.getOsName())) {
            privateKeyPath = privateWinKeyPath;
            wechatPayPublicKeyFilePath = wechatWinPayPublicKeyFilePath;
        } else {
            privateKeyPath = privateLinuxKeyPath;
            wechatPayPublicKeyFilePath = wechatLinuxPayPublicKeyFilePath;
        }
        this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyPath);
        this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
    }

    @Override
    public R createPrePayOrder(String price, String subject) throws Exception {
        log.info("创建微信预支付订单，价格：{}，描述：{}", price, subject);
        // 参数验证
        if (price == null || price.trim().isEmpty()) {
            return R.fail("价格不能为空");
        }
        if (subject == null || subject.trim().isEmpty()) {
            return R.fail("订单描述不能为空");
        }
        try {
            BigDecimal amount = new BigDecimal(price);
            if (amount.compareTo(BigDecimal.ZERO) <= 0) {
                return R.fail("价格必须大于0");
            }
        } catch (NumberFormatException e) {
            return R.fail("价格格式不正确");
        }

        CommonPrepayRequest request = new CommonPrepayRequest();
        request.appid = appId;
        request.mchid = mchId;
        request.description = subject;
        request.outTradeNo = UniqueRandomNumGenerator.generateUniqueCode(19);

//        request.timeExpire = "2018-06-08T10:34:56+08:00"; 超时支付不传默认7天
//        request.attach = "自定义数据说明";
        // 目前没用，但是必填
        request.notifyUrl = prePayNotifyUrl;
//        request.goodsTag = "WXG";
//        request.supportFapiao = false;
        request.amount = new CommonAmountInfo();
        request.amount.total = new BigDecimal(price).multiply(new BigDecimal(100)).longValue();
        request.amount.currency = "CNY";
        /* 【优惠功能】 优惠功能
        request.detail = new CouponInfo();
        request.detail.costPrice = 608800L;
        request.detail.invoiceId = "微信123";
        request.detail.goodsDetail = new ArrayList<>();
        {
            GoodsDetail goodsDetailItem = new GoodsDetail();
            goodsDetailItem.merchantGoodsId = "1246464644";
            goodsDetailItem.wechatpayGoodsId = "1001";
            goodsDetailItem.goodsName = "iPhoneX 256G";
            goodsDetailItem.quantity = 1L;
            goodsDetailItem.unitPrice = 528800L;
            request.detail.goodsDetail.add(goodsDetailItem);
        };*/
        /* 【场景信息】 场景信息
        request.sceneInfo = new CommonSceneInfo();
        request.sceneInfo.payerClientIp = "14.23.150.211";
        request.sceneInfo.deviceId = "013467007045764";
        request.sceneInfo.storeInfo = new StoreInfo();
        request.sceneInfo.storeInfo.id = "0001";
        request.sceneInfo.storeInfo.name = "腾讯大厦分店";
        request.sceneInfo.storeInfo.areaCode = "440305";
        request.sceneInfo.storeInfo.address = "广东省深圳市南山区科技中一道10000号";*/
        /* 【结算信息】 结算信息
        request.settleInfo = new SettleInfo();
        request.settleInfo.profitSharing = false;*/
        try {
            DirectAPIv3AppPrepayResponse response = this.prePayOrderRun(request);
            log.info("微信预支付订单创建成功，预支付ID：{}", response.prepayId);
            Map<String,String> result = new HashMap<>();
            result.put("prepayId", response.prepayId);
            result.put("appId", appId);
            result.put("mchId", mchId);
            result.put("orderNo", request.outTradeNo);
            // 生成sign
            long timestamp = System.currentTimeMillis() / 1000; // 时间戳
            String nonce = WXPayUtility.createNonce(32); // 随机字符串
            String prepayId = response.prepayId;
            String message = String.format("%s\n%s\n%s\n%s\n", appId, timestamp, nonce, prepayId);
//            String sign = WXPayUtility.sign(message, sha256withRSA, privateKey);
            Signature sign = Signature.getInstance("SHA256withRSA");
            sign.initSign(privateKey);
            sign.update(message.getBytes(StandardCharsets.UTF_8));
            result.put("sign", Base64.getEncoder().encodeToString(sign.sign()));
            result.put("timestamp", String.valueOf(timestamp));
            result.put("nonce", nonce);
            return R.data(result);
        } catch (WXPayUtility.ApiException e) {
            log.error("微信支付预支付失败，状态码：{}，错误信息：{}", e.getErrorCode(), e.getMessage());
            return R.fail(e.getMessage());
        }
    }

    @Override
    public R createPreAliPayOrder(String orderId, String amount, String subject, String smid) throws Exception {
        return null;
    }


    @Override
    public R handleNotify(String notifyData) throws Exception {
        /**
         * 目前没用，先写着
         */
        return null;
    }

    @Override
    public R searchOrderByOutTradeNoPath(String transactionId) throws Exception {
        log.info("查询微信支付订单状态，交易订单号：{}", transactionId);
        QueryByWxTradeNoRequest request = new QueryByWxTradeNoRequest();
        request.transactionId = transactionId;
        request.mchid = mchId;
        try {
            DirectAPIv3QueryResponse response = searchOrderRun(request);
            return R.data(response);
        } catch (WXPayUtility.ApiException e) {
            log.error("查询微信支付订单状态失败，状态码：{}，错误信息：{}", e.getErrorCode(), e.getMessage());
            return R.fail(e.getMessage());
        }
    }

    @Override
    public String handleRefund(Map<String,String> params) throws Exception {

        CreateRequest request = new CreateRequest();
        // 微信支付订单号和商户订单号必须二选一，不能同时为空，查询的时候使用的是商户订单号
        //request.transactionId = "1217752501201407033233368018";
        request.outTradeNo = params.get("outTradeNo");
        // 退款订单号
        request.outRefundNo = UniqueRandomNumGenerator.generateUniqueCode(19);
        // 退款原因
        request.reason = params.get("reason");
        // 退款回调通知地址
        request.notifyUrl = refundNotifyUrl;
        // 退款资金来源选填
        //request.fundsAccount = ReqFundsAccount.AVAILABLE;
        // 金额信息
        request.amount = new AmountReq();
        request.amount.refund = new BigDecimal(params.get("refundAmount")).longValue();
        // 退款出资账户及金额 目前不需要，需要的时候再看
        /*
        request.amount.from = new ArrayList<>();
        {
            FundsFromItem fromItem = new FundsFromItem();
            fromItem.account = Account.AVAILABLE;
            fromItem.amount = 444L;
            request.amount.from.add(fromItem);
        };*/
        // 订单总金额
        request.amount.total = new BigDecimal(params.get("totalAmount")).longValue();
        // 退款币种 目前默认人民币 CNY
        request.amount.currency = "CNY";
        // 退款商品信息 目前不需要，需要的时候再看
        /*
        request.goodsDetail = new ArrayList<>();
        {
            GoodsDetail goodsDetailItem = new GoodsDetail();
            goodsDetailItem.merchantGoodsId = "1217752501201407033233368018";
            goodsDetailItem.wechatpayGoodsId = "1001";
            goodsDetailItem.goodsName = "iPhone6s 16G";
            goodsDetailItem.unitPrice = 528800L;
            goodsDetailItem.refundAmount = 528800L;
            goodsDetailItem.refundQuantity = 1L;
            request.goodsDetail.add(goodsDetailItem);
        };*/
        // 记录退款请求信息
        log.info("开始处理微信支付退款，商户订单号：{}，商户退款单号：{}，退款金额：{}分，订单总金额：{}分，退款原因：{}",
                request.outTradeNo, request.outRefundNo, request.amount.refund, request.amount.total, request.reason);
        String refundResult = "";
        try {
            Refund response = refundRun(request);
            // 退款状态
            String status = response.status != null ? response.status.name() : "UNKNOWN";
            if ("SUCCESS".equals(status) || "PROCESSING".equals(status)) {
                // refund_id 申请退款受理成功时，该笔退款单在微信支付侧生成的唯一标识。
                String refundId = response.refundId;
                // 商户申请退款时传的商户系统内部退款单号。
                String outRefundNo = response.outRefundNo != null ? response.outRefundNo : request.outRefundNo;
                // 微信支付订单号
                String transactionId = response.transactionId;

                // 退款金额信息
                String refundAmount = response.amount != null && response.amount.refund != null
                        ? String.valueOf(response.amount.refund) : String.valueOf(request.amount.refund);
                String totalAmount = response.amount != null && response.amount.total != null
                        ? String.valueOf(response.amount.total) : String.valueOf(request.amount.total);
                // 退款成功时间
                String successTime = response.successTime;
                // 退款创建时间
                String createTime = response.createTime;
                // 退款渠道
                String channel = response.channel != null ? response.channel.name() : "UNKNOWN";

                // 记录退款成功详细信息
                log.info("微信支付退款成功 - 商户订单号：{}，微信支付订单号：{}，商户退款单号：{}，微信退款单号：{}，" +
                                "退款状态：{}，退款金额：{}分，订单总金额：{}分，退款渠道：{}，创建时间：{}，成功时间：{}",
                        request.outTradeNo, transactionId, outRefundNo, refundId, status, refundAmount,
                        totalAmount, channel, createTime, successTime != null ? successTime : "未完成");

                // 保存到通用退款记录表
                try {
                    RefundRecord refundRecord = buildRefundRecordFromWeChatResponse(response, request, params);
                    if (refundRecord != null) {
                        // 检查是否已存在，避免重复插入
                        long count = refundRecordService.lambdaQuery()
                                .eq(RefundRecord::getOutRefundNo, refundRecord.getOutRefundNo())
                                .count();
                        if (count == 0) {
                            refundRecordService.save(refundRecord);
                            log.info("微信支付退款记录已保存到RefundRecord表，商户退款单号：{}", refundRecord.getOutRefundNo());
                        } else {
                            log.info("微信支付退款记录已存在，跳过插入，商户退款单号：{}", refundRecord.getOutRefundNo());
                        }
                    }
                } catch (Exception e) {
                    log.error("保存微信支付退款记录到RefundRecord表失败", e);
                    // 不抛出异常，避免影响原有逻辑
                }

                refundResult = "调用成功";
                return refundResult;
            } else {
                log.error("微信支付退款失败 - 商户订单号：{}，商户退款单号：{}，退款金额：{}分，订单总金额：{}分，" +
                                "退款状态：{}",
                        request.outTradeNo, request.outRefundNo, request.amount.refund,
                        request.amount.total, status);
                
                // 保存失败记录到通用退款记录表
                try {
                    RefundRecord refundRecord = buildRefundRecordFromWeChatError(response, request, params, status);
                    if (refundRecord != null) {
                        // 检查是否已存在，避免重复插入
                        long count = refundRecordService.lambdaQuery()
                                .eq(RefundRecord::getOutRefundNo, refundRecord.getOutRefundNo())
                                .count();
                        if (count == 0) {
                            refundRecordService.save(refundRecord);
                            log.info("微信支付退款失败记录已保存到RefundRecord表，商户退款单号：{}", refundRecord.getOutRefundNo());
                        } else {
                            log.info("微信支付退款失败记录已存在，跳过插入，商户退款单号：{}", refundRecord.getOutRefundNo());
                        }
                    }
                } catch (Exception e) {
                    log.error("保存微信支付退款失败记录到RefundRecord表失败", e);
                }
                
                return "退款失败";
            }
        }
        catch (Exception e) {
            // 记录其他异常
            log.error("微信支付退款异常 - 商户订单号：{}，商户退款单号：{}，退款金额：{}分，订单总金额：{}分，" +
                    "退款原因：{}，异常信息：{}",
                    request.outTradeNo, request.outRefundNo, request.amount.refund, 
                    request.amount.total, request.reason, e.getMessage(), e);
            
            // 保存异常记录到通用退款记录表
            try {
                RefundRecord refundRecord = buildRefundRecordFromWeChatException(request, params, e);
                if (refundRecord != null) {
                    // 检查是否已存在，避免重复插入
                    long count = refundRecordService.lambdaQuery()
                            .eq(RefundRecord::getOutRefundNo, refundRecord.getOutRefundNo())
                            .count();
                    if (count == 0) {
                        refundRecordService.save(refundRecord);
                        log.info("微信支付退款异常记录已保存到RefundRecord表，商户退款单号：{}", refundRecord.getOutRefundNo());
                    } else {
                        log.info("微信支付退款异常记录已存在，跳过插入，商户退款单号：{}", refundRecord.getOutRefundNo());
                    }
                }
            } catch (Exception ex) {
                log.error("保存微信支付退款异常记录到RefundRecord表失败", ex);
            }
            
            refundResult = "退款处理异常：" + e.getMessage();
            return refundResult;
        }
    }

    @Override
    public R searchRefundRecordByOutRefundNo(String outRefundNo) throws Exception {
        return null;
    }


    @Override
    public String getType() {
        return PaymentEnum.WECHAT_PAY.getType();
    }


    public DirectAPIv3AppPrepayResponse prePayOrderRun(CommonPrepayRequest request) {
        String uri = prePayPath;
        String reqBody = WXPayUtility.toJson(request);

        Request.Builder reqBuilder = new Request.Builder().url(wechatPayApiHost + uri);
        reqBuilder.addHeader("Accept", "application/json");
        reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
        reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchId, merchantSerialNumber, privateKey, POSTMETHOD, uri, reqBody));
        reqBuilder.addHeader("Content-Type", "application/json");
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
        reqBuilder.method(POSTMETHOD, requestBody);
        Request httpRequest = reqBuilder.build();

        // 发送HTTP请求
        OkHttpClient client = new OkHttpClient.Builder().build();
        try (Response httpResponse = client.newCall(httpRequest).execute()) {
            String respBody = WXPayUtility.extractBody(httpResponse);
            if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
                // 2XX 成功，验证应答签名
                WXPayUtility.validateResponse(wechatPayPublicKeyId, wechatPayPublicKey,
                        httpResponse.headers(), respBody);

                // 从HTTP应答报文构建返回数据
                return WXPayUtility.fromJson(respBody, DirectAPIv3AppPrepayResponse.class);
            } else {
                throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
            }
        } catch (IOException e) {
            throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
        }
    }

    public DirectAPIv3QueryResponse searchOrderRun(QueryByWxTradeNoRequest request) {
        String uri = searchOrderByOutTradeNoPath;
        uri = uri.replace("{out_trade_no}", WXPayUtility.urlEncode(request.transactionId));
        Map<String, Object> args = new HashMap<>();
        args.put("mchid", mchId);
        String queryString = WXPayUtility.urlEncode(args);
        if (!queryString.isEmpty()) {
            uri = uri + "?" + queryString;
        }

        Request.Builder reqBuilder = new Request.Builder().url(wechatPayApiHost + uri);
        reqBuilder.addHeader("Accept", "application/json");
        reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
        reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchId, merchantSerialNumber, privateKey, GETMETHOD, uri, null));
        reqBuilder.method(GETMETHOD, null);
        Request httpRequest = reqBuilder.build();

        // 发送HTTP请求
        OkHttpClient client = new OkHttpClient.Builder().build();
        try (Response httpResponse = client.newCall(httpRequest).execute()) {
            String respBody = WXPayUtility.extractBody(httpResponse);
            if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
                // 2XX 成功，验证应答签名
                WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
                        httpResponse.headers(), respBody);

                // 从HTTP应答报文构建返回数据
                return WXPayUtility.fromJson(respBody, DirectAPIv3QueryResponse.class);
            } else {
                throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
            }
        } catch (IOException e) {
            throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
        }
    }

    public Refund refundRun(CreateRequest request) {
        String uri = refundPath;
        String reqBody = WXPayUtility.toJson(request);

        Request.Builder reqBuilder = new Request.Builder().url(wechatPayApiHost + uri);
        reqBuilder.addHeader("Accept", "application/json");
        reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
        reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchId, merchantSerialNumber, privateKey, POSTMETHOD, uri, reqBody));
        reqBuilder.addHeader("Content-Type", "application/json");
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
        reqBuilder.method(POSTMETHOD, requestBody);
        Request httpRequest = reqBuilder.build();

        // 发送HTTP请求
        OkHttpClient client = new OkHttpClient.Builder().build();
        try (Response httpResponse = client.newCall(httpRequest).execute()) {
            String respBody = WXPayUtility.extractBody(httpResponse);
            if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
                // 2XX 成功，验证应答签名
                WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
                        httpResponse.headers(), respBody);

                // 从HTTP应答报文构建返回数据
                return WXPayUtility.fromJson(respBody, Refund.class);
            } else {
                throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
            }
        } catch (IOException e) {
            throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
        }
    }

    /*****************************************下面为支付使用参数*****************************************/
    public static class CommonPrepayRequest {
        @SerializedName("appid")
        public String appid;

        @SerializedName("mchid")
        public String mchid;

        @SerializedName("description")
        public String description;

        @SerializedName("out_trade_no")
        public String outTradeNo;

        @SerializedName("time_expire")
        public String timeExpire;

        @SerializedName("attach")
        public String attach;

        @SerializedName("notify_url")
        public String notifyUrl;

        @SerializedName("goods_tag")
        public String goodsTag;

        @SerializedName("support_fapiao")
        public Boolean supportFapiao;

        @SerializedName("amount")
        public CommonAmountInfo amount;

        @SerializedName("detail")
        public CouponInfo detail;

        @SerializedName("scene_info")
        public CommonSceneInfo sceneInfo;

        @SerializedName("settle_info")
        public SettleInfo settleInfo;
    }

    public static class DirectAPIv3AppPrepayResponse {
        @SerializedName("prepay_id")
        public String prepayId;
    }

    public static class CommonAmountInfo {
        @SerializedName("total")
        public Long total;

        @SerializedName("currency")
        public String currency;
    }

    public static class CouponInfo {
        @SerializedName("cost_price")
        public Long costPrice;

        @SerializedName("invoice_id")
        public String invoiceId;

        @SerializedName("goods_detail")
        public List<GoodsDetail> goodsDetail;
    }

    public static class CommonSceneInfo {
        @SerializedName("payer_client_ip")
        public String payerClientIp;

        @SerializedName("device_id")
        public String deviceId;

        @SerializedName("store_info")
        public StoreInfo storeInfo;
    }

    public static class SettleInfo {
        @SerializedName("profit_sharing")
        public Boolean profitSharing;
    }

    public static class StoreInfo {
        @SerializedName("id")
        public String id;

        @SerializedName("name")
        public String name;

        @SerializedName("area_code")
        public String areaCode;

        @SerializedName("address")
        public String address;
    }

    public static class QueryByWxTradeNoRequest {
        @SerializedName("mchid")
        @Expose(serialize = false)
        public String mchid;

        @SerializedName("transaction_id")
        @Expose(serialize = false)
        public String transactionId;
    }

    public static class DirectAPIv3QueryResponse {
        @SerializedName("appid")
        public String appid;

        @SerializedName("mchid")
        public String mchid;

        @SerializedName("out_trade_no")
        public String outTradeNo;

        @SerializedName("transaction_id")
        public String transactionId;

        @SerializedName("trade_type")
        public String tradeType;

        @SerializedName("trade_state")
        public String tradeState;

        @SerializedName("trade_state_desc")
        public String tradeStateDesc;

        @SerializedName("bank_type")
        public String bankType;

        @SerializedName("attach")
        public String attach;

        @SerializedName("success_time")
        public String successTime;

        @SerializedName("payer")
        public CommRespPayerInfo payer;

        @SerializedName("amount")
        public CommRespAmountInfo amount;

        @SerializedName("scene_info")
        public CommRespSceneInfo sceneInfo;

        @SerializedName("promotion_detail")
        public List<PromotionDetail> promotionDetail;
    }

    public static class CommRespPayerInfo {
        @SerializedName("openid")
        public String openid;
    }

    public static class CommRespAmountInfo {
        @SerializedName("total")
        public Long total;

        @SerializedName("payer_total")
        public Long payerTotal;

        @SerializedName("currency")
        public String currency;

        @SerializedName("payer_currency")
        public String payerCurrency;
    }

    public static class CommRespSceneInfo {
        @SerializedName("device_id")
        public String deviceId;
    }

    public static class PromotionDetail {
        @SerializedName("coupon_id")
        public String couponId;

        @SerializedName("name")
        public String name;

        @SerializedName("scope")
        public String scope;

        @SerializedName("type")
        public String type;

        @SerializedName("amount")
        public Long amount;

        @SerializedName("stock_id")
        public String stockId;

        @SerializedName("wechatpay_contribute")
        public Long wechatpayContribute;

        @SerializedName("merchant_contribute")
        public Long merchantContribute;

        @SerializedName("other_contribute")
        public Long otherContribute;

        @SerializedName("currency")
        public String currency;

        @SerializedName("goods_detail")
        public List<GoodsDetailInPromotion> goodsDetail;
    }

    public static class GoodsDetailInPromotion {
        @SerializedName("goods_id")
        public String goodsId;

        @SerializedName("quantity")
        public Long quantity;

        @SerializedName("unit_price")
        public Long unitPrice;

        @SerializedName("discount_amount")
        public Long discountAmount;

        @SerializedName("goods_remark")
        public String goodsRemark;
    }

    public static class CreateRequest {
        @SerializedName("transaction_id")
        public String transactionId;

        @SerializedName("out_trade_no")
        public String outTradeNo;

        @SerializedName("out_refund_no")
        public String outRefundNo;

        @SerializedName("reason")
        public String reason;

        @SerializedName("notify_url")
        public String notifyUrl;

        @SerializedName("funds_account")
        public ReqFundsAccount fundsAccount;

        @SerializedName("amount")
        public AmountReq amount;

        @SerializedName("goods_detail")
        public List<GoodsDetail> goodsDetail;

    }

    public static class Refund {
        @SerializedName("refund_id")
        public String refundId;

        @SerializedName("out_refund_no")
        public String outRefundNo;

        @SerializedName("transaction_id")
        public String transactionId;

        @SerializedName("out_trade_no")
        public String outTradeNo;

        @SerializedName("channel")
        public Channel channel;

        @SerializedName("user_received_account")
        public String userReceivedAccount;

        @SerializedName("success_time")
        public String successTime;

        @SerializedName("create_time")
        public String createTime;

        @SerializedName("status")
        public Status status;

        @SerializedName("funds_account")
        public FundsAccount fundsAccount;

        @SerializedName("amount")
        public Amount amount;

        @SerializedName("promotion_detail")
        public List<Promotion> promotionDetail;

    }

    public enum ReqFundsAccount {
        @SerializedName("AVAILABLE")
        AVAILABLE,
        @SerializedName("UNSETTLED")
        UNSETTLED
    }

    public static class AmountReq {
        @SerializedName("refund")
        public Long refund;

        @SerializedName("from")
        public List<FundsFromItem> from;

        @SerializedName("total")
        public Long total;

        @SerializedName("currency")
        public String currency;
    }

    public static class GoodsDetail {
        @SerializedName("merchant_goods_id")
        public String merchantGoodsId;

        @SerializedName("wechatpay_goods_id")
        public String wechatpayGoodsId;

        @SerializedName("goods_name")
        public String goodsName;

        @SerializedName("quantity")
        public Long quantity;

        @SerializedName("unit_price")
        public Long unitPrice;

        @SerializedName("refund_amount")
        public Long refundAmount;

        @SerializedName("refund_quantity")
        public Long refundQuantity;
    }

    public enum Channel {
        @SerializedName("ORIGINAL")
        ORIGINAL,
        @SerializedName("BALANCE")
        BALANCE,
        @SerializedName("OTHER_BALANCE")
        OTHER_BALANCE,
        @SerializedName("OTHER_BANKCARD")
        OTHER_BANKCARD
    }

    public enum Status {
        @SerializedName("SUCCESS")
        SUCCESS,
        @SerializedName("CLOSED")
        CLOSED,
        @SerializedName("PROCESSING")
        PROCESSING,
        @SerializedName("ABNORMAL")
        ABNORMAL
    }

    public enum FundsAccount {
        @SerializedName("UNSETTLED")
        UNSETTLED,
        @SerializedName("AVAILABLE")
        AVAILABLE,
        @SerializedName("UNAVAILABLE")
        UNAVAILABLE,
        @SerializedName("OPERATION")
        OPERATION,
        @SerializedName("BASIC")
        BASIC,
        @SerializedName("ECNY_BASIC")
        ECNY_BASIC
    }

    public static class Amount {
        @SerializedName("total")
        public Long total;

        @SerializedName("refund")
        public Long refund;

        @SerializedName("from")
        public List<FundsFromItem> from;

        @SerializedName("payer_total")
        public Long payerTotal;

        @SerializedName("payer_refund")
        public Long payerRefund;

        @SerializedName("settlement_refund")
        public Long settlementRefund;

        @SerializedName("settlement_total")
        public Long settlementTotal;

        @SerializedName("discount_refund")
        public Long discountRefund;

        @SerializedName("currency")
        public String currency;

        @SerializedName("refund_fee")
        public Long refundFee;
    }

    public static class Promotion {
        @SerializedName("promotion_id")
        public String promotionId;

        @SerializedName("scope")
        public PromotionScope scope;

        @SerializedName("type")
        public PromotionType type;

        @SerializedName("amount")
        public Long amount;

        @SerializedName("refund_amount")
        public Long refundAmount;

        @SerializedName("goods_detail")
        public List<GoodsDetail> goodsDetail;
    }

    public static class FundsFromItem {
        @SerializedName("account")
        public Account account;

        @SerializedName("amount")
        public Long amount;
    }

    public enum PromotionScope {
        @SerializedName("GLOBAL")
        GLOBAL,
        @SerializedName("SINGLE")
        SINGLE
    }

    public enum PromotionType {
        @SerializedName("CASH")
        CASH,
        @SerializedName("NOCASH")
        NOCASH
    }

    public enum Account {
        @SerializedName("AVAILABLE")
        AVAILABLE,
        @SerializedName("UNAVAILABLE")
        UNAVAILABLE
    }

    /**
     * 从微信支付退款响应构建RefundRecord对象（成功情况）
     */
    public RefundRecord buildRefundRecordFromWeChatResponse(Refund response, CreateRequest request, Map<String, String> params) {
        try {
            RefundRecord record = new RefundRecord();
            
            // 基本信息
            record.setPayType(PaymentEnum.WECHAT_PAY.getType());
            record.setOutTradeNo(response.outTradeNo != null ? response.outTradeNo : request.outTradeNo);
            record.setTransactionId(response.transactionId);
            record.setOutRefundNo(response.outRefundNo != null ? response.outRefundNo : request.outRefundNo);
            record.setRefundId(response.refundId);
            record.setRefundStatus(response.status != null ? response.status.name() : "UNKNOWN");
            
            // 金额信息（微信返回的是分）
            if (response.amount != null) {
                record.setTotalAmount(response.amount.total);
                record.setRefundAmount(response.amount.refund);
                record.setActualRefundAmount(response.amount.refund); // 微信退款金额就是实际退款金额
                if (response.amount.currency != null) {
                    record.setCurrency(response.amount.currency);
                } else {
                    record.setCurrency("CNY");
                }
            } else {
                record.setTotalAmount(request.amount.total);
                record.setRefundAmount(request.amount.refund);
                record.setActualRefundAmount(request.amount.refund);
                record.setCurrency(request.amount.currency != null ? request.amount.currency : "CNY");
            }
            
            // 退款原因
            record.setRefundReason(request.reason);
            
            // 退款渠道
            if (response.channel != null) {
                record.setRefundChannel(response.channel.name());
            }
            
            // 退款资金来源
            if (response.fundsAccount != null) {
                record.setFundsAccount(response.fundsAccount.name());
            }
            
            // 用户收到退款账户
            record.setUserReceivedAccount(response.userReceivedAccount);
            
            // 退款详情（如果有优惠信息）
            if (response.promotionDetail != null && !response.promotionDetail.isEmpty()) {
                record.setRefundDetail(WXPayUtility.toJson(response.promotionDetail));
            }
            
            // 退款时间（微信返回的是ISO 8601格式字符串，需要转换为Date）
            if (response.createTime != null) {
                Date createTime = parseWeChatTime(response.createTime);
                if (createTime != null) {
                    record.setRefundCreateTime(createTime);
                }
            }
            if (response.successTime != null) {
                Date successTime = parseWeChatTime(response.successTime);
                if (successTime != null) {
                    record.setRefundSuccessTime(successTime);
                }
            }
            
            // 业务信息（从params获取，如果有的话）
            if (params != null) {
                if (params.containsKey("userId")) {
                    try {
                        record.setUserId(Integer.parseInt(params.get("userId")));
                    } catch (NumberFormatException e) {
                        log.warn("解析userId失败: {}", params.get("userId"));
                    }
                }
                if (params.containsKey("orderId")) {
                    record.setOrderId(params.get("orderId"));
                }
                if (params.containsKey("storeId")) {
                    try {
                        record.setStoreId(Integer.parseInt(params.get("storeId")));
                    } catch (NumberFormatException e) {
                        log.warn("解析storeId失败: {}", params.get("storeId"));
                    }
                }
            }
            
            // 响应数据
            record.setResponseData(WXPayUtility.toJson(response));
            
            // 标准字段
            record.setDeleteFlag(0);
            record.setCreatedTime(new Date());
            
            return record;
        } catch (Exception e) {
            log.error("构建RefundRecord对象失败", e);
            return null;
        }
    }

    /**
     * 从微信支付退款错误响应构建RefundRecord对象（失败情况）
     */
    public RefundRecord buildRefundRecordFromWeChatError(Refund response, CreateRequest request, Map<String, String> params, String status) {
        try {
            RefundRecord record = new RefundRecord();
            
            // 基本信息
            record.setPayType(PaymentEnum.WECHAT_PAY.getType());
            record.setOutTradeNo(response.outTradeNo != null ? response.outTradeNo : request.outTradeNo);
            record.setTransactionId(response.transactionId);
            record.setOutRefundNo(response.outRefundNo != null ? response.outRefundNo : request.outRefundNo);
            record.setRefundId(response.refundId);
            record.setRefundStatus(status);
            
            // 金额信息
            if (response.amount != null) {
                record.setTotalAmount(response.amount.total);
                record.setRefundAmount(response.amount.refund);
                record.setCurrency(response.amount.currency != null ? response.amount.currency : "CNY");
            } else {
                record.setTotalAmount(request.amount.total);
                record.setRefundAmount(request.amount.refund);
                record.setCurrency(request.amount.currency != null ? request.amount.currency : "CNY");
            }
            
            // 退款原因
            record.setRefundReason(request.reason);
            
            // 退款时间
            if (response.createTime != null) {
                Date createTime = parseWeChatTime(response.createTime);
                if (createTime != null) {
                    record.setRefundCreateTime(createTime);
                }
            }
            
            // 业务信息
            if (params != null) {
                if (params.containsKey("userId")) {
                    try {
                        record.setUserId(Integer.parseInt(params.get("userId")));
                    } catch (NumberFormatException e) {
                        log.warn("解析userId失败: {}", params.get("userId"));
                    }
                }
                if (params.containsKey("orderId")) {
                    record.setOrderId(params.get("orderId"));
                }
                if (params.containsKey("storeId")) {
                    try {
                        record.setStoreId(Integer.parseInt(params.get("storeId")));
                    } catch (NumberFormatException e) {
                        log.warn("解析storeId失败: {}", params.get("storeId"));
                    }
                }
            }
            
            // 响应数据
            record.setResponseData(WXPayUtility.toJson(response));
            
            // 标准字段
            record.setDeleteFlag(0);
            record.setCreatedTime(new Date());
            
            return record;
        } catch (Exception e) {
            log.error("构建RefundRecord对象失败", e);
            return null;
        }
    }

    /**
     * 从微信支付退款异常构建RefundRecord对象（异常情况）
     */
    public RefundRecord buildRefundRecordFromWeChatException(CreateRequest request, Map<String, String> params, Exception e) {
        try {
            RefundRecord record = new RefundRecord();
            
            // 基本信息
            record.setPayType(PaymentEnum.WECHAT_PAY.getType());
            record.setOutTradeNo(request.outTradeNo);
            record.setOutRefundNo(request.outRefundNo);
            record.setRefundStatus("ABNORMAL");
            
            // 金额信息
            record.setTotalAmount(request.amount.total);
            record.setRefundAmount(request.amount.refund);
            record.setCurrency(request.amount.currency != null ? request.amount.currency : "CNY");
            
            // 退款原因
            record.setRefundReason(request.reason);
            
            // 错误信息
            if (e instanceof WXPayUtility.ApiException) {
                WXPayUtility.ApiException apiException = (WXPayUtility.ApiException) e;
                record.setErrorCode(String.valueOf(apiException.getErrorCode()));
                record.setErrorMsg(apiException.getMessage());
            } else {
                record.setErrorMsg(e.getMessage());
            }
            
            // 业务信息
            if (params != null) {
                if (params.containsKey("userId")) {
                    try {
                        record.setUserId(Integer.parseInt(params.get("userId")));
                    } catch (NumberFormatException ex) {
                        log.warn("解析userId失败: {}", params.get("userId"));
                    }
                }
                if (params.containsKey("orderId")) {
                    record.setOrderId(params.get("orderId"));
                }
                if (params.containsKey("storeId")) {
                    try {
                        record.setStoreId(Integer.parseInt(params.get("storeId")));
                    } catch (NumberFormatException ex) {
                        log.warn("解析storeId失败: {}", params.get("storeId"));
                    }
                }
            }
            
            // 标准字段
            record.setDeleteFlag(0);
            record.setCreatedTime(new Date());
            record.setRefundCreateTime(new Date());
            
            return record;
        } catch (Exception ex) {
            log.error("构建RefundRecord对象失败", ex);
            return null;
        }
    }

    /**
     * 解析微信支付返回的时间字符串（ISO 8601格式）
     * 例如：2018-06-08T10:34:56+08:00
     */
    private Date parseWeChatTime(String timeStr) {
        if (timeStr == null || timeStr.trim().isEmpty()) {
            return null;
        }
        try {
            // 尝试解析ISO 8601格式
            OffsetDateTime dateTime = OffsetDateTime.parse(timeStr, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
            return Date.from(dateTime.toInstant());
        } catch (Exception e) {
            // 如果ISO 8601解析失败，尝试其他格式
            try {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                return sdf.parse(timeStr);
            } catch (ParseException ex) {
                log.warn("解析微信支付时间失败: {}", timeStr, ex);
                return null;
            }
        }
    }
}
