package com.haha.service.payment.payscore.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.haha.common.constant.OrderConstants;
import com.haha.common.constant.PaymentConstants;
import com.haha.common.enums.OrderStatus;
import com.haha.common.enums.PayScoreState;
import com.haha.common.enums.PayStatus;
import com.haha.common.enums.PaymentChannel;
import com.haha.common.enums.RefundStatus;
import com.haha.entity.Order;
import com.haha.entity.User;
import com.haha.service.OrderService;
import com.haha.service.UserService;
import com.haha.service.payment.config.WxPayConfig;
import com.haha.service.payment.payscore.*;
import com.haha.service.payment.payscore.PayScoreCreateRequest.PostPayment;
import com.haha.service.payment.payscore.PayScoreCompleteRequest.PostDiscount;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 支付分业务服务实现
 * 封装支付分相关的业务逻辑，协调订单服务和支付分策略
 */
@Slf4j
@Service
public class PayScoreServiceImpl implements PayScoreService {

    @Autowired(required = false)
    private PayScoreStrategy payScoreStrategy;

    @Autowired
    private OrderService orderService;

    @Autowired
    private UserService userService;

    @Autowired(required = false)
    private WxPayConfig wxPayConfig;

    @Autowired(required = false)
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private com.haha.service.OrderInventoryService orderInventoryService;

    private static final String REDIS_KEY_PREFIX = "payscore:preauth:";
    private static final long REDIS_TTL_MINUTES = 30;
    private static final String REDIS_TRACKING_KEY = "payscore:preauth:tracking:";
    private static final long REDIS_TRACKING_TTL_HOURS = 24;

