package com.liquidnet.service.goblin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.dto.vo.*;
import com.liquidnet.service.goblin.entity.GoblinSqbPerformanceGoods;
import com.liquidnet.service.goblin.mapper.GoblinSqbPerformanceGoodsMapper;
import com.liquidnet.service.goblin.param.shouqianba.request.*;
import com.liquidnet.service.goblin.param.shouqianba.response.data.*;
import com.liquidnet.service.goblin.service.IGoblinShouQianBaService;
import com.liquidnet.service.goblin.service.IGoblinSqbOrderService;
import com.liquidnet.service.goblin.util.GoblinRedisUtils;
import com.liquidnet.service.goblin.util.GoblinSqbRedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 收钱吧订单服务实现
 */
@Slf4j
@Service
public class GoblinSqbOrderServiceImpl implements IGoblinSqbOrderService {

    @Autowired
    private GoblinSqbRedisUtils goblinSqbRedisUtils;

    @Autowired
    private GoblinRedisUtils goblinRedisUtils;

    @Autowired
    private com.liquidnet.service.goblin.util.GoblinMongoUtils goblinMongoUtils;

    @Autowired
    private com.liquidnet.service.goblin.util.QueueUtils queueUtils;

    @Autowired
    private GoblinSqbPerformanceGoodsMapper goblinSqbPerformanceGoodsMapper;

    @Autowired
    private IGoblinShouQianBaService goblinShouQianBaService;

    private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    // ========== 常量（后期可移至配置文件） ==========
    // TODO: 将以下常量移至 application.yml 配置
    private static final String SQB_APPID            = "test_appid";
    private static final String SQB_MERCHANT_ID       = "todo_merchant_id";
    private static final String SQB_MERCHANT_USER_ID  = "todo_merchant_user_id";
    private static final String SQB_ROLE              = "super_admin";

    // ================================ 创建订单 ================================

    @Override
    public ResponseDto<GoblinSqbOrderCreateVo> createOrder(String userId, String spuId, String skuId,
                                                            Integer quantity, String performancesId) {
        log.info("[收钱吧下单] 开始 userId={}, spuId={}, skuId={}, quantity={}, performancesId={}",
                userId, spuId, skuId, quantity, performancesId);

        // Step 1: 分布式锁防重
        boolean locked = goblinSqbRedisUtils.tryOrderLock(userId, skuId);
        if (!locked) {
            log.warn("[收钱吧下单] 获取防重锁失败，userId={}, skuId={}", userId, skuId);
            return ResponseDto.failure("请勿重复下单");
        }

        try {
            // Step 2: 校验演出-商品关联
            LambdaQueryWrapper<GoblinSqbPerformanceGoods> query = new LambdaQueryWrapper<>();
            query.eq(GoblinSqbPerformanceGoods::getPerformancesId, performancesId)
                    .eq(GoblinSqbPerformanceGoods::getSkuId, skuId)
                    .eq(GoblinSqbPerformanceGoods::getStatus, 1);
            GoblinSqbPerformanceGoods relation = goblinSqbPerformanceGoodsMapper.selectOne(query);
            if (relation == null) {
                log.warn("[收钱吧下单] 演出-商品关联不存在或已禁用，performancesId={}, skuId={}", performancesId, skuId);
                return ResponseDto.failure("商品与演出关联不存在");
            }

            // Step 3: 原子扣减库存
            long remaining = goblinRedisUtils.decrSkuStock(null, skuId, quantity);
            if (remaining < 0) {
                goblinRedisUtils.incrSkuStock(null, skuId, quantity);
                log.warn("[收钱吧下单] 库存不足，skuId={}, quantity={}", skuId, quantity);
                return ResponseDto.failure("库存不足");
            }
            log.info("[收钱吧下单] 扣减库存成功，skuId={}, remaining={}", skuId, remaining);

            // Step 4: 构建收钱吧公共请求参数
            CommonRequest.Seller seller = buildSeller();

            // Step 4.1: createSettlement → 得 checkoutItemsId
            // TODO: 从商品数据中获取价格、图片、标题等信息填充 CheckoutItem
            SettlementCreateRequest settlementReq = new SettlementCreateRequest();
            settlementReq.setAppid(SQB_APPID);
            settlementReq.setSeller(seller);
            CommonRequest.Buyer buyer = new CommonRequest.Buyer();
            buyer.setBuyerId(userId);
            settlementReq.setBuyer(buyer);
            // TODO: settlementReq.setCheckoutItems(...); settlementReq.setAmount(...);

            SettlementCreateData settlementData = goblinShouQianBaService.createSettlement(settlementReq);
            if (settlementData == null) {
                goblinRedisUtils.incrSkuStock(null, skuId, quantity);
                return ResponseDto.failure("创建结算明细失败");
            }
            String checkoutItemsId = settlementData.getCheckoutItemsId();
            log.info("[收钱吧下单] createSettlement 成功，checkoutItemsId={}", checkoutItemsId);

            // Step 4.2: createOrder → 得 sqbOrderSn + sqbOrderSignature + sqbAcquiringSn
            OrderCreateRequest orderReq = new OrderCreateRequest();
            orderReq.setAppid(SQB_APPID);
            orderReq.setSeller(seller);
            orderReq.setCheckoutItemsId(checkoutItemsId);
            orderReq.setBuyer(buyer);
            orderReq.setRequestId(IDGenerator.nextSnowId());
            orderReq.setSubject("收钱吧商品");

            OrderCreateData orderData = goblinShouQianBaService.createOrder(orderReq);
            if (orderData == null) {
                goblinRedisUtils.incrSkuStock(null, skuId, quantity);
                return ResponseDto.failure("创建收钱吧订单失败");
            }
            String sqbOrderSn        = orderData.getOrderSn();
            String sqbOrderSignature  = orderData.getOrderSignature();
            String sqbAcquiringSn    = orderData.getAcquiring() != null ? orderData.getAcquiring().getAcquiringSn() : null;
            log.info("[收钱吧下单] createOrder 成功，sqbOrderSn={}, sqbAcquiringSn={}", sqbOrderSn, sqbAcquiringSn);

            // Step 4.3: queryCashier → 得 selectedSignature + seq
            CashierQueryRequest cashierReq = buildCashierQueryRequest(seller, sqbAcquiringSn, sqbOrderSignature);
            CashierQueryData cashierData = goblinShouQianBaService.queryCashier(cashierReq);
            if (cashierData == null) {
                goblinRedisUtils.incrSkuStock(null, skuId, quantity);
                return ResponseDto.failure("查询收银台失败");
            }
            String selectedSignature = cashierData.getSelectedSignature();
            String seq               = cashierData.getSeq();
            log.info("[收钱吧下单] queryCashier 成功，selectedSignature={}, seq={}", selectedSignature, seq);

            // Step 4.4: createWechatPrepayOrder → 得 paymentVoucher
            CreateWechatPrepayOrderRequest prepayReq = buildWechatPrepayRequest(
                    seller, sqbAcquiringSn, sqbOrderSignature, selectedSignature, seq, cashierData);
            CreateWechatPrepayOrderData prepayData = goblinShouQianBaService.createWechatPrepayOrder(prepayReq);
            if (prepayData == null || prepayData.getPaymentVoucher() == null) {
                goblinRedisUtils.incrSkuStock(null, skuId, quantity);
                return ResponseDto.failure("创建微信预支付失败");
            }
            CreateWechatPrepayOrderData.PaymentVoucher pv = prepayData.getPaymentVoucher();
            log.info("[收钱吧下单] createWechatPrepayOrder 成功，timeStamp={}", pv.getTimeStamp());

            String orderId = IDGenerator.nextSnowId();
            String masterOrderCode = IDGenerator.nextTimeId();
            String orderCode = IDGenerator.nextTimeId();
            String now = LocalDateTime.now().format(DTF);

            // 获取商品和 SKU 信息，供后续订单基础信息拼接使用
            GoblinGoodsInfoVo goodsInfo = goblinMongoUtils.getGoodsInfoVo(spuId);
            GoblinGoodsSkuInfoVo skuInfo = goblinMongoUtils.getGoodsSkuInfoVo(skuId);

            // 1) 构建基础商城订单 VO (GoblinStoreOrderVo)
            GoblinStoreOrderVo storeOrderVo = new GoblinStoreOrderVo();
            storeOrderVo.setMasterOrderCode(masterOrderCode);
            storeOrderVo.setOrderId(orderId);
            storeOrderVo.setStoreId(goodsInfo != null ? goodsInfo.getStoreId() : "SQB_STORE");
            storeOrderVo.setStoreName(goodsInfo != null ? goodsInfo.getStoreName() : "收钱吧商品聚合门店");
            storeOrderVo.setOrderCode(orderCode);
            storeOrderVo.setUserId(userId);
            // 姓名手机号为了兼容留空或占位即可
            storeOrderVo.setUserName("");
            storeOrderVo.setUserMobile("");
            
            java.math.BigDecimal skuPrice = skuInfo != null ? skuInfo.getPrice() : java.math.BigDecimal.ZERO;
            java.math.BigDecimal priceTotal = skuPrice.multiply(new java.math.BigDecimal(quantity));
            storeOrderVo.setPriceTotal(priceTotal);
            storeOrderVo.setPriceActual(priceTotal); // 收钱吧暂无运费及优惠逻辑，实际价格等于总价
            storeOrderVo.setPriceRefund(java.math.BigDecimal.ZERO);
            storeOrderVo.setPriceExpress(java.math.BigDecimal.ZERO);
            storeOrderVo.setPriceCoupon(java.math.BigDecimal.ZERO);
            storeOrderVo.setStorePriceCoupon(java.math.BigDecimal.ZERO);
            storeOrderVo.setPriceVoucher(java.math.BigDecimal.ZERO);
            // 待支付
            storeOrderVo.setStatus(0);
            storeOrderVo.setPayType("SQB_PAY"); // 标识为收钱吧支付类型
            storeOrderVo.setDeviceFrom("shouqianba");
            storeOrderVo.setOrderType(0);
            storeOrderVo.setWriteOffCode("EMPTY");
            storeOrderVo.setPayCountdownMinute(15); 
            storeOrderVo.setCreatedAt(now);

            // 2) 构建基础商城 SKU VO (GoblinOrderSkuVo)
            String orderSkuId = IDGenerator.nextSnowId();
            GoblinOrderSkuVo orderSkuVo = new GoblinOrderSkuVo();
            orderSkuVo.setOrderSkuId(orderSkuId);
            orderSkuVo.setOrderId(orderId);
            orderSkuVo.setSpuId(spuId);
            orderSkuVo.setSpuName(goodsInfo != null ? goodsInfo.getName() : "收钱吧未知商品");
            orderSkuVo.setSkuId(skuId);
            orderSkuVo.setNum(quantity);
            orderSkuVo.setSkuPrice(skuPrice);
            orderSkuVo.setSkuPriceActual(priceTotal); // 按件数总价
            orderSkuVo.setSkuName(skuInfo != null ? skuInfo.getName() : "收钱吧未匹配SKU");
            orderSkuVo.setSkuImage(skuInfo != null ? skuInfo.getSkuPic() : "");
            orderSkuVo.setSkuSpecs("[]");
            orderSkuVo.setPriceVoucher(java.math.BigDecimal.ZERO);
            orderSkuVo.setCreatedAt(now);
            // 特殊标识类型：33
            orderSkuVo.setSkuType(33); 

            // 存入 Redis 并绑定关系
            List<String> orderSkuVoIds = new ArrayList<>();
            orderSkuVoIds.add(orderSkuId);
            storeOrderVo.setOrderSkuVoIds(orderSkuVoIds);
            goblinRedisUtils.setGoblinOrderSku(orderSkuId, orderSkuVo);
            goblinRedisUtils.setGoblinOrder(orderId, storeOrderVo);
            goblinRedisUtils.setMasterCode(masterOrderCode, orderId);

            // 3) 构建收钱吧专属特有字段 (GoblinSqbOrderVo)
            GoblinSqbOrderVo orderVo = new GoblinSqbOrderVo();
            orderVo.setOrderId(orderId);
            orderVo.setUserId(userId);
            orderVo.setPerformancesId(performancesId);
            orderVo.setSpuId(spuId);
            orderVo.setSkuId(skuId);
            orderVo.setQuantity(quantity);
            orderVo.setSqbOrderSn(sqbOrderSn);
            orderVo.setSqbOrderSignature(sqbOrderSignature);
            orderVo.setSqbAcquiringSn(sqbAcquiringSn);
            orderVo.setSqbCheckoutItemsId(checkoutItemsId);
            // 内部状态同步使用
            orderVo.setStatus(0); 
            orderVo.setCreatedAt(now);
            orderVo.setUpdatedAt(now);

            goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
            goblinRedisUtils.addOrderList(userId, orderId);
            log.info("[收钱吧下单] 订单写入 Redis 成功，orderId={}", orderId);

            // Step 6: 写 MongoDB + 发送复用的 SQL MQ
            // 写入 Mongo
            goblinMongoUtils.insertGoblinOrderSkuVo(orderSkuVo);
            goblinMongoUtils.insertGoblinStoreOrderVo(storeOrderVo);
            // 收钱吧扩展暂无需单独写 MongoDB 除非专门需要查询

            // 拼接 SQL 数据并丢队列
            java.util.LinkedList<String> sqls = new java.util.LinkedList<>();
            sqls.add(com.liquidnet.service.base.SqlMapping.get("goblin.order.create.sku_insert"));
            sqls.add(com.liquidnet.service.base.SqlMapping.get("goblin.order.create.order_insert"));

            java.util.LinkedList<Object[]> sqlDataSku = new java.util.LinkedList<>();
            sqlDataSku.add(new Object[]{
                    orderSkuVo.getOrderSkuId(), orderSkuVo.getOrderId(), orderSkuVo.getSpuId(), orderSkuVo.getSpuName(), (goodsInfo != null ? goodsInfo.getCoverPic() : ""),
                    orderSkuVo.getSkuId(), orderSkuVo.getNum(), orderSkuVo.getSkuPrice(), orderSkuVo.getSkuPriceActual(), orderSkuVo.getSkuName(),
                    "", orderSkuVo.getSkuImage(), orderSkuVo.getSkuSpecs(), orderSkuVo.getPriceVoucher(),
                    "", "", "", "", 0, // ERP 等非必要参数直接置空
                    orderSkuVo.getCreatedAt()
            });

            java.util.LinkedList<Object[]> sqlDataOrder = new java.util.LinkedList<>();
            sqlDataOrder.add(new Object[]{
                    storeOrderVo.getMasterOrderCode(), storeOrderVo.getOrderId(), storeOrderVo.getStoreId(), storeOrderVo.getStoreName(), storeOrderVo.getOrderCode(),
                    storeOrderVo.getUserId(), storeOrderVo.getUserName(), storeOrderVo.getUserMobile(), storeOrderVo.getPriceTotal(), storeOrderVo.getPayCode(),
                    storeOrderVo.getPriceActual(), storeOrderVo.getPriceRefund(), storeOrderVo.getPriceExpress(), storeOrderVo.getPriceCoupon(), storeOrderVo.getStorePriceCoupon(),
                    storeOrderVo.getPriceVoucher(), storeOrderVo.getStatus(), storeOrderVo.getUcouponId(), storeOrderVo.getStoreCouponId(), storeOrderVo.getPayType(), storeOrderVo.getDeviceFrom(),
                    storeOrderVo.getSource(), storeOrderVo.getVersion(), storeOrderVo.getIsMember(), storeOrderVo.getOrderType(), storeOrderVo.getWriteOffCode(), storeOrderVo.getPayCountdownMinute(),
                    storeOrderVo.getIpAddress(), storeOrderVo.getMarketId(), storeOrderVo.getMarketType(), storeOrderVo.getCreatedAt(), "", ""
            });

            // 借用 Base 模块中 ConsumerGoblinOrderCPRdsReceiver 这个队列消费类进行写库
            if(queueUtils != null) {
                queueUtils.sendMsgByRedis(com.liquidnet.service.base.constant.MQConst.GoblinQueue.GOBLIN_ORDER_CREATE_PAY.getKey(),
                        com.liquidnet.service.base.SqlMapping.gets(sqls, sqlDataSku, sqlDataOrder));
                // 待支付超时回调等处理也可放入原有股票队列逻辑，暂省略
            }
            log.info("[收钱吧下单] 完成 MongoDB 及 MQ 落库，orderId={}, masterCode={}", orderId, masterOrderCode);

            // Step 7: 释放分布式锁，构建返回
            goblinSqbRedisUtils.releaseOrderLock(userId, skuId);

            GoblinSqbOrderCreateVo createVo = new GoblinSqbOrderCreateVo();
            createVo.setOrderId(orderId);
            createVo.setAcquiringSn(sqbAcquiringSn);
            createVo.setTimeStamp(pv.getTimeStamp());
            createVo.setPackageStr(pv.getPackageStr());
            createVo.setPaySign(pv.getPaySign());
            createVo.setAppId(pv.getAppId());
            createVo.setSignType(pv.getSignType());
            createVo.setNonceStr(pv.getNonceStr());

            log.info("[收钱吧下单] 下单成功，orderId={}", orderId);
            return ResponseDto.success(createVo);

        } catch (Exception e) {
            log.error("[收钱吧下单] 下单异常，userId={}, skuId={}", userId, skuId, e);
            goblinRedisUtils.incrSkuStock(null, skuId, quantity);
            goblinSqbRedisUtils.releaseOrderLock(userId, skuId);
            return ResponseDto.failure("下单失败：" + e.getMessage());
        }
    }