    private static final BigDecimal DEFAULT_RISK_FUND_AMOUNT = new BigDecimal("99.00");
    private static final String DEFAULT_RISK_FUND_NAME = "DEPOSIT";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayScoreResult createPayScoreOrder(Long orderId, String openId) {
        return createPayScoreOrder(orderId, openId, DEFAULT_RISK_FUND_AMOUNT, DEFAULT_RISK_FUND_NAME);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayScoreResult createPayScoreOrder(Long orderId, String openId, 
            BigDecimal riskFundAmount, String riskFundName) {
        log.info("[支付分服务] 创建服务订单 - orderId: {}, openId: {}, riskFund: {}元", 
                orderId, openId, riskFundAmount);

        PayScoreResult checkResult = checkServiceAvailable();
        if (checkResult != null) {
            return checkResult;
        }

        Order order = validateAndGetOrder(orderId);

        if (order.getPayScoreOrderId() != null && !PayScoreState.REVOKED.getCode().equals(order.getPayScoreState())) {
            log.warn("[支付分服务] 订单已存在支付分订单 - orderId: {}, payScoreState: {}", 
                    orderId, order.getPayScoreState());
            return PayScoreResult.fail("ORDER_EXISTS", "该订单已创建支付分服务订单");
        }

        PayScoreCreateRequest request = new PayScoreCreateRequest();
        request.setOutOrderNo(generateOutOrderNo(orderId));
        request.setServiceIntroduction("充电服务");
        request.setOpenId(openId);
        request.setRiskFundName(riskFundName != null ? riskFundName : DEFAULT_RISK_FUND_NAME);
        request.setRiskFundAmount(riskFundAmount != null ? riskFundAmount : DEFAULT_RISK_FUND_AMOUNT);
        request.setStartTime("OnAccept");
        request.setStartDeviceId(order.getDeviceId());

        if (order.getTotalAmount() != null && order.getTotalAmount().compareTo(BigDecimal.ZERO) > 0) {
            PostPayment payment = new PostPayment();
            payment.setName("充电费用");
            payment.setAmount(order.getTotalAmount());
            payment.setDescription("预估费用");
            request.setPostPayments(Collections.singletonList(payment));
        }

        PayScoreResult result = payScoreStrategy.createServiceOrder(request);

        if (result.isSuccess()) {
            order.setPayScoreOrderId(result.getOutOrderNo());
            order.setPayScoreState(result.getState());
            if (wxPayConfig != null) {
                order.setServiceId(wxPayConfig.getServiceId());
            }
            order.setServiceStartTime(LocalDateTime.now());
            order.setPayChannel(PaymentChannel.WECHAT_PAYSCORE.getCode());
            order.setPayType("微信支付分");
            orderService.updateById(order);

            log.info("[支付分服务] 创建服务订单成功 - orderId: {}, outOrderNo: {}, state: {}", 
                    orderId, result.getOutOrderNo(), result.getState());
        } else {
            log.error("[支付分服务] 创建服务订单失败 - orderId: {}, errorCode: {}, errorMsg: {}", 
                    orderId, result.getErrorCode(), result.getErrorMsg());
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayScoreResult completePayScoreOrder(Long orderId, BigDecimal totalAmount, 
            List<PostPayment> payments) {
        return completePayScoreOrder(orderId, totalAmount, payments, null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayScoreResult completePayScoreOrder(Long orderId, BigDecimal totalAmount, 
            List<PostPayment> payments, List<PostDiscount> discounts) {
        log.info("[支付分服务] 完结服务订单 - orderId: {}, totalAmount: {}元", orderId, totalAmount);

        PayScoreResult checkResult = checkServiceAvailable();
        if (checkResult != null) {
            return checkResult;
        }

        Order order = validateAndGetOrder(orderId);

        if (order.getPayScoreOrderId() == null) {
            log.error("[支付分服务] 订单未创建支付分服务订单 - orderId: {}", orderId);
            return PayScoreResult.fail("ORDER_NOT_CREATED", "该订单未创建支付分服务订单");
        }

        if (PayScoreState.isFinished(order.getPayScoreState())) {
            log.warn("[支付分服务] 订单已完结或已取消 - orderId: {}, payScoreState: {}", 
                    orderId, order.getPayScoreState());
            return PayScoreResult.fail("ORDER_COMPLETED", "该订单已完结或已取消");
        }

        PayScoreCompleteRequest request = new PayScoreCompleteRequest();
        request.setOutOrderNo(order.getPayScoreOrderId());
        request.setTotalAmount(totalAmount);
        request.setPostPayments(payments);
        request.setPostDiscounts(discounts);
        request.setEndTime(formatDateTime(LocalDateTime.now()));
        request.setStartDeviceId(order.getDeviceId());

        PayScoreResult result = payScoreStrategy.completeServiceOrder(request);

        if (result.isSuccess()) {
            // 微信 API 调用成功，根据返回的 state 更新订单
            String state = result.getState() != null ? result.getState() : PayScoreState.USER_PAYING.getCode();
            order.setPayScoreState(state);
            order.setServiceEndTime(LocalDateTime.now());
            order.setTotalAmount(totalAmount);

            if (PayScoreState.DONE.getCode().equals(state)) {
                // 完结并扣款成功，同步更新订单状态为已完成
                order.setPayStatus(PayStatus.PAID.getCode());
                order.setStatus(OrderStatus.COMPLETED.getCode());
                order.setPayTime(LocalDateTime.now());
                order.setPayScoreFailReason(null);
                // 同步支付状态到哈哈平台
                orderService.notifyHahaOrderStatusChanged(order.getOrderNo());
                log.info("[支付分服务] 完结并扣款成功 - orderId: {}, state: {}", orderId, state);

                // 支付成功后扣减库存
                try {
                    orderInventoryService.decreaseStockOnPaid(order);
                } catch (Exception e) {
                    log.error("[支付分服务] 扣减库存异常 - orderNo={}", order.getOrderNo(), e);
                }
            } else if (PayScoreState.isPaying(state)) {
                log.warn("[支付分服务] 完结成功但用户待支付 - orderId: {}, state: {}", orderId, state);
            } else {
                log.info("[支付分服务] 完结服务订单成功 - orderId: {}, state: {}", orderId, state);
            }

            orderService.updateById(order);
        } else {
            // 微信 API 调用失败（网络异常、业务拒绝等），标记为 USER_PAYING 避免订单卡死
            String failReason = result.getErrorCode() + ": " + result.getErrorMsg();
            log.error("[支付分服务] 完结服务订单失败 - orderId: {}, failReason: {}", orderId, failReason);

            order.setPayScoreState(PayScoreState.USER_PAYING.getCode());
            order.setPayScoreFailReason(failReason);
            order.setServiceEndTime(LocalDateTime.now());
            order.setTotalAmount(totalAmount);
            orderService.updateById(order);

            // 本地已正确处理为 USER_PAYING 中间态，返回 success
            return PayScoreResult.success(
                    order.getPayScoreOrderId(), PayScoreState.USER_PAYING.getCode());
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayScoreResult cancelPayScoreOrder(Long orderId, String reason) {
        log.info("[支付分服务] 取消服务订单 - orderId: {}, reason: {}", orderId, reason);

        PayScoreResult checkResult = checkServiceAvailable();
        if (checkResult != null) {
            return checkResult;
        }

        Order order = validateAndGetOrder(orderId);

        if (order.getPayScoreOrderId() == null) {
            log.error("[支付分服务] 订单未创建支付分服务订单 - orderId: {}", orderId);
            return PayScoreResult.fail("ORDER_NOT_CREATED", "该订单未创建支付分服务订单");
        }

        if (PayScoreState.isFinished(order.getPayScoreState())) {
            log.warn("[支付分服务] 订单已完结或已取消 - orderId: {}, payScoreState: {}", 
                    orderId, order.getPayScoreState());
            return PayScoreResult.fail("ORDER_COMPLETED", "该订单已完结或已取消");
        }

        PayScoreCancelRequest request = new PayScoreCancelRequest();
        request.setOutOrderNo(order.getPayScoreOrderId());
        request.setReason(reason != null ? reason : "用户取消");

        PayScoreResult result = payScoreStrategy.cancelServiceOrder(request);

        if (result.isSuccess()) {
            order.setPayScoreState(PayScoreState.REVOKED.getCode());
            order.setStatus(OrderStatus.CANCELLED.getCode());
            orderService.updateById(order);

            log.info("[支付分服务] 取消服务订单成功 - orderId: {}", orderId);
        } else {
            log.error("[支付分服务] 取消服务订单失败 - orderId: {}, errorCode: {}, errorMsg: {}", 
                    orderId, result.getErrorCode(), result.getErrorMsg());
        }

        return result;
    }

    @Override
    public PayScoreResult queryPayScoreOrder(String outOrderNo) {
        log.info("[支付分服务] 查询服务订单 - outOrderNo: {}", outOrderNo);
        
        PayScoreResult checkResult = checkServiceAvailable();
        if (checkResult != null) {
            return checkResult;
        }
        
        return payScoreStrategy.queryServiceOrder(outOrderNo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayScoreCallbackResult handlePayScoreCallback(Map<String, Object> params) {
        log.info("[支付分服务] 处理回调通知");

        if (payScoreStrategy == null) {
            log.error("[支付分服务] 支付分策略未初始化，请检查微信支付配置");
            return PayScoreCallbackResult.fail("支付分服务未配置");
        }

        PayScoreCallbackResult result = payScoreStrategy.parseCallback(params);

        if (!result.isSuccess()) {
            log.error("[支付分服务] 回调解析失败 - errorMsg: {}", result.getErrorMsg());
            return result;
        }

        String outOrderNo = result.getOutOrderNo();
        String eventType = result.getEventType();
        String state = result.getState();

        log.info("[支付分服务] 回调解析成功 - outOrderNo: {}, eventType: {}, state: {}", 
                outOrderNo, eventType, state);

        Order order = orderService.lambdaQuery()
                .eq(Order::getPayScoreOrderId, outOrderNo)
                .one();

        if (order == null) {
            log.error("[支付分服务] 未找到对应订单 - payScoreOrderId: {}", outOrderNo);
            return result;
        }

        if ("PAYSCORE.USER_CONFIRMED".equals(eventType)) {
            order.setPayScoreState(PayScoreState.DOING.getCode());
            log.info("[支付分服务] 用户确认使用服务 - orderId: {}", order.getId());
        } else if ("PAYSCORE.USER_PAID".equals(eventType)) {
            order.setPayScoreState(PayScoreState.DONE.getCode());
            order.setPayStatus(PayStatus.PAID.getCode());
            order.setStatus(OrderStatus.COMPLETED.getCode());
            order.setPayTime(result.getPayTime() != null ? result.getPayTime() : LocalDateTime.now());
            order.setPayScoreFailReason(null);
            if (result.getTotalAmount() != null) {
                order.setTotalAmount(result.getTotalAmount());
            }
            if (result.getTransactionId() != null) {
                order.setTransactionId(result.getTransactionId());
            }
            log.info("[支付分服务] 用户完成支付 - orderId: {}, amount: {}元, transactionId: {}",
                    order.getId(), result.getTotalAmount(), result.getTransactionId());

            // 支付成功后扣减库存
            try {
                orderInventoryService.decreaseStockOnPaid(order);
            } catch (Exception e) {
                log.error("[支付分服务] 扣减库存异常 - orderNo={}", order.getOrderNo(), e);
            }
        } else if ("PAYSCORE.REFUND_PAID".equals(eventType)) {
            order.setRefundStatus(RefundStatus.REFUNDED.getCode());
            order.setPayStatus(OrderConstants.PAY_STATUS_REFUND);
            order.setRefundTime(result.getPayTime() != null ? result.getPayTime() : LocalDateTime.now());
            if (result.getTotalAmount() != null) {
                order.setRefundAmount(result.getTotalAmount());
            }
            log.info("[支付分服务] 退款成功回调 - orderId: {}, amount: {}元",
                    order.getId(), result.getTotalAmount());
        } else if ("PAYSCORE.USER_CANCEL".equals(eventType)) {
            order.setPayScoreState(PayScoreState.REVOKED.getCode());
            order.setStatus(OrderStatus.CANCELLED.getCode());
            order.setPayScoreFailReason(result.getCancelReason() != null
                    ? result.getCancelReason() : "用户取消");
            log.info("[支付分服务] 用户取消服务订单 - orderId: {}, reason: {}",
                    order.getId(), order.getPayScoreFailReason());
        } else if (PayScoreState.isRevoked(state) || PayScoreState.isExpired(state)) {
            order.setPayScoreState(state);
            order.setStatus(OrderStatus.CANCELLED.getCode());
            log.info("[支付分服务] 订单已取消/过期 - orderId: {}, state: {}", order.getId(), state);
        } else if (PayScoreState.isPaying(state)) {
            // 订单进入 USER_PAYING 状态（扣款已发起但用户尚未完成支付）
            order.setPayScoreState(PayScoreState.USER_PAYING.getCode());
            log.warn("[支付分服务] 订单进入用户支付中状态 - orderId: {}, state: {}",
                    order.getId(), state);
        }

        orderService.updateById(order);

        // 支付/退款状态变更时同步到哈哈平台
        if ("PAYSCORE.USER_PAID".equals(eventType) || "PAYSCORE.REFUND_PAID".equals(eventType)) {
            orderService.notifyHahaOrderStatusChanged(order.getOrderNo());
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayScoreResult syncPayScoreStatus(Long orderId) {
        log.info("[支付分服务] 同步订单状态 - orderId: {}", orderId);

        PayScoreResult checkResult = checkServiceAvailable();
        if (checkResult != null) {
            return null;
        }

        Order order = validateAndGetOrder(orderId);

        if (order.getPayScoreOrderId() == null) {
            log.warn("[支付分服务] 订单未创建支付分服务订单，无法同步 - orderId: {}", orderId);
            return null;
        }

        PayScoreResult result = payScoreStrategy.queryServiceOrder(order.getPayScoreOrderId());

        if (!result.isSuccess()) {
            log.error("[支付分服务] 查询服务订单失败 - orderId: {}, errorCode: {}",
                    orderId, result.getErrorCode());
            return null;
        }

        String newState = result.getState();
        String oldState = order.getPayScoreState();

        if (newState != null && !newState.equals(oldState)) {
            order.setPayScoreState(newState);

            if (PayScoreState.isDone(newState)) {
                order.setPayStatus(PayStatus.PAID.getCode());
                order.setStatus(OrderStatus.COMPLETED.getCode());
                order.setPayScoreFailReason(null);
                if (result.getTotalAmount() != null) {
                    order.setTotalAmount(result.getTotalAmount());
                }
                // 同步支付状态到哈哈平台
                orderService.notifyHahaOrderStatusChanged(order.getOrderNo());

                // 支付成功后扣减库存
                try {
                    orderInventoryService.decreaseStockOnPaid(order);
                } catch (Exception e) {
                    log.error("[支付分服务] 扣减库存异常 - orderNo={}", order.getOrderNo(), e);
                }
            } else if (PayScoreState.isRevoked(newState)) {
                order.setStatus(OrderStatus.CANCELLED.getCode());
            } else if (PayScoreState.isExpired(newState)) {
                order.setStatus(OrderStatus.CANCELLED.getCode());
                log.info("[支付分服务] 订单已过期 - orderId: {}, outOrderNo: {}", orderId, order.getPayScoreOrderId());
            } else if (PayScoreState.isPaying(newState)) {
                log.info("[支付分服务] 订单仍处于用户支付中状态 - orderId: {}", orderId);
            }

            orderService.updateById(order);
            log.info("[支付分服务] 订单状态已更新 - orderId: {}, oldState: {}, newState: {}",
                    orderId, oldState, newState);
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayScoreResult payPayScoreOrder(Long orderId) {
        log.info("[支付分服务] 发起支付扣款 - orderId: {}", orderId);

        PayScoreResult checkResult = checkServiceAvailable();
        if (checkResult != null) {
            return checkResult;
        }

        Order order = validateAndGetOrder(orderId);

        if (order.getPayScoreOrderId() == null) {
            return PayScoreResult.fail("ORDER_NOT_CREATED", "该订单未创建支付分服务订单");
        }

        // 调用微信支付分 /pay 接口发起扣款
        PayScoreResult result = payScoreStrategy.payServiceOrder(order.getPayScoreOrderId());

        if (result.isSuccess()) {
            log.info("[支付分服务] 支付扣款成功 - orderId: {}, outOrderNo: {}", orderId, order.getPayScoreOrderId());
        } else {
            log.error("[支付分服务] 支付扣款失败 - orderId: {}, errorCode: {}, errorMsg: {}",
                    orderId, result.getErrorCode(), result.getErrorMsg());
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayScoreResult modifyPayScoreOrder(Long orderId, BigDecimal totalAmount,
            List<PayScoreModifyRequest.PostPayment> payments, String reason) {
        log.info("[支付分服务] 修改订单金额 - orderId: {}, 新金额: {}元", orderId, totalAmount);

        PayScoreResult checkResult = checkServiceAvailable();
        if (checkResult != null) {
            return checkResult;
        }

        Order order = validateAndGetOrder(orderId);

        if (order.getPayScoreOrderId() == null) {
            return PayScoreResult.fail("ORDER_NOT_CREATED", "该订单未创建支付分服务订单");
        }

        if (!PayScoreState.USER_PAYING.getCode().equals(order.getPayScoreState())) {
            return PayScoreResult.fail("INVALID_STATE", "仅待支付状态的订单可修改金额，当前状态: " + order.getPayScoreState());
        }

        PayScoreModifyRequest request = new PayScoreModifyRequest();
        request.setOutOrderNo(order.getPayScoreOrderId());
        request.setTotalAmount(totalAmount);
        request.setPostPayments(payments);
        request.setReason(reason != null ? reason : "金额调整");

        PayScoreResult result = payScoreStrategy.modifyServiceOrder(request);

        if (result.isSuccess()) {
            if (result.getState() != null) {
                order.setPayScoreState(result.getState());
            }
            order.setTotalAmount(totalAmount);
            orderService.updateById(order);
            log.info("[支付分服务] 修改金额成功 - orderId: {}", orderId);
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayScoreResult syncOrderPaidInfo(Long orderId, String detail) {
        log.info("[支付分服务] 同步订单支付信息 - orderId: {}, detail: {}", orderId, detail);

        PayScoreResult checkResult = checkServiceAvailable();
        if (checkResult != null) {
            return checkResult;
        }

        Order order = validateAndGetOrder(orderId);

        if (order.getPayScoreOrderId() == null) {
            return PayScoreResult.fail("ORDER_NOT_CREATED", "该订单未创建支付分服务订单");
        }

        if (PayScoreState.isFinished(order.getPayScoreState())) {
            return PayScoreResult.fail("ORDER_FINISHED", "该订单已完结或已取消");
        }

        PayScoreSyncRequest request = new PayScoreSyncRequest();
        request.setOutOrderNo(order.getPayScoreOrderId());
        request.setType("ORDER_PAID");
        request.setDetail(detail != null ? detail : "用户已通过其他方式支付");

        PayScoreResult result = payScoreStrategy.syncServiceOrder(request);

        if (result.isSuccess()) {
            if (result.getState() != null) {
                order.setPayScoreState(result.getState());
            }
            order.setPayStatus(PayStatus.PAID.getCode());
            order.setStatus(OrderStatus.COMPLETED.getCode());
            order.setPayTime(LocalDateTime.now());
            order.setPayScoreFailReason(null);
            orderService.updateById(order);
            log.info("[支付分服务] 同步支付信息成功 - orderId: {}", orderId);

            // 支付成功后扣减库存
            try {
                orderInventoryService.decreaseStockOnPaid(order);
            } catch (Exception e) {
                log.error("[支付分服务] 扣减库存异常 - orderNo={}", order.getOrderNo(), e);
            }
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayScoreResult refundPayScoreOrder(Long orderId, BigDecimal refundAmount, String reason) {
        log.info("[支付分服务] 发起退款 - orderId: {}, 金额: {}元", orderId, refundAmount);

        PayScoreResult checkResult = checkServiceAvailable();
        if (checkResult != null) {
            return checkResult;
        }

        Order order = validateAndGetOrder(orderId);

        if (order.getPayScoreOrderId() == null) {
            return PayScoreResult.fail("ORDER_NOT_CREATED", "该订单未创建支付分服务订单");
        }

        if (!OrderConstants.PAY_STATUS_PAID.equals(order.getPayStatus())
                && !OrderConstants.PAY_STATUS_PARTIAL_REFUND.equals(order.getPayStatus())) {
            return PayScoreResult.fail("ORDER_NOT_PAID", "只有已支付或部分退款订单可以退款");
        }

        // 检查 7 天退款期限
        if (order.getPayTime() != null) {
            long daysDiff = java.time.temporal.ChronoUnit.DAYS.between(order.getPayTime(), LocalDateTime.now());
            if (daysDiff > 7) {
                return PayScoreResult.fail("REFUND_EXPIRED", "订单已完成超过7天，不支持退款");
            }
        }

        // 退款金额未传则默认使用实付金额
        BigDecimal actualRefundAmount = refundAmount != null ? refundAmount
                : (order.getPaidAmount() != null ? order.getPaidAmount() : order.getTotalAmount());

        // 如果缺少 transaction_id（旧订单回调时未提取），从微信查询补全
        if (order.getTransactionId() == null || order.getTransactionId().isEmpty()) {
            log.info("[支付分服务] transaction_id缺失，从微信查询补全 - orderId: {}", orderId);
            PayScoreResult queryResult = payScoreStrategy.queryServiceOrder(order.getPayScoreOrderId());
            if (queryResult.isSuccess() && queryResult.getTransactionId() != null) {
                order.setTransactionId(queryResult.getTransactionId());
                orderService.updateById(order);
                log.info("[支付分服务] transaction_id补全成功 - orderId: {}, transactionId: {}",
                        orderId, order.getTransactionId());
            } else {
                return PayScoreResult.fail("MISSING_TRANSACTION_ID",
                        "未收到微信支付回调，缺少 transaction_id，请稍后重试");
            }
        }

        PayScoreRefundRequest request = new PayScoreRefundRequest();
        request.setOutOrderNo(order.getPayScoreOrderId());
        request.setTransactionId(order.getTransactionId());
        request.setRefundAmount(actualRefundAmount);
        request.setTotalAmount(order.getTotalAmount());
        request.setReason(reason != null ? reason : "用户申请退款");
        // 每次退款生成唯一 out_refund_no，避免重试时参数不一致导致微信拒绝
        request.setOutRefundNo(PaymentConstants.REFUND_ORDER_PREFIX
                + order.getPayScoreOrderId() + System.currentTimeMillis());

        PayScoreResult result = payScoreStrategy.refundServiceOrder(request);

        if (result.isSuccess()) {
            // Order 状态由 PaymentServiceImpl.updateOrderRefundStatus() 统一处理（累计算法）
            log.info("[支付分服务] 退款成功 - orderId: {}, refundId: {}", orderId, result.getPackageStr());
        }

        return result;
    }

    @Override
    public PayScoreResult queryPayScoreRefund(Long orderId, String outRefundNo) {
        log.info("[支付分服务] 查询退款状态 - orderId: {}, refundNo: {}", orderId, outRefundNo);

        PayScoreResult checkResult = checkServiceAvailable();
        if (checkResult != null) {
            return checkResult;
        }

        Order order = validateAndGetOrder(orderId);

        if (order.getPayScoreOrderId() == null) {
            return PayScoreResult.fail("ORDER_NOT_CREATED", "该订单未创建支付分服务订单");
        }

        return payScoreStrategy.queryRefund(order.getPayScoreOrderId(), outRefundNo);
    }

    private PayScoreResult checkServiceAvailable() {
        if (payScoreStrategy == null) {
            log.error("[支付分服务] 支付分策略未初始化，请检查微信支付配置");
            return PayScoreResult.fail("SERVICE_UNAVAILABLE", "支付分服务未配置");
        }
        return null;
    }

    private Order validateAndGetOrder(Long orderId) {
        if (orderId == null) {
            throw new IllegalArgumentException("订单ID不能为空");
        }

        Order order = orderService.getById(orderId);
        if (order == null) {
            throw new IllegalArgumentException("订单不存在: " + orderId);
        }

        return order;
    }

    private String generateOutOrderNo(Long orderId) {
        // 微信限制 out_order_no ≤ 32 字符，PS(2) + 秒级时间戳(10) + orderId(19) = 31
        return PaymentConstants.PAYSCORE_ORDER_PREFIX + (System.currentTimeMillis() / 1000) + orderId;
    }

    private String generatePreAuthOutOrderNo(String deviceId) {
        // 预授权模式：无本地订单ID，PS(2) + 时间戳(10) + 设备ID后10位 = 最多22字符
        String safeDeviceId = deviceId.replaceAll("[^A-Za-z0-9]", "");
        String suffix = safeDeviceId.length() > 10 ? safeDeviceId.substring(safeDeviceId.length() - 10) : safeDeviceId;
        return PaymentConstants.PAYSCORE_ORDER_PREFIX + (System.currentTimeMillis() / 1000) + suffix;
    }

    private String formatDateTime(LocalDateTime dateTime) {
        return dateTime.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
    }

    // ==================== 用户端支付分业务方法 ====================

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> createUserPayScoreOrder(Long userId, Long orderId, String openId,
                                                        BigDecimal riskFundAmount, String riskFundName) {
        Order order = orderService.getById(orderId);
        if (order == null || !order.getUserId().equals(userId)) {
            return null;
        }

        PayScoreResult result;
        if (riskFundAmount != null || riskFundName != null) {
            result = createPayScoreOrder(orderId, openId, riskFundAmount, riskFundName);
        } else {
            result = createPayScoreOrder(orderId, openId);
        }

        if (result.isSuccess()) {
            Map<String, Object> data = new HashMap<>();
            data.put("outOrderNo", result.getOutOrderNo());
            data.put("state", result.getState());
            data.put("package", result.getPackageStr());
            return data;
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> completeUserPayScoreOrder(Long userId, Long orderId, BigDecimal totalAmount,
                                                          List<PostPayment> payments,
                                                          List<PostDiscount> discounts) {
        Order order = orderService.getById(orderId);
        if (order == null || !order.getUserId().equals(userId)) {
            return null;
        }

        PayScoreResult result = completePayScoreOrder(orderId, totalAmount, payments, discounts);
        if (result.isSuccess()) {
            Map<String, Object> data = new HashMap<>();
            data.put("outOrderNo", result.getOutOrderNo());
            data.put("state", result.getState());
            return data;
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> cancelUserPayScoreOrder(Long userId, Long orderId, String reason) {
        Order order = orderService.getById(orderId);
        if (order == null || !order.getUserId().equals(userId)) {
            return null;
        }

        PayScoreResult result = cancelPayScoreOrder(orderId, reason);
        if (result.isSuccess()) {
            Map<String, Object> data = new HashMap<>();
            data.put("outOrderNo", result.getOutOrderNo());
            data.put("state", result.getState());
            return data;
        }
        return null;
    }

    @Override
    public Map<String, Object> queryUserPayScoreOrder(Long userId, Long orderId) {
        Order order = orderService.getById(orderId);
        if (order == null || !order.getUserId().equals(userId)) {
            return null;
        }
        if (order.getPayScoreOrderId() == null) {
            return null;
        }

        PayScoreResult result = queryPayScoreOrder(order.getPayScoreOrderId());
        if (result.isSuccess()) {
            Map<String, Object> data = new HashMap<>();
            data.put("outOrderNo", result.getOutOrderNo());
            data.put("state", result.getState());
            data.put("totalAmount", result.getTotalAmount());
            return data;
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean syncUserPayScoreStatus(Long userId, Long orderId) {
        Order order = orderService.getById(orderId);
        if (order == null || !order.getUserId().equals(userId)) {
            return false;
        }
        PayScoreResult result = syncPayScoreStatus(orderId);
        return result != null && result.isSuccess();
    }

    @Override
    public Map<String, Object> createUserPayScoreOrder(Long userId, Map<String, Object> params) {
        if (!params.containsKey("orderId")) {
            return null;
        }
        if (!params.containsKey("openId")) {
            return null;
        }

        Long orderId = Long.valueOf(params.get("orderId").toString());
        String openId = params.get("openId").toString();

        BigDecimal riskFundAmount = null;
        if (params.containsKey("riskFundAmount")) {
            riskFundAmount = new BigDecimal(params.get("riskFundAmount").toString());
        }

        String riskFundName = null;
        if (params.containsKey("riskFundName")) {
            riskFundName = params.get("riskFundName").toString();
        }

        return createUserPayScoreOrder(userId, orderId, openId, riskFundAmount, riskFundName);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> completeUserPayScoreOrder(Long userId, Map<String, Object> params) {
        if (!params.containsKey("orderId")) {
            return null;
        }
        if (!params.containsKey("totalAmount")) {
            return null;
        }

        Long orderId = Long.valueOf(params.get("orderId").toString());
        BigDecimal totalAmount = new BigDecimal(params.get("totalAmount").toString());

        List<PostPayment> payments = null;
        if (params.containsKey("payments")) {
            payments = JSON.parseArray(params.get("payments").toString(), PostPayment.class);
        }

        List<PostDiscount> discounts = null;
        if (params.containsKey("discounts")) {
            discounts = JSON.parseArray(params.get("discounts").toString(), PostDiscount.class);
        }

        return completeUserPayScoreOrder(userId, orderId, totalAmount, payments, discounts);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> cancelUserPayScoreOrder(Long userId, Map<String, Object> params) {
        if (!params.containsKey("orderId")) {
            return null;
        }

        Long orderId = Long.valueOf(params.get("orderId").toString());
        String reason = params.containsKey("reason") ? params.get("reason").toString() : "用户取消";

        return cancelUserPayScoreOrder(userId, orderId, reason);
    }

    @Override
    public Map<String, Object> preCreatePayScoreOrder(Long userId, String deviceId, String openId) {
        log.info("[支付分服务] 预创建服务订单（需确认模式）- userId: {}, deviceId: {}", userId, deviceId);

        PayScoreResult checkResult = checkServiceAvailable();
        if (checkResult != null) {
            Map<String, Object> errorData = new HashMap<>();
            errorData.put("success", false);
            errorData.put("errorMsg", checkResult.getErrorMsg());
            return errorData;
        }

        // 清理该用户旧的进行中支付分订单（分级：自动补扣 > 取消未确认 > 清理超时孤儿 > Redis追踪）
        int remainingActive = cancelStalePayScoreOrdersAndCount(userId, deviceId);

        // 微信支付分限制：同一实名用户进行中订单不能超过 3 笔
        if (remainingActive >= 3) {
            log.warn("[支付分服务] 用户 {} 仍有 {} 笔未完结支付分订单，已达上限，拒绝创建新订单", userId, remainingActive);
            Map<String, Object> limitData = new HashMap<>();
            limitData.put("success", false);
            limitData.put("errorMsg", "同一实名身份下进行中订单过多（已达" + remainingActive + "笔），请先完成或取消未支付订单后再试");
            return limitData;
        }

        // 如果没有传 openId，从用户表中获取
        if (openId == null || openId.isEmpty()) {
            User user = userService.getById(userId);
            if (user == null || user.getOpenid() == null) {
                Map<String, Object> errorData = new HashMap<>();
                errorData.put("success", false);
                errorData.put("errorMsg", "用户openId未获取，请重新登录");
                return errorData;
            }
            openId = user.getOpenid();
        }

        String outOrderNo = generatePreAuthOutOrderNo(deviceId);

        PayScoreCreateRequest request = new PayScoreCreateRequest();
        request.setOutOrderNo(outOrderNo);
        request.setServiceIntroduction("智能零售服务");
        request.setOpenId(openId);
        request.setRiskFundName("DEPOSIT");
        request.setRiskFundAmount(DEFAULT_RISK_FUND_AMOUNT);
        request.setStartTime("OnAccept");
        request.setStartDeviceId(deviceId);

        PayScoreResult result = payScoreStrategy.createServiceOrder(request);

        if (result.isSuccess()) {
            trackPreAuthOrder(userId, outOrderNo);
            storePreAuthToRedis(deviceId, userId, result);
            // 取消同设备旧的追踪订单（已被本次新订单替代）
            cancelOldDeviceOrders(userId, deviceId, outOrderNo);

            Map<String, Object> data = new HashMap<>();
            data.put("success", true);
            data.put("outOrderNo", result.getOutOrderNo());
            data.put("package", result.getPackageStr());
            if (wxPayConfig != null) {
                data.put("mchId", wxPayConfig.getMchId());
            }
            log.info("[支付分服务] 预创建服务订单成功 - outOrderNo: {}", result.getOutOrderNo());
            return data;
        } else {
            log.error("[支付分服务] 预创建服务订单失败 - error: {}", result.getErrorMsg());
            Map<String, Object> errorData = new HashMap<>();
            errorData.put("success", false);
            errorData.put("errorMsg", result.getErrorMsg());
            return errorData;
        }
    }

    @Override
    public Map<String, Object> getPayscoreDetailSign(String outTradeNo) {
        if (wxPayConfig == null) {
            throw new IllegalStateException("微信支付未配置");
        }
        String apiV2Key = wxPayConfig.getApiV2Key();
        if (apiV2Key == null || apiV2Key.isEmpty()) {
            throw new IllegalStateException("APIv2密钥未配置，请在商户平台-API安全中设置APIv2密钥");
        }

        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        String nonceStr = generateNonceStr(32);
        String signType = "HMAC-SHA256";

        // 按 key 字典序拼接，末尾追加 &key={APIv2密钥}（微信支付V2签名规范）
        String signMessage = "mch_id=" + wxPayConfig.getMchId() + "&"
                + "nonce_str=" + nonceStr + "&"
                + "out_order_no=" + outTradeNo + "&"
                + "service_id=" + wxPayConfig.getServiceId() + "&"
                + "sign_type=" + signType + "&"
                + "timestamp=" + timestamp
                + "&key=" + apiV2Key;

        String sign;
        try {
            Mac mac = Mac.getInstance("HmacSHA256");
            byte[] keyBytes = apiV2Key.getBytes(StandardCharsets.UTF_8);
            SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "HmacSHA256");
            mac.init(secretKey);
            byte[] signBytes = mac.doFinal(signMessage.getBytes(StandardCharsets.UTF_8));
            // 输出大写十六进制
            StringBuilder sb = new StringBuilder();
            for (byte b : signBytes) {
                sb.append(String.format("%02X", b & 0xFF));
            }
            sign = sb.toString();
        } catch (Exception e) {
            log.error("[支付分服务] 生成openBusinessView签名失败", e);
            throw new RuntimeException("生成签名失败", e);
        }

        Map<String, Object> data = new HashMap<>();
        data.put("mchId", wxPayConfig.getMchId());
        data.put("serviceId", wxPayConfig.getServiceId());
        data.put("outOrderNo", outTradeNo);
        data.put("timestamp", timestamp);
        data.put("nonceStr", nonceStr);
        data.put("signType", signType);
        data.put("sign", sign);

        log.info("[支付分服务] 生成支付分详情页签名 - outTradeNo: {}", outTradeNo);
        return data;
    }

    private static String generateNonceStr(int length) {
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        SecureRandom random = new SecureRandom();
        StringBuilder sb = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            sb.append(chars.charAt(random.nextInt(chars.length())));
        }
        return sb.toString();
    }

    private void storePreAuthToRedis(String deviceId, Long userId, PayScoreResult result) {
        if (stringRedisTemplate == null) {
            return;
        }
        String redisKey = REDIS_KEY_PREFIX + deviceId + ":" + userId;
        JSONObject json = new JSONObject();
        json.put("payScoreOrderId", result.getOutOrderNo());
        json.put("payScoreState", result.getState());
        if (wxPayConfig != null) {
            json.put("serviceId", wxPayConfig.getServiceId());
        }
        stringRedisTemplate.opsForValue().set(redisKey, json.toJSONString(), REDIS_TTL_MINUTES, TimeUnit.MINUTES);
        log.info("[支付分服务] 支付分信息已存入Redis - key: {}, ttl: {}min", redisKey, REDIS_TTL_MINUTES);
    }

    /**
     * 从 Redis 获取预创建的支付分信息并关联到订单
     * 由 HahaCallbackServiceImpl 在创建订单后调用
     */
    public void applyPreAuthPayScore(Order order) {
        if (stringRedisTemplate == null || order == null) {
            log.warn("[支付分服务] 无法关联预授权 - stringRedisTemplate={}, order={}",
                    stringRedisTemplate != null, order != null);
            return;
        }

        String redisKey = REDIS_KEY_PREFIX + order.getDeviceId() + ":" + order.getUserId();

        // 订单已携带支付分信息（INSERT 时已写入），只需清理 Redis
        if (order.getPayScoreOrderId() != null) {
            stringRedisTemplate.delete(redisKey);
            stringRedisTemplate.opsForSet().remove(REDIS_TRACKING_KEY + order.getUserId(), order.getPayScoreOrderId());
            log.debug("[支付分服务] 订单已有支付分信息，清理Redis - orderId: {}", order.getId());
            return;
        }

        String jsonStr = stringRedisTemplate.opsForValue().get(redisKey);
        if (jsonStr == null) {
            log.warn("[支付分服务] Redis中未找到预授权信息 - key: {}", redisKey);
            return;
        }

        try {
            JSONObject json = JSON.parseObject(jsonStr);
            String payScoreOrderId = json.getString("payScoreOrderId");
            String payScoreState = json.getString("payScoreState");
            String serviceId = json.getString("serviceId");

            if (payScoreOrderId != null) {
                order.setPayScoreOrderId(payScoreOrderId);
                order.setPayScoreState(payScoreState != null ? payScoreState : PayScoreState.CREATED.getCode());
                order.setServiceId(serviceId);
                order.setPayChannel(PaymentChannel.WECHAT_PAYSCORE.getCode());
                order.setPayType("微信支付分");
                orderService.updateById(order);

                // 删除 Redis 记录，防止重复使用
                stringRedisTemplate.delete(redisKey);
                // 从追踪 SET 中移除，订单已正常关联不再需要清理
                stringRedisTemplate.opsForSet().remove(REDIS_TRACKING_KEY + order.getUserId(), payScoreOrderId);
                log.info("[支付分服务] 预授权信息已关联到订单 - orderId: {}, payScoreOrderId: {}", order.getId(), payScoreOrderId);
            } else {
                log.warn("[支付分服务] 预授权JSON中payScoreOrderId为null - key: {}, json: {}", redisKey, jsonStr);
            }
        } catch (Exception e) {
            log.error("[支付分服务] 关联预授权信息失败 - orderId: {}", order.getId(), e);
        }
    }

    /**
     * 从 Redis 读取预授权信息（只读不删，用于订单创建前提前获取支付分信息）
     */
    public JSONObject readPreAuthFromRedis(String deviceId, Long userId) {
        if (stringRedisTemplate == null) {
            return null;
        }
        String redisKey = REDIS_KEY_PREFIX + deviceId + ":" + userId;
        String jsonStr = stringRedisTemplate.opsForValue().get(redisKey);
        if (jsonStr == null) {
            return null;
        }
        try {
            return JSON.parseObject(jsonStr);
        } catch (Exception e) {
            log.warn("[支付分服务] 解析预授权信息失败 - key: {}", redisKey, e);
            return null;
        }
    }

    /**
     * 从 Redis 追踪 SET 中尝试恢复丢失的 payScoreOrderId
     * outOrderNo 格式为 PS{timestamp}{deviceIdSuffix}，通过 deviceId 后缀匹配
     *
     * @return 恢复的 payScoreOrderId，未找到返回 null
     */
    @Override
    public String tryRecoverPayScoreOrderId(Long userId, String deviceId) {
        if (stringRedisTemplate == null || userId == null || deviceId == null) {
            return null;
        }
        try {
            // 1. 先查 pre-auth key（最快）
            JSONObject preAuth = readPreAuthFromRedis(deviceId, userId);
            if (preAuth != null) {
                String id = preAuth.getString("payScoreOrderId");
                if (id != null) {
                    log.info("[支付分服务] 从pre-auth恢复 payScoreOrderId - userId: {}, deviceId: {}, id: {}", userId, deviceId, id);
                    return id;
                }
            }

            // 2. pre-auth key 不在了，查追踪 SET
            String trackingKey = REDIS_TRACKING_KEY + userId;
            java.util.Set<String> tracked = stringRedisTemplate.opsForSet().members(trackingKey);
            if (tracked != null && !tracked.isEmpty()) {
                // outOrderNo 格式: PS{timestamp}{deviceIdSuffix}
                // deviceId 如 B150534 → suffix 为 B150534 (转安全格式后的后10位)
                String safeDeviceId = deviceId.replaceAll("[^A-Za-z0-9]", "");
                String suffix = safeDeviceId.length() > 10
                        ? safeDeviceId.substring(safeDeviceId.length() - 10) : safeDeviceId;

                String matched = tracked.stream()
                        .filter(outOrderNo -> outOrderNo != null && outOrderNo.endsWith(suffix))
                        .findFirst().orElse(null);
                if (matched != null) {
                    log.info("[支付分服务] 从追踪SET恢复 payScoreOrderId - userId: {}, deviceId: {}, id: {}", userId, deviceId, matched);
                    return matched;
                }
            }
        } catch (Exception e) {
            log.warn("[支付分服务] 恢复 payScoreOrderId 异常 - userId: {}, deviceId: {}", userId, deviceId, e);
        }
        return null;
    }

    @Override
    public String getServiceId() {
        return wxPayConfig != null ? wxPayConfig.getServiceId() : null;
    }

    @Override
    public Map<String, String> getPreAuthInfo(String deviceId, Long userId) {
        JSONObject preAuth = readPreAuthFromRedis(deviceId, userId);
        if (preAuth == null) {
            return null;
        }
        Map<String, String> result = new HashMap<>();
        result.put("payScoreOrderId", preAuth.getString("payScoreOrderId"));
        result.put("payScoreState", preAuth.getString("payScoreState"));
        result.put("serviceId", preAuth.getString("serviceId"));
        return result;
    }

    /**
     * 清理用户旧的进行中支付分订单，确保不超过微信支付分 3 笔限额。
     *
     * 分级策略（按优先级从高到低）：
     * 1. 自动补扣：有金额(>0) 且 创建超过 1 分钟的订单 → 直接扣款，不损失资金
     * 2. 取消未确认：CREATED 状态（用户从未授权） → 安全取消
     * 3. 取消超时孤儿：DOING/USER_PAYING + 金额为空 + 超过 30 分钟 → 异常单清理
     * 4. Redis 追踪清理：同设备旧的预创建订单
     *
     * @return 清理后用户剩余的未完结支付分订单数量
     */
    private int cancelStalePayScoreOrdersAndCount(Long userId, String deviceId) {
        // 1. 自动补扣：有金额的待支付订单（>1min 避免与 ORDER 回调竞态）
        try {
            java.time.LocalDateTime autoCompleteThreshold = java.time.LocalDateTime.now().minusMinutes(1);
            List<Order> readyOrders = orderService.lambdaQuery()
                    .eq(Order::getUserId, userId)
                    .eq(Order::getPayChannel, PaymentChannel.WECHAT_PAYSCORE.getCode())
                    .in(Order::getPayScoreState, Arrays.asList(
                            PayScoreState.DOING.getCode(),
                            PayScoreState.USER_PAYING.getCode()))
                    .isNotNull(Order::getPayScoreOrderId)
                    .gt(Order::getTotalAmount, BigDecimal.ZERO)
                    .le(Order::getCreateTime, autoCompleteThreshold)
                    .list();

            if (readyOrders != null && !readyOrders.isEmpty()) {
                log.info("[支付分服务] 自动补扣用户 {} 的 {} 笔待支付订单", userId, readyOrders.size());
                for (Order order : readyOrders) {
                    try {
                        orderService.completeOrderWithPayScore(order.getId(), order.getTotalAmount());
                    } catch (Exception e) {
                        log.error("[支付分服务] 自动补扣失败 - orderId: {}, orderNo: {}", order.getId(), order.getOrderNo(), e);
                    }
                }
            }
        } catch (Exception e) {
            log.error("[支付分服务] 自动补扣查询失败 - userId: {}", userId, e);
        }

        // 2. 取消 CREATED 状态的孤儿订单（用户从未授权使用，不会损失资金）
        try {
            List<Order> inProgressOrders = orderService.lambdaQuery()
                    .eq(Order::getUserId, userId)
                    .eq(Order::getPayChannel, PaymentChannel.WECHAT_PAYSCORE.getCode())
                    .eq(Order::getPayScoreState, PayScoreState.CREATED.getCode())
                    .isNotNull(Order::getPayScoreOrderId)
                    .list();

            if (inProgressOrders != null && !inProgressOrders.isEmpty()) {
                log.info("[支付分服务] 清理用户 {} 的 {} 笔CREATED状态订单", userId, inProgressOrders.size());
                for (Order order : inProgressOrders) {
                    cancelPayScoreOrderByOutOrderNo(order.getPayScoreOrderId(), order.getId());
                }
            }
        } catch (Exception e) {
            log.error("[支付分服务] 清理CREATED订单失败 - userId: {}", userId, e);
        }

        // 3. 取消超时孤儿：DOING/USER_PAYING + 金额为空 + 超过 30 分钟
        //    仅清理回调签名失败等异常造成的遗留订单，正常等待 ORDER 回调的不受影响
        try {
            java.time.LocalDateTime staleThreshold = java.time.LocalDateTime.now().minusMinutes(30);
            List<Order> stuckOrders = orderService.lambdaQuery()
                    .eq(Order::getUserId, userId)
                    .eq(Order::getPayChannel, PaymentChannel.WECHAT_PAYSCORE.getCode())
                    .in(Order::getPayScoreState, Arrays.asList(
                            PayScoreState.DOING.getCode(),
                            PayScoreState.USER_PAYING.getCode()))
                    .isNotNull(Order::getPayScoreOrderId)
                    .and(w -> w.isNull(Order::getTotalAmount).or().le(Order::getTotalAmount, BigDecimal.ZERO))
                    .le(Order::getCreateTime, staleThreshold)
                    .list();

            if (stuckOrders != null && !stuckOrders.isEmpty()) {
                log.info("[支付分服务] 清理用户 {} 的 {} 笔超时孤儿订单(>30min)", userId, stuckOrders.size());
                for (Order order : stuckOrders) {
                    cancelPayScoreOrderByOutOrderNo(order.getPayScoreOrderId(), order.getId());
                }
            }
        } catch (Exception e) {
            log.error("[支付分服务] 清理超时孤儿订单失败 - userId: {}", userId, e);
        }

        // 4. 取消 Redis 追踪的预创建订单（之前未完成购物流程留下的）
        if (stringRedisTemplate != null) {
            try {
                String trackingKey = REDIS_TRACKING_KEY + userId;
                java.util.Set<String> trackedOrders = stringRedisTemplate.opsForSet().members(trackingKey);
                if (trackedOrders != null && !trackedOrders.isEmpty()) {
                    log.info("[支付分服务] 清理用户 {} 的 {} 笔追踪预创建订单", userId, trackedOrders.size());
                    for (String outOrderNo : trackedOrders) {
                        if (outOrderNo != null && !outOrderNo.isEmpty()) {
                            if (!isPayScoreOrderSafeToCancel(outOrderNo)) {
                                log.info("[支付分服务] 跳过取消已确认的支付分订单 - outOrderNo: {}", outOrderNo);
                                continue;
                            }
                            cancelPayScoreOrderByOutOrderNo(outOrderNo, null);
                            stringRedisTemplate.opsForSet().remove(trackingKey, outOrderNo);
                        }
                    }
                }
            } catch (Exception e) {
                log.error("[支付分服务] 清理Redis追踪订单失败 - userId: {}", userId, e);
            }
        }

        // 统计清理后剩余的未完结订单数
        return countActivePayScoreOrders(userId);
    }

    /**
     * 统计用户当前未完结的支付分订单数量（DB 维度）
     */
    private int countActivePayScoreOrders(Long userId) {
        try {
            Long count = orderService.lambdaQuery()
                    .eq(Order::getUserId, userId)
                    .eq(Order::getPayChannel, PaymentChannel.WECHAT_PAYSCORE.getCode())
                    .in(Order::getPayScoreState, Arrays.asList(
                            PayScoreState.CREATED.getCode(),
                            PayScoreState.DOING.getCode(),
                            PayScoreState.USER_PAYING.getCode()))
                    .isNotNull(Order::getPayScoreOrderId)
                    .count();
            return count != null ? count.intValue() : 0;
        } catch (Exception e) {
            log.warn("[支付分服务] 统计未完结订单失败 - userId: {}", userId, e);
            return 99; // 保守值，宁可拒绝也不要超标
        }
    }

    /** @deprecated 由 cancelStalePayScoreOrdersAndCount 替代 */
    private void cancelStalePayScoreOrders(Long userId, String deviceId) {
        cancelStalePayScoreOrdersAndCount(userId, deviceId);
    }

    private void cancelPayScoreOrderByOutOrderNo(String outOrderNo, Long localOrderId) {
        try {
            PayScoreCancelRequest cancelReq = new PayScoreCancelRequest();
            cancelReq.setOutOrderNo(outOrderNo);
            cancelReq.setReason("新订单创建前自动取消旧订单");
            PayScoreResult cancelResult = payScoreStrategy.cancelServiceOrder(cancelReq);

            if (cancelResult.isSuccess()) {
                log.info("[支付分服务] 取消成功 - outOrderNo: {}", outOrderNo);
                markOrderRevoked(localOrderId);
            } else if (cancelResult.getErrorMsg() != null
                    && cancelResult.getErrorMsg().contains("ORDER_NOT_EXIST")) {
                // 微信侧已不存在，同步清理本地状态，避免反复尝试
                log.debug("[支付分服务] 微信侧已不存在，清理本地记录 - outOrderNo: {}", outOrderNo);
                markOrderRevoked(localOrderId);
            }
        } catch (Exception e) {
            // 网络异常等，微信侧可能已取消成功，保守清理本地状态
            log.debug("[支付分服务] 取消异常，清理本地记录 - outOrderNo: {}", outOrderNo);
            markOrderRevoked(localOrderId);
        }
    }

    private void markOrderRevoked(Long localOrderId) {
        if (localOrderId == null) {
            return;
        }
        try {
            Order order = orderService.getById(localOrderId);
            if (order != null && !PayScoreState.isFinished(order.getPayScoreState())) {
                order.setPayScoreState(PayScoreState.REVOKED.getCode());
                orderService.updateById(order);
            }
        } catch (Exception e) {
            log.warn("[支付分服务] 更新本地订单状态失败 - orderId: {}", localOrderId, e);
        }
    }

    /**
     * 将预创建的 outOrderNo 记录到 Redis SET，回调正常关联后自动移除
     */
    private void trackPreAuthOrder(Long userId, String outOrderNo) {
        if (stringRedisTemplate == null) {
            return;
        }
        try {
            String trackingKey = REDIS_TRACKING_KEY + userId;
            stringRedisTemplate.opsForSet().add(trackingKey, outOrderNo);
            stringRedisTemplate.expire(trackingKey, REDIS_TRACKING_TTL_HOURS, TimeUnit.HOURS);
        } catch (Exception e) {
            log.warn("[支付分服务] 追踪订单失败 - outOrderNo: {}", outOrderNo, e);
        }
    }

    /**
     * 取消同设备旧的预创建订单（已被本次新订单替代）
     * 必须检查关联的本地订单状态，避免误取消已确认/正在扣款的订单
     */
    private void cancelOldDeviceOrders(Long userId, String deviceId, String currentOutOrderNo) {
        if (stringRedisTemplate == null) {
            return;
        }
        try {
            String safeDeviceId = deviceId.replaceAll("[^A-Za-z0-9]", "");
            String suffix = safeDeviceId.length() > 10 ? safeDeviceId.substring(safeDeviceId.length() - 10) : safeDeviceId;
            String trackingKey = REDIS_TRACKING_KEY + userId;
            java.util.Set<String> tracked = stringRedisTemplate.opsForSet().members(trackingKey);
            if (tracked != null) {
                for (String outOrderNo : tracked) {
                    if (outOrderNo != null && outOrderNo.endsWith(suffix) && !outOrderNo.equals(currentOutOrderNo)) {
                        if (!isPayScoreOrderSafeToCancel(outOrderNo)) {
                            log.info("[支付分服务] 跳过取消同设备已确认的支付分订单 - outOrderNo: {}, deviceId: {}", outOrderNo, deviceId);
                            continue;
                        }
                        cancelPayScoreOrderByOutOrderNo(outOrderNo, null);
                        stringRedisTemplate.opsForSet().remove(trackingKey, outOrderNo);
                    }
                }
            }
        } catch (Exception e) {
            log.warn("[支付分服务] 清理设备旧追踪失败 - deviceId: {}", deviceId, e);
        }
    }

    /**
     * 检查支付分订单是否可以安全取消
     * 已确认(DOING)或正在扣款(USER_PAYING)或已完成(DONE)的订单不应被取消
     *
     * @return true 可以安全取消（本地无订单或仅 CREATED 状态），false 不可取消
     */
    private boolean isPayScoreOrderSafeToCancel(String outOrderNo) {
        try {
            Order localOrder = orderService.lambdaQuery()
                    .eq(Order::getPayScoreOrderId, outOrderNo)
                    .one();
            if (localOrder == null) {
                // 没有关联的本地订单，可以安全取消（只是预创建的支付分记录）
                return true;
            }
            String state = localOrder.getPayScoreState();
            if (PayScoreState.CREATED.getCode().equals(state)) {
                // CREATED 状态的订单（用户从未确认），可以取消
                return true;
            }
            // DOING / USER_PAYING / DONE 状态的订单不可取消
            log.warn("[支付分服务] 支付分订单已确认不可取消 - outOrderNo: {}, payScoreState: {}, orderId: {}",
                    outOrderNo, state, localOrder.getId());
            return false;
        } catch (Exception e) {
            log.warn("[支付分服务] 检查支付分订单状态失败 - outOrderNo: {}", outOrderNo, e);
            // 查询失败时保守处理：不取消，避免误伤
            return false;
        }
    }
}