    // ================================ 查询支付状态 ================================

    @Override
    public ResponseDto<Integer> queryPayStatus(String userId, String orderId) {
        log.info("[收钱吧支付状态] 开始查询 userId={}, orderId={}", userId, orderId);

        GoblinSqbOrderVo orderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
        if (orderVo == null) {
            return ResponseDto.failure("订单不存在");
        }
        if (!userId.equals(orderVo.getUserId())) {
            return ResponseDto.failure("无权限访问该订单");
        }

        // 已支付直接返回
        if (Integer.valueOf(1).equals(orderVo.getStatus())) {
            return ResponseDto.success(1);
        }

        // 调用收钱吧查询收单状态
        CommonRequest.Seller seller = buildSeller();
        CashierQueryRequest cashierReq = buildCashierQueryRequest(seller, orderVo.getSqbAcquiringSn(), orderVo.getSqbOrderSignature());
        CashierQueryData cashierData = goblinShouQianBaService.queryCashier(cashierReq);

        if (cashierData == null) {
            log.warn("[收钱吧支付状态] queryCashier 调用失败，orderId={}", orderId);
            return ResponseDto.success(orderVo.getStatus());
        }

        // acquiringState 通过 cashierData.getAmount() > 0 && 收单签名有效来推断 —— 实际以收钱吧文档为准
        // 简化处理：收银台能正常返回且 selectedSignature 非空，视为已支付
        if (cashierData.getSelectedSignature() != null) {
            String now = LocalDateTime.now().format(DTF);
            orderVo.setStatus(1);
            orderVo.setUpdatedAt(now);
            goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);

            syncOrderStatus(orderId, 1);
            log.info("[收钱吧支付状态] 确认支付成功，orderId={}", orderId);
            return ResponseDto.success(1);
        }

        return ResponseDto.success(orderVo.getStatus());
    }

    // ================================ 获取券码 ================================

    @Override
    public ResponseDto<GoblinSqbCouponVo> queryCoupon(String userId, String orderId) {
        log.info("[收钱吧券码] 开始获取 userId={}, orderId={}", userId, orderId);

        GoblinSqbOrderVo orderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
        if (orderVo == null) return ResponseDto.failure("订单不存在");
        if (!userId.equals(orderVo.getUserId())) return ResponseDto.failure("无权限访问该订单");
        if (!Integer.valueOf(1).equals(orderVo.getStatus())) return ResponseDto.failure("订单未支付，无法获取券码");

        // 幂等：已存在则直接返回
        if (orderVo.getCouponQrCode() != null && !orderVo.getCouponQrCode().isEmpty()) {
            GoblinSqbCouponVo couponVo = new GoblinSqbCouponVo();
            couponVo.setCouponSn(orderVo.getCouponSn());
            couponVo.setCouponQrCode(orderVo.getCouponQrCode());
            couponVo.setCouponExpireTime(orderVo.getCouponExpireTime());
            return ResponseDto.success(couponVo);
        }

        // 调用收钱吧查询券码
        CouponQueryRequest req = new CouponQueryRequest();
        req.setAppid(SQB_APPID);
        req.setSeller(buildSeller());
        CouponQueryRequest.OrderInfo orderInfo = new CouponQueryRequest.OrderInfo();
        orderInfo.setSn(orderVo.getSqbOrderSn());
        orderInfo.setSignature(orderVo.getSqbOrderSignature());
        req.setOrderID(orderInfo);

        CouponQueryData couponData = goblinShouQianBaService.queryCoupon(req);
        if (couponData == null) return ResponseDto.failure("获取券码失败");

        // 更新订单 coupon 字段
        String now = LocalDateTime.now().format(DTF);
        orderVo.setCouponSn(couponData.getVoucherNo());
        orderVo.setCouponQrCode(couponData.getUrl());
        orderVo.setCouponExpireTime(couponData.getOperationTime());
        orderVo.setUpdatedAt(now);
        goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
        // 券码信息保存在 Redis，MySQL和MongoDB商城基础模型无此字段，无需同步

        GoblinSqbCouponVo couponVo = new GoblinSqbCouponVo();
        couponVo.setCouponSn(couponData.getVoucherNo());
        couponVo.setCouponQrCode(couponData.getUrl());
        couponVo.setCouponExpireTime(couponData.getOperationTime());

        log.info("[收钱吧券码] 获取成功，orderId={}", orderId);
        return ResponseDto.success(couponVo);
    }

    // ================================ 申请退款 ================================

    @Override
    public ResponseDto<Boolean> refund(String userId, String orderId) {
        log.info("[收钱吧退款] 开始 userId={}, orderId={}", userId, orderId);

        GoblinSqbOrderVo orderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
        if (orderVo == null) return ResponseDto.failure("订单不存在");
        if (!userId.equals(orderVo.getUserId())) return ResponseDto.failure("无权限访问该订单");
        if (!Integer.valueOf(1).equals(orderVo.getStatus())) return ResponseDto.failure("订单状态不可退款");
        if (Integer.valueOf(1).equals(orderVo.getCouponUsedStatus())) return ResponseDto.failure("券码已核销，不可退款");

        // 更新状态为退款中
        String now = LocalDateTime.now().format(DTF);
        orderVo.setStatus(4);
        orderVo.setUpdatedAt(now);
        goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
        syncOrderStatus(orderId, 4);

        try {
            // 调用收钱吧退款
            CouponRefundRequest refundReq = new CouponRefundRequest();
            refundReq.setAppid(SQB_APPID);
            refundReq.setSeller(buildSeller());
            refundReq.setRequestSource("EXTERN");
            refundReq.setRequestId(IDGenerator.nextSnowId());

            CouponRefundRequest.OrderInfo orderInfo = new CouponRefundRequest.OrderInfo();
            orderInfo.setSn(orderVo.getSqbOrderSn());
            orderInfo.setSignature(orderVo.getSqbOrderSignature());
            refundReq.setOrderID(orderInfo);

            CouponRefundRequest.RefundInfo refundInfo = new CouponRefundRequest.RefundInfo();
            // amount 字段待接入实际金额（GoblinSqbOrderVo 需补充 amount）
            refundInfo.setApplyAmount(0L); // TODO: 替换为实际订单金额
            refundInfo.setType((byte) 2); // 2-按金额退款
            refundInfo.setRefundReason("用户申请退款");
            refundReq.setRefundInfo(refundInfo);

            CouponRefundData refundData = goblinShouQianBaService.refundCoupon(refundReq);
            if (refundData == null) {
                // 退款失败，回滚状态
                orderVo.setStatus(1);
                orderVo.setUpdatedAt(LocalDateTime.now().format(DTF));
                goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
                syncOrderStatus(orderId, 1);
                return ResponseDto.failure("退款失败，请稍后重试");
            }

            // 退款成功
            orderVo.setStatus(3);
            orderVo.setUpdatedAt(LocalDateTime.now().format(DTF));
            goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
            goblinRedisUtils.incrSkuStock(null, orderVo.getSkuId(), orderVo.getQuantity());

            syncOrderStatus(orderId, 3);
            log.info("[收钱吧退款] 退款成功，orderId={}", orderId);
            return ResponseDto.success(Boolean.TRUE);

        } catch (Exception e) {
            log.error("[收钱吧退款] 退款异常，orderId={}，回滚 status=1", orderId, e);
            orderVo.setStatus(1);
            orderVo.setUpdatedAt(LocalDateTime.now().format(DTF));
            goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
            syncOrderStatus(orderId, 1);
            return ResponseDto.failure("退款失败：" + e.getMessage());
        }
    }

    // ================================ 同步核销状态 ================================

    @Override
    public ResponseDto<Boolean> syncCouponStatus(String userId, String orderId) {
        log.info("[收钱吧核销同步] 开始 userId={}, orderId={}", userId, orderId);

        GoblinSqbOrderVo orderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
        if (orderVo == null) return ResponseDto.failure("订单不存在");
        if (!userId.equals(orderVo.getUserId())) return ResponseDto.failure("无权限访问该订单");

        CouponStatusSyncRequest req = new CouponStatusSyncRequest();
        req.setAppid(SQB_APPID);
        req.setRedeemSource("EXTERN");
        // TODO: 填充 voucherNos（券号列表）、redeemMerchantId、redeemExternalOrderSn、clientSn、status
        //       需要从 orderVo 中获取 couponSn 和其他必要字段
        if (orderVo.getCouponSn() != null) {
            req.setVoucherNos(java.util.Collections.singletonList(orderVo.getCouponSn()));
        }
        req.setRedeemMerchantId(SQB_MERCHANT_ID);
        req.setRedeemExternalOrderSn(IDGenerator.nextSnowId());
        req.setClientSn("terminal_001"); // TODO: 配置终端号
        req.setStatus((byte) 1); // 1-已核销

        boolean couponUsed = goblinShouQianBaService.syncCouponStatus(req);
        if (couponUsed) {
            String now = LocalDateTime.now().format(DTF);
            orderVo.setStatus(2);
            orderVo.setCouponUsedStatus(1);
            orderVo.setUpdatedAt(now);
            goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
            syncOrderStatus(orderId, 2);
            log.info("[收钱吧核销同步] 核销成功，orderId={}", orderId);
        }
        return ResponseDto.success(couponUsed);
    }

    // ================================ 回调处理 ================================

    @Override
    public ResponseDto<String> handlePayCallback(Map<String, Object> params) {
        log.info("[收钱吧支付回调] 收到回调参数: {}", params);
        String orderId = getOrderIdFromParams(params);
        if (orderId == null) return ResponseDto.failure("缺少订单标识");

        GoblinSqbOrderVo orderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
        if (orderVo == null) return ResponseDto.failure("订单不存在");
        if (Integer.valueOf(1).equals(orderVo.getStatus())) return ResponseDto.success("success"); // 幂等

        String now = LocalDateTime.now().format(DTF);
        orderVo.setStatus(1);
        orderVo.setUpdatedAt(now);
        goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
        syncOrderStatus(orderId, 1);
        log.info("[收钱吧支付回调] 更新支付状态成功，orderId={}", orderId);
        return ResponseDto.success("success");
    }

    @Override
    public ResponseDto<String> handleRefundCallback(Map<String, Object> params) {
        log.info("[收钱吧退款回调] 收到回调参数: {}", params);
        String orderId = getOrderIdFromParams(params);
        if (orderId == null) return ResponseDto.failure("缺少订单标识");

        GoblinSqbOrderVo orderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
        if (orderVo == null) return ResponseDto.failure("订单不存在");
        if (Integer.valueOf(3).equals(orderVo.getStatus())) return ResponseDto.success("success"); // 幂等

        String now = LocalDateTime.now().format(DTF);
        orderVo.setStatus(3);
        orderVo.setUpdatedAt(now);
        goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
        goblinRedisUtils.incrSkuStock(null, orderVo.getSkuId(), orderVo.getQuantity());
        syncOrderStatus(orderId, 3);
        log.info("[收钱吧退款回调] 更新退款状态成功，orderId={}", orderId);
        return ResponseDto.success("success");
    }

    @Override
    public ResponseDto<String> handleCouponCallback(Map<String, Object> params) {
        log.info("[收钱吧券状态回调] 收到回调参数: {}", params);
        String orderId = getOrderIdFromParams(params);
        if (orderId == null) return ResponseDto.failure("缺少订单标识");

        GoblinSqbOrderVo orderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
        if (orderVo == null) return ResponseDto.failure("订单不存在");
        if (Integer.valueOf(2).equals(orderVo.getStatus())) return ResponseDto.success("success"); // 幂等

        String now = LocalDateTime.now().format(DTF);
        orderVo.setStatus(2);
        orderVo.setCouponUsedStatus(1);
        orderVo.setUpdatedAt(now);
        goblinSqbRedisUtils.setSqbOrder(orderId, orderVo);
        syncOrderStatus(orderId, 2);
        log.info("[收钱吧券状态回调] 核销状态更新成功，orderId={}", orderId);
        return ResponseDto.success("success");
    }

    // ================================ 自动退款（定时任务） ================================

    @Override
    public ResponseDto<String> autoRefundByPerformance(String performancesId) {
        log.info("[收钱吧自动退款] 开始处理演出 performancesId={}", performancesId);

        // 查询该演出下 status=1（已支付）的订单（MySQL）
        // TODO: 通过 GoblinSqbOrderMapper 查询（需注入后解注释）
        // LambdaQueryWrapper<GoblinSqbOrder> query = new LambdaQueryWrapper<>();
        // query.eq(GoblinSqbOrder::getPerformancesId, performancesId).eq(GoblinSqbOrder::getStatus, 1);
        // List<GoblinSqbOrder> orders = goblinSqbOrderMapper.selectList(query);

        int successCount = 0;
        int failCount = 0;

        // TODO: 取消注释并接入 GoblinSqbOrderMapper 后启用
        // for (GoblinSqbOrder order : orders) {
        //     try {
        //         ResponseDto<Boolean> result = refund(order.getUserId(), order.getOrderId());
        //         if (result != null && result.isSuccess()) {
        //             successCount++;
        //         } else {
        //             log.warn("[收钱吧自动退款] 订单退款失败 orderId={}", order.getOrderId());
        //             failCount++;
        //         }
        //     } catch (Exception e) {
        //         log.error("[收钱吧自动退款] 订单退款异常 orderId={}", order.getOrderId(), e);
        //         failCount++;
        //     }
        // }

        String summary = String.format("演出 %s 自动退款完成：成功 %d 笔，失败 %d 笔", performancesId, successCount, failCount);
        log.info("[收钱吧自动退款] {}", summary);
        return ResponseDto.success(summary);
    }

    // ================================ 订单列表 ================================

    @Override
    public ResponseDto<List<GoblinSqbOrderDetailVo>> getOrderList(String userId) {
        log.info("[收钱吧订单列表] userId={}", userId);

        List<String> orderIds = goblinRedisUtils.getOrderList(userId);
        if (CollectionUtils.isEmpty(orderIds)) {
            return ResponseDto.success(Collections.emptyList());
        }

        List<GoblinSqbOrderDetailVo> result = new ArrayList<>();
        for (String orderId : orderIds) {
            GoblinStoreOrderVo storeOrderVo = goblinRedisUtils.getGoblinOrder(orderId);
            if (storeOrderVo == null) continue;

            // 取第一个 orderSkuId 判断 skuType
            List<String> orderSkuVoIds = storeOrderVo.getOrderSkuVoIds();
            if (CollectionUtils.isEmpty(orderSkuVoIds)) continue;
            GoblinOrderSkuVo skuVo = goblinRedisUtils.getGoblinOrderSkuVo(orderSkuVoIds.get(0));
            if (skuVo == null) continue;

            // 过滤：只处理 skuType=33 的收钱吧订单
            if (!Integer.valueOf(33).equals(skuVo.getSkuType())) continue;

            GoblinSqbOrderVo sqbOrderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
            result.add(buildDetailVo(storeOrderVo, skuVo, sqbOrderVo));
        }

        // 按创建时间倒序排列
        result.sort((a, b) -> {
            if (a.getCreatedAt() == null) return 1;
            if (b.getCreatedAt() == null) return -1;
            return b.getCreatedAt().compareTo(a.getCreatedAt());
        });

        log.info("[收钱吧订单列表] userId={}, 共 {} 条", userId, result.size());
        return ResponseDto.success(result);
    }

    // ================================ 订单详情 ================================

    @Override
    public ResponseDto<GoblinSqbOrderDetailVo> getOrderDetail(String userId, String orderId) {
        log.info("[收钱吧订单详情] userId={}, orderId={}", userId, orderId);

        GoblinStoreOrderVo storeOrderVo = goblinRedisUtils.getGoblinOrder(orderId);
        if (storeOrderVo == null) return ResponseDto.failure("订单不存在");
        if (!userId.equals(storeOrderVo.getUserId())) return ResponseDto.failure("无权限访问该订单");

        List<String> orderSkuVoIds = storeOrderVo.getOrderSkuVoIds();
        if (CollectionUtils.isEmpty(orderSkuVoIds)) return ResponseDto.failure("订单数据异常");
        GoblinOrderSkuVo skuVo = goblinRedisUtils.getGoblinOrderSkuVo(orderSkuVoIds.get(0));
        if (skuVo == null) return ResponseDto.failure("订单商品数据异常");

        // 校验是收钱吧订单
        if (!Integer.valueOf(33).equals(skuVo.getSkuType())) {
            return ResponseDto.failure("该订单非收钱吧订单");
        }

        GoblinSqbOrderVo sqbOrderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
        GoblinSqbOrderDetailVo detailVo = buildDetailVo(storeOrderVo, skuVo, sqbOrderVo);

        log.info("[收钱吧订单详情] 查询成功，orderId={}", orderId);
        return ResponseDto.success(detailVo);
    }

    // ================================ 再次付款 ================================

    @Override
    public ResponseDto<GoblinSqbOrderCreateVo> repay(String userId, String orderId) {
        log.info("[收钱吧再次付款] userId={}, orderId={}", userId, orderId);

        GoblinSqbOrderVo orderVo = goblinSqbRedisUtils.getSqbOrder(orderId);
        if (orderVo == null) return ResponseDto.failure("订单不存在");
        if (!userId.equals(orderVo.getUserId())) return ResponseDto.failure("无权限访问该订单");
        if (!Integer.valueOf(0).equals(orderVo.getStatus())) {
            return ResponseDto.failure("订单状态不支持再次付款（仅待支付状态可重新拉起）");
        }
        if (orderVo.getSqbAcquiringSn() == null) {
            return ResponseDto.failure("订单数据异常，缺少收单号");
        }

        try {
            CommonRequest.Seller seller = buildSeller();

            // 重新查询收银台，获取新的 selectedSignature + seq
            CashierQueryRequest cashierReq = buildCashierQueryRequest(
                    seller, orderVo.getSqbAcquiringSn(), orderVo.getSqbOrderSignature());
            CashierQueryData cashierData = goblinShouQianBaService.queryCashier(cashierReq);
            if (cashierData == null) return ResponseDto.failure("查询收银台失败，请稍后重试");

            // 重新创建微信预支付
            CreateWechatPrepayOrderRequest prepayReq = buildWechatPrepayRequest(
                    seller, orderVo.getSqbAcquiringSn(), orderVo.getSqbOrderSignature(),
                    cashierData.getSelectedSignature(), cashierData.getSeq(), cashierData);
            CreateWechatPrepayOrderData prepayData = goblinShouQianBaService.createWechatPrepayOrder(prepayReq);
            if (prepayData == null || prepayData.getPaymentVoucher() == null) {
                return ResponseDto.failure("创建微信预支付失败，请稍后重试");
            }

            CreateWechatPrepayOrderData.PaymentVoucher pv = prepayData.getPaymentVoucher();
            GoblinSqbOrderCreateVo createVo = new GoblinSqbOrderCreateVo();
            createVo.setOrderId(orderId);
            createVo.setAcquiringSn(orderVo.getSqbAcquiringSn());
            createVo.setTimeStamp(pv.getTimeStamp());
            createVo.setPackageStr(pv.getPackageStr());
            createVo.setPaySign(pv.getPaySign());
            createVo.setAppId(pv.getAppId());
            createVo.setSignType(pv.getSignType());
            createVo.setNonceStr(pv.getNonceStr());

            log.info("[收钱吧再次付款] 成功，orderId={}", orderId);
            return ResponseDto.success(createVo);

        } catch (Exception e) {
            log.error("[收钱吧再次付款] 异常，orderId={}", orderId, e);
            return ResponseDto.failure("再次付款失败：" + e.getMessage());
        }
    }

    // ================================ 私有辅助方法 ================================

    private CommonRequest.Seller buildSeller() {
        CommonRequest.Seller seller = new CommonRequest.Seller();
        seller.setMerchantId(SQB_MERCHANT_ID);
        seller.setMerchantUserId(SQB_MERCHANT_USER_ID);
        seller.setRole(SQB_ROLE);
        return seller;
    }

    private CashierQueryRequest buildCashierQueryRequest(CommonRequest.Seller seller,
                                                         String acquiringSn, String acquiringSignature) {
        CashierQueryRequest req = new CashierQueryRequest();
        req.setAppid(SQB_APPID);
        req.setSeller(seller);
        req.setPaymentMode(4); // 4-微信小程序支付

        CashierQueryRequest.PaymentEnv paymentEnv = new CashierQueryRequest.PaymentEnv();
        paymentEnv.setClient("wechat");
        req.setPaymentEnv(paymentEnv);

        CommonRequest.Acquiring acquiring = new CommonRequest.Acquiring();
        acquiring.setAcquiringSn(acquiringSn);
        acquiring.setSignature(acquiringSignature);
        req.setAcquiringInfo(acquiring);
        return req;
    }

    private CreateWechatPrepayOrderRequest buildWechatPrepayRequest(CommonRequest.Seller seller,
                                                                     String acquiringSn,
                                                                     String acquiringSignature,
                                                                     String selectedSignature,
                                                                     String seq,
                                                                     CashierQueryData cashierData) {
        CreateWechatPrepayOrderRequest req = new CreateWechatPrepayOrderRequest();
        req.setAppid(SQB_APPID);
        req.setSeller(seller);
        req.setAcquiringSn(acquiringSn);
        req.setSignature(acquiringSignature);
        req.setSelectedSignature(selectedSignature);
        req.setSeq(seq);

        // 使用收银台返回的第一个可用支付工具
        if (cashierData != null && !CollectionUtils.isEmpty(cashierData.getPayTools())) {
            List<CreateWechatPrepayOrderRequest.UsingPayTool> usingPayTools = new ArrayList<>();
            cashierData.getPayTools().stream()
                    .filter(t -> Boolean.TRUE.equals(t.getSelectable()))
                    .findFirst()
                    .ifPresent(payTool -> {
                        CreateWechatPrepayOrderRequest.UsingPayTool usingTool = new CreateWechatPrepayOrderRequest.UsingPayTool();
                        usingTool.setId(payTool.getId());
                        usingTool.setPayTool(payTool.getType());
                        usingTool.setPayMode(4);
                        usingTool.setAmount(payTool.getShowAmount() != null ? String.valueOf(payTool.getShowAmount()) : "0");
                        usingTool.setIdentity("wzwl");
                        usingTool.setRequestSn(IDGenerator.nextSnowId());
                        usingPayTools.add(usingTool);
                    });
            req.setUsingPayTools(usingPayTools);
        }
        return req;
    }

    private GoblinSqbOrderDetailVo buildDetailVo(GoblinStoreOrderVo storeOrderVo,
                                                   GoblinOrderSkuVo skuVo,
                                                   GoblinSqbOrderVo sqbOrderVo) {
        GoblinSqbOrderDetailVo detailVo = new GoblinSqbOrderDetailVo();
        // 来自 GoblinStoreOrderVo
        detailVo.setOrderId(storeOrderVo.getOrderId());
        detailVo.setOrderCode(storeOrderVo.getOrderCode());
        detailVo.setStatus(storeOrderVo.getStatus());
        detailVo.setPriceActual(storeOrderVo.getPriceActual());
        detailVo.setCreatedAt(storeOrderVo.getCreatedAt());
        detailVo.setPayTime(storeOrderVo.getPayTime());
        // 来自 GoblinOrderSkuVo
        detailVo.setSpuId(skuVo.getSpuId());
        detailVo.setSpuName(skuVo.getSpuName());
        detailVo.setSkuId(skuVo.getSkuId());
        detailVo.setSkuName(skuVo.getSkuName());
        detailVo.setSkuImage(skuVo.getSkuImage());
        detailVo.setQuantity(skuVo.getNum());
        // 来自 GoblinSqbOrderVo
        if (sqbOrderVo != null) {
            detailVo.setSqbStatus(sqbOrderVo.getStatus());
            detailVo.setPerformancesId(sqbOrderVo.getPerformancesId());
            detailVo.setSqbAcquiringSn(sqbOrderVo.getSqbAcquiringSn());
            detailVo.setCouponSn(sqbOrderVo.getCouponSn());
            detailVo.setCouponQrCode(sqbOrderVo.getCouponQrCode());
            detailVo.setCouponExpireTime(sqbOrderVo.getCouponExpireTime());
            detailVo.setCouponUsedStatus(sqbOrderVo.getCouponUsedStatus());
        }
        return detailVo;
    }

    private String getOrderIdFromParams(Map<String, Object> params) {
        String orderId = (String) params.get("orderId");
        if (orderId == null) orderId = (String) params.get("acquiringSn");
        return orderId;
    }

    private void syncOrderStatus(String orderId, int status) {
        GoblinStoreOrderVo storeOrderVo = goblinRedisUtils.getGoblinOrder(orderId);
        if (storeOrderVo == null) return;
        
        String now = LocalDateTime.now().format(DTF);
        storeOrderVo.setStatus(status);
        if (status == 1) { // 支付成功
            storeOrderVo.setPayTime(now);
        }
        
        // 1. 同步 Redis
        goblinRedisUtils.setGoblinOrder(orderId, storeOrderVo);
        
        // 2. 同步 MongoDB
        goblinMongoUtils.updateGoblinStoreOrderVo(orderId, storeOrderVo);
        
        // 3. 同步 MySQL (复用下单 MQ 发送 Update 语句)
        String sql;
        Object[] data;
        if (status == 1) {
            sql = "UPDATE goblin_store_order SET status = ?, pay_time = ?, updated_at = ? WHERE order_id = ?";
            data = new Object[]{status, now, now, orderId};
        } else {
            sql = "UPDATE goblin_store_order SET status = ?, updated_at = ? WHERE order_id = ?";
            data = new Object[]{status, now, orderId};
        }
        
        java.util.LinkedList<String> sqls = new java.util.LinkedList<>();
        sqls.add(sql);
        java.util.LinkedList<Object[]> sqlData = new java.util.LinkedList<>();
        sqlData.add(data);
        
        if (queueUtils != null) {
            queueUtils.sendMsgByRedis(com.liquidnet.service.base.constant.MQConst.GoblinQueue.GOBLIN_ORDER_CREATE_PAY.getKey(),
                    com.liquidnet.service.base.SqlMapping.gets(sqls, sqlData));
        }
    }
}
