package com.haha.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.haha.common.constant.OrderConstants;
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.config.CommonConfig;
import com.haha.common.enums.UserTag;
import com.haha.common.utils.EntityLabelUtils;
import com.haha.common.utils.OrderUtils;
import com.haha.common.vo.OrderItemVO;
import com.haha.common.vo.OrderStatisticsVO;
import com.haha.common.vo.OrderVO;
import com.haha.entity.Device;
import com.haha.entity.Order;
import com.haha.entity.OrderGoods;
import com.haha.entity.Shop;
import com.haha.entity.User;
import com.haha.mapper.DeviceMapper;
import com.haha.mapper.OrderGoodsMapper;
import com.haha.mapper.OrderMapper;
import com.haha.mapper.ShopMapper;
import com.haha.mapper.UserMapper;
import com.haha.service.UserTagService;
import com.haha.service.OrderGoodsService;
import com.haha.service.RefundService;
import com.haha.service.OrderService;
import com.haha.service.InviteActivityService;
import com.haha.service.payment.PaymentService;
import com.haha.service.payment.RefundResult;
import com.haha.service.payment.payscore.PayScoreCreateRequest;
import com.haha.service.payment.payscore.PayScoreResult;
import com.haha.service.payment.payscore.PayScoreService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    private final DeviceMapper deviceMapper;
    private final ShopMapper shopMapper;
    private final UserMapper userMapper;
    private final CommonConfig commonConfig;
    private final UserTagService userTagService;

    @Autowired
    @Lazy
    private PaymentService paymentService;

    @Autowired
    @Lazy
    private PayScoreService payScoreService;

    @Autowired
    @Lazy
    private RefundService refundService;

    @Autowired
    @Lazy
    private OrderGoodsService orderGoodsService;

    @Autowired
    @Lazy
    private InviteActivityService inviteActivityService;

    @Autowired(required = false)
    private com.haha.sdk.HahaClient hahaClient;

    @Autowired
    @Lazy
    private OrderGoodsMapper orderGoodsMapper;

    @Autowired
    @Lazy
    private com.haha.service.ProductService productService;

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

    @Override
    public IPage<Order> getPage(int page, int pageSize, String orderNo, String deviceId,
                                 String payStatus, Integer status, String startDate, String endDate,
                                 List<Integer> statusList) {
        return getPage(page, pageSize, orderNo, deviceId, payStatus, status, startDate, endDate, statusList, null);
    }

    @Override
    public IPage<Order> getPage(int page, int pageSize, String orderNo, String deviceId,
                                 String payStatus, Integer status, String startDate, String endDate,
                                 List<Integer> statusList, String phone) {
        // 确保分页参数有效（MyBatis-Plus 要求页码从 1 开始）
        if (page < 1) {
            page = 1;
        }
        if (pageSize < 1 || pageSize > 100) {
            pageSize = 10;  // 默认每页 10 条，最大 100 条
        }

        log.info("订单分页查询：page={}, pageSize={}, orderNo={}, deviceId={}, phone={}", page, pageSize, orderNo, deviceId, phone);

        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();

        // 手机号查询：先根据手机号查出用户ID，再按用户ID过滤订单
        List<Long> userIdsByPhone = null;
        if (phone != null && !phone.isEmpty()) {
            LambdaQueryWrapper<User> userWrapper = new LambdaQueryWrapper<>();
            userWrapper.like(User::getPhone, phone);
            List<User> users = userMapper.selectList(userWrapper);
            if (users != null && !users.isEmpty()) {
                userIdsByPhone = users.stream().map(User::getId).collect(Collectors.toList());
                wrapper.in(Order::getUserId, userIdsByPhone);
            } else {
                // 没有匹配到用户，返回空结果
                return new Page<>(page, pageSize);
            }
        }

        // 构建其他查询条件
        wrapper.like(orderNo != null && !orderNo.isEmpty(), Order::getOrderNo, orderNo)
               .like(deviceId != null && !deviceId.isEmpty(), Order::getDeviceId, deviceId)
               .eq(payStatus != null && !payStatus.isEmpty(), Order::getPayStatus, payStatus)
               .eq(status != null, Order::getStatus, status)
               .in(statusList != null && !statusList.isEmpty(), Order::getStatus, statusList);

        // 时间范围查询
        if (startDate != null && !startDate.isEmpty()) {
            LocalDateTime startDateTime = LocalDate.parse(startDate).atStartOfDay();
            wrapper.ge(Order::getCreateTime, startDateTime);
        }
        if (endDate != null && !endDate.isEmpty()) {
            LocalDateTime endDateTime = LocalDate.parse(endDate).atTime(LocalTime.MAX);
            wrapper.le(Order::getCreateTime, endDateTime);
        }

        // 按创建时间倒序
        wrapper.orderByDesc(Order::getCreateTime);

        // 分页查询
        IPage<Order> orderPage = this.page(new Page<>(page, pageSize), wrapper);

        // 批量填充标签字段和关联信息（含用户消费标签）
        fillOrderLabels(orderPage.getRecords());

        return orderPage;
    }

    @Override
    public Order getDetailById(Long id) {
        Order order = this.getById(id);
        if (order == null) {
            return null;
        }
        fillOrderLabels(List.of(order));
        return order;
    }

    @Override
    public OrderVO getDetailVOById(Long id) {
        Order order = this.getById(id);
        if (order == null) {
            return null;
        }

        // 填充关联标签信息（门店名称、设备名称等）
        fillOrderLabels(List.of(order));

        OrderVO vo = new OrderVO();
        vo.setId(order.getId());
        vo.setOrderNo(order.getOrderNo());
        vo.setOrderName(order.getOrderName());
        vo.setOutTradeNo(order.getOutTradeNo());
        vo.setActivityId(order.getActivityId());
        vo.setDeviceId(order.getDeviceId());
        vo.setTotalAmount(order.getTotalAmount());
        vo.setDiscountAmount(order.getDiscountAmount());
        vo.setPaidAmount(order.getPaidAmount());
        vo.setPayStatus(order.getPayStatus());
        vo.setPayStatusLabel(getPayStatusLabel(order.getPayStatus()));
        vo.setStatus(order.getStatus());
        vo.setStatusText(getStatusLabel(order.getStatus()));
        vo.setCreateTime(order.getCreateTime());
        vo.setPayTime(order.getPayTime());
        vo.setVideoUrl(order.getVideoUrl());
        vo.setConfidence(order.getConfidence());
        vo.setShopName(order.getStoreName() != null ? order.getStoreName() : order.getShopName());
        vo.setDeviceName(order.getDeviceName());
        vo.setPayType(order.getPayType());

        List<OrderItemVO> products = orderGoodsService.getVOByOrderId(id);

        // 填充每个商品的已退款数量
        if (refundService != null && !products.isEmpty()) {
            Map<Long, Integer> refundedQtyMap = refundService.getRefundedQuantityMap(id);
            for (OrderItemVO p : products) {
                p.setRefundedQuantity(refundedQtyMap.getOrDefault(p.getId(), 0));
            }
        }

        vo.setProducts(products);

        // 填充用户消费标签
        if (order.getUserId() != null) {
            Map<Long, UserTag> tagMap = userTagService.batchComputeUserTags(List.of(order.getUserId()));
            UserTag tag = tagMap.get(order.getUserId());
            if (tag != null) {
                vo.setUserTag(tag.getCode());
                vo.setUserTagLabel(tag.getDescription());
            }
        }

        return vo;
    }

    private String getPayStatusLabel(String payStatus) {
        if (payStatus == null) {
            return "未知";
        }
        switch (payStatus) {
            case OrderConstants.PAY_STATUS_UNPAID:
                return "未支付";
            case OrderConstants.PAY_STATUS_PAID:
                return "已支付";
            case OrderConstants.PAY_STATUS_PARTIAL_REFUND:
                return "部分退款";
            case OrderConstants.PAY_STATUS_REFUND:
                return "全额退款";
            default:
                return "未知";
        }
    }

    private String getStatusLabel(Integer status) {
        if (status == null) {
            return "未知";
        }
        switch (status) {
            case OrderConstants.STATUS_PENDING_PAYMENT:
                return "待支付";
            case OrderConstants.STATUS_COMPLETED:
                return "已完成";
            case OrderConstants.STATUS_CANCELLED:
                return "已取消";
            case OrderConstants.STATUS_CLOSED:
                return "已关闭";
            default:
                return "未知";
        }
    }

    @Override
    public OrderStatisticsVO getStatistics(String startDate, String endDate) {
        LocalDateTime startDateTime = null;
        LocalDateTime endDateTime = null;
        if (startDate != null && !startDate.isEmpty()) {
            startDateTime = LocalDate.parse(startDate).atStartOfDay();
        }
        if (endDate != null && !endDate.isEmpty()) {
            endDateTime = LocalDate.parse(endDate).atTime(LocalTime.MAX);
        }

        // 时间范围内的订单总数
        Long totalOrders = baseMapper.countByDateRange(startDateTime, endDateTime);

        // 时间范围内的已完成订单数
        Long completedOrders = baseMapper.countCompletedByDateRange(startDateTime, endDateTime);

        // 时间范围内的已退款订单数
        Long refundOrders = baseMapper.countRefundedByDateRange(startDateTime, endDateTime);

        // 时间范围内的总销售额（所有已完成订单）
        BigDecimal totalAmount = baseMapper.sumCompletedOrderAmount(startDateTime);
        if (endDateTime != null) {
            totalAmount = baseMapper.selectObjs(
                new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<Order>()
                    .eq(Order::getStatus, OrderConstants.STATUS_COMPLETED)
                    .eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID)
                    .ge(startDateTime != null, Order::getCreateTime, startDateTime)
                    .le(endDateTime != null, Order::getCreateTime, endDateTime)
                    .select(Order::getPaidAmount)
            ).stream()
                .map(obj -> obj instanceof BigDecimal ? (BigDecimal) obj : BigDecimal.ZERO)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        }

        // 按支付渠道统计金额
        List<Map<String, Object>> channelStats = baseMapper.sumAmountByChannel(startDateTime, endDateTime);
        BigDecimal wechatAmount = BigDecimal.ZERO;
        BigDecimal alipayAmount = BigDecimal.ZERO;
        BigDecimal otherAmount = BigDecimal.ZERO;

        if (channelStats != null) {
            for (Map<String, Object> stat : channelStats) {
                String channel = (String) stat.get("channel");
                BigDecimal amount = stat.get("amount") instanceof BigDecimal
                        ? (BigDecimal) stat.get("amount")
                        : new BigDecimal(stat.get("amount").toString());
                if (channel == null) {
                    otherAmount = otherAmount.add(amount);
                    continue;
                }
                String lowerChannel = channel.toLowerCase();
                if (lowerChannel.contains(PaymentChannel.WECHAT.getCode())) {
                    wechatAmount = wechatAmount.add(amount);
                } else if (lowerChannel.contains(PaymentChannel.ALIPAY.getCode())) {
                    alipayAmount = alipayAmount.add(amount);
                } else {
                    otherAmount = otherAmount.add(amount);
                }
            }
        }

        return OrderStatisticsVO.builder()
                .totalOrders(totalOrders != null ? totalOrders : 0)
                .completedOrders(completedOrders != null ? completedOrders : 0)
                .refundOrders(refundOrders != null ? refundOrders : 0)
                .totalAmount(totalAmount != null ? totalAmount.setScale(2, RoundingMode.HALF_UP).toString() : "0.00")
                .wechatAmount(wechatAmount.setScale(2, RoundingMode.HALF_UP).toString())
                .alipayAmount(alipayAmount.setScale(2, RoundingMode.HALF_UP).toString())
                .otherAmount(otherAmount.setScale(2, RoundingMode.HALF_UP).toString())
                .build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean refund(Long orderId, String reason) {
        // 委托给 PaymentService 处理退款
        // PaymentService.refund() 内部已经处理了：
        // - 订单状态校验
        // - 调用第三方退款 API
        // - 更新退款状态和支付状态
        RefundResult result = paymentService.refund(orderId, reason);
        return result.isSuccess();
    }

    @Override
    public List<Order> getOrderListByUserId(Long userId, Integer status) {
        if (status != null) {
            return lambdaQuery()
                .eq(Order::getUserId, userId)
                .eq(Order::getStatus, status)
                .ne(Order::getOrderType, OrderConstants.ORDER_TYPE_IN)
                .orderByDesc(Order::getId)
                .list();
        } else {
            return lambdaQuery()
                .eq(Order::getUserId, userId)
                .ne(Order::getOrderType, OrderConstants.ORDER_TYPE_IN)
                .orderByDesc(Order::getId)
                .list();
        }
    }

    @Override
    public boolean cancelOrder(Long orderId) {
        return lambdaUpdate().eq(Order::getId, orderId).set(Order::getStatus, OrderConstants.STATUS_CANCELLED).update();
    }

    @Override
    public boolean updateOrderStatus(Long orderId, Integer status) {
        return lambdaUpdate().eq(Order::getId, orderId).set(Order::getStatus, status).update();
    }

    @Override
    public Order getOrderByOutTradeNo(String outTradeNo) {
        return lambdaQuery().eq(Order::getOutTradeNo, outTradeNo).one();
    }

    @Override
    public Order getOrderBydeviceId(String deviceId) {
        return lambdaQuery().eq(Order::getDeviceId, deviceId).orderByDesc(Order::getCreateTime).one();
    }

    @Override
    public Order getOrderByActivityId(String activityId) {
        if (activityId == null || activityId.isEmpty()) {
            return null;
        }
        return lambdaQuery().eq(Order::getActivityId, activityId).one();
    }

    @Override
    public boolean updatePayStatus(String orderNo, String payStatus) {
        boolean updated = lambdaUpdate().eq(Order::getOrderNo, orderNo).set(Order::getPayStatus, payStatus).update();
        if (updated && (OrderConstants.PAY_STATUS_PAID.equals(payStatus)
                || OrderConstants.PAY_STATUS_REFUND.equals(payStatus)
                || OrderConstants.PAY_STATUS_PARTIAL_REFUND.equals(payStatus))) {
            notifyHahaOrderStatusChanged(orderNo);
        }
        return updated;
    }

    @Override
    public void notifyHahaOrderStatusChanged(String orderNo) {
        if (hahaClient == null || orderNo == null || orderNo.isEmpty()) {
            return;
        }
        try {
            // 优先使用哈哈平台的 orderId，本地 orderNo 作为 fallback
            Order order = lambdaQuery().eq(Order::getOrderNo, orderNo).one();
            String hahaRef = (order != null && order.getHahaOrderId() != null && !order.getHahaOrderId().isEmpty())
                    ? order.getHahaOrderId() : orderNo;
            hahaClient.getOrderApi().setPayStatus(hahaRef);
            log.info("订单状态已同步到哈哈平台 - hahaRef: {}, localOrderNo: {}", hahaRef, orderNo);
        } catch (Exception e) {
            log.error("同步订单状态到哈哈平台失败 - orderNo: {}", orderNo, e);
        }
    }

    /**
     * 从AI识别结果创建订单
     *
     * 业务流程：
     * 1. 幂等性检查：防止重复创建订单
     * 2. 保存商品识别信息（此时不计算金额，因为AI识别结果不包含价格）
     * 3. 解析视频URL等资源信息
     * 4. 创建订单记录，状态为待支付，金额为0（等待订单回调时由设备端提供实付金额）
     *
     * 注意：
     * - AI识别结果（sku_list）只包含商品编码(code)和数量(quantity)，不包含价格
     * - 商品价格在订单回调时由设备端计算并传来
     * - 此方法只创建订单框架，实际金额在handleOrderCallback中更新
     *
     * @param activityId 活动ID（设备开门会话ID）
     * @param deviceId 设备ID
     * @param userId 用户ID
     * @param skuListStr 商品列表JSON字符串，格式：[{"code":"C001","quantity":2}]（不包含price）
     * @param resourceInfoStr 资源信息JSON字符串，包含视频URL等
     * @param confidence AI识别置信度
     * @return 创建的订单对象，失败返回null
     */
    @Override
    @Transactional
    public Order createOrderFromRecognition(String activityId, String deviceId, String userId,
                                             String skuListStr, String resourceInfoStr, BigDecimal confidence) {
        // 【步骤1】幂等性检查：如果该activityId已存在订单，直接返回，避免重复创建
        if (activityId != null && !activityId.isEmpty()) {
            Order existingOrder = getOrderByActivityId(activityId);
            if (existingOrder != null) {
                log.info("订单已存在，跳过创建 - activityId: {}, orderId: {}", activityId, existingOrder.getId());
                return existingOrder;
            }
        }

        // 【步骤2】解析视频URL等资源信息
        String videoUrl = null;
        if (resourceInfoStr != null && !resourceInfoStr.isEmpty()) {
            JSONObject resourceInfo = JSON.parseObject(resourceInfoStr);
            videoUrl = resourceInfo.getString("video_url");
        }

        // 【步骤3】创建订单记录
        // 注意：
        // 1. AI识别结果不包含商品价格，只包含商品编码和数量
        // 2. 此时订单金额设为0（或NULL），等待设备端回调时更新为实付金额
        // 3. 设备端会根据商品编码查询价格，并计算优惠后得到最终实付金额
        if (userId != null && deviceId != null) {
            Order order = new Order();
            order.setOrderNo(OrderUtils.getOrderNo());
            order.setActivityId(activityId);                          // 开门会话ID
            order.setUserId(Long.parseLong(userId));                  // 用户ID
            order.setDeviceId(deviceId);                              // 设备ID

            // 下单时写入门店信息，避免后续设备换门店导致历史订单门店失真
            try {
                Device device = deviceMapper.selectByDeviceId(deviceId);
                if (device != null && device.getShopId() != null) {
                    order.setShopId(device.getShopId());
                    Shop shop = shopMapper.selectById(device.getShopId());
                    if (shop != null) {
                        order.setStoreName(shop.getName());
                        order.setShopName(shop.getName());
                    }
                }
            } catch (Exception e) {
                log.warn("写入订单门店信息失败: deviceId={}", deviceId, e);
            }

            order.setTotalAmount(BigDecimal.ZERO);                    // 初始金额为0，等待回调更新
            order.setItems(skuListStr);                               // 商品列表JSON（包含code和quantity）
            order.setStatus(OrderConstants.STATUS_PENDING_PAYMENT);   // 订单状态：待支付
            order.setPayStatus(OrderConstants.PAY_STATUS_UNPAID);     // 支付状态：未支付
            order.setCreateTime(LocalDateTime.now());                 // 创建时间
            if (videoUrl != null) {
                order.setVideoUrl(videoUrl);                          // 购物视频URL
            }
            if (confidence != null) {
                order.setConfidence(confidence);                      // AI识别置信度
            }

            boolean saved = this.save(order);
            if (saved) {
                log.info("订单创建成功 - 订单ID: {}, 用户: {}, 等待回调更新金额", order.getId(), userId);
                return order;
            } else {
                log.error("订单创建失败 - 用户: {}, 设备: {}", userId, deviceId);
                return null;
            }
        } else {
            log.warn("订单创建跳过 - 缺少必要参数: userId={}, deviceId={}", userId, deviceId);
            return null;
        }
    }

    /**
     * 创建订单（带支付分预授权信息），支付分字段在 INSERT 时直接写入
     */
    public Order createOrderFromRecognition(String activityId, String deviceId, String userId,
                                             String skuListStr, String resourceInfoStr, BigDecimal confidence,
                                             String payScoreOrderId, String payScoreState, String serviceId) {
        Order order = createOrderFromRecognition(activityId, deviceId, userId, skuListStr, resourceInfoStr, confidence);
        if (order != null && payScoreOrderId != null) {
            order.setPayScoreOrderId(payScoreOrderId);
            order.setPayScoreState(payScoreState != null ? payScoreState : PayScoreState.CREATED.getCode());
            order.setServiceId(serviceId);
            order.setPayChannel(PaymentChannel.WECHAT_PAYSCORE.getCode());
            order.setPayType("微信支付分");
            this.updateById(order);
        }
        return order;
    }

    /**
     * 批量填充订单标签字段（含用户消费标签）
     * 优化：使用批量SQL预计算用户标签，避免N+1查询
     */
    private void fillOrderLabels(List<Order> orders) {
        if (orders == null || orders.isEmpty()) {
            return;
        }

        // 1. 批量计算用户消费标签
        List<Long> userIds = orders.stream()
                .map(Order::getUserId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        Map<Long, UserTag> userTagMap = userTagService.batchComputeUserTags(userIds);

        // 2. 批量查询用户信息（手机号）
        Map<Long, User> userMap = new HashMap<>();
        if (!userIds.isEmpty()) {
            List<User> users = userMapper.selectBatchIds(userIds);
            if (users != null) {
                userMap = users.stream().collect(Collectors.toMap(User::getId, u -> u, (a, b) -> a));
            }
        }

        // 3. 批量查询设备信息，避免循环内逐条查询（N+1）
        List<String> deviceIds = orders.stream()
                .map(Order::getDeviceId)
                .filter(id -> id != null && !id.isEmpty())
                .distinct()
                .collect(Collectors.toList());
        Map<String, Device> deviceMap = new HashMap<>();
        if (!deviceIds.isEmpty()) {
            List<Device> devices = deviceMapper.selectList(
                    new LambdaQueryWrapper<Device>().in(Device::getDeviceId, deviceIds));
            if (devices != null) {
                deviceMap = devices.stream().collect(Collectors.toMap(Device::getDeviceId, d -> d, (a, b) -> a));
            }
        }

        // 4. 批量查询门店信息（用于历史订单未写入 shopId 时回退查询）
        Map<Long, Shop> shopMap = new HashMap<>();
        List<Long> shopIds = deviceMap.values().stream()
                .map(Device::getShopId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        if (!shopIds.isEmpty()) {
            List<Shop> shops = shopMapper.selectBatchIds(shopIds);
            if (shops != null) {
                shopMap = shops.stream().collect(Collectors.toMap(Shop::getId, s -> s, (a, b) -> a));
            }
        }

        // 5. 逐条填充标签（使用预加载的 Map，无额外 SQL）
        for (Order order : orders) {
            // 用户消费标签 + 手机号
            if (order.getUserId() != null) {
                UserTag tag = userTagMap.get(order.getUserId());
                if (tag != null) {
                    order.setUserTag(tag.getCode());
                    order.setUserTagLabel(tag.getDescription());
                }
                // 填充手机号
                User user = userMap.get(order.getUserId());
                if (user != null) {
                    order.setPhone(user.getPhone());
                }
            }

            // 支付状态标签
            if (order.getPayStatus() != null) {
                var payLabel = EntityLabelUtils.getPayStatusLabel(order.getPayStatus());
                order.setPayStatusLabel(payLabel.getLabel());
            }
            // 订单状态标签
            if (order.getStatus() != null) {
                var statusLabel = EntityLabelUtils.getStatusLabel("order", order.getStatus());
                order.setStatusLabel(statusLabel.getLabel());
            }

            // 如果 payType 为空但 payChannel 有值，从 payChannel 获取描述
            if (order.getPayType() == null || order.getPayType().isEmpty()) {
                if (order.getPayChannel() != null && !order.getPayChannel().isEmpty()) {
                    PaymentChannel channel = PaymentChannel.fromCode(order.getPayChannel());
                    if (channel != null) {
                        order.setPayType(channel.getDescription());
                    }
                } else if (order.getOutTradeNo() != null && !order.getOutTradeNo().isEmpty()) {
                    order.setPayType("微信支付"); // 兼容旧数据
                } else if (PayStatus.isPaid(order.getPayStatus())) {
                    order.setPayType("免费");
                }
            }

            // 补充设备/门店名称（从预加载的Map取值，无额外SQL）
            if (order.getDeviceId() != null && !order.getDeviceId().isEmpty()) {
                Device device = deviceMap.get(order.getDeviceId());
                if (device != null) {
                    order.setDeviceName(device.getName());
                    // 历史订单未写入门店信息时，回退到 device→shop
                    if (order.getShopId() == null && device.getShopId() != null) {
                        order.setShopId(device.getShopId());
                        Shop shop = shopMap.get(device.getShopId());
                        if (shop != null) {
                            order.setShopName(shop.getName());
                            order.setStoreName(shop.getName());
                        }
                    }
                }
            }
        }
    }

    @Override
    @Transactional
    public Order createOrderWithPayScore(String activityId, String deviceId, String userId,
                                          String skuListStr, String resourceInfoStr, BigDecimal confidence,
                                          String openId) {
        Order order = createOrderFromRecognition(activityId, deviceId, userId,
                skuListStr, resourceInfoStr, confidence);

        if (order == null) {
            return null;
        }

        // 立即设置支付渠道，防止后续回调到达时 payChannel 为 null 而跳过扣费
        order.setPayChannel(PaymentChannel.WECHAT_PAYSCORE.getCode());
        order.setPayType("微信支付分");
        this.updateById(order);

        if (openId == null || openId.isEmpty()) {
            log.warn("[支付分集成] openId为空，跳过支付分服务订单创建 - orderId: {}", order.getId());
            return order;
        }

        try {
            PayScoreResult result = payScoreService.createPayScoreOrder(order.getId(), openId);

            if (result.isSuccess()) {
                log.info("[支付分集成] 支付分服务订单创建成功 - orderId: {}, outOrderNo: {}",
                        order.getId(), result.getOutOrderNo());
                order.setPayScoreOrderId(result.getOutOrderNo());
                order.setPayScoreState(result.getState());
                this.updateById(order);
            } else {
                log.warn("[支付分集成] 支付分服务订单创建失败 - orderId: {}, errorCode: {}, errorMsg: {}",
                        order.getId(), result.getErrorCode(), result.getErrorMsg());
            }
        } catch (Exception e) {
            log.error("[支付分集成] 支付分服务订单创建异常 - orderId: {}", order.getId(), e);
        }

        return order;
    }

    /**
     * 构建后付费项目列表（post_payments）
     * 从 order_goods 表查询已保存的商品，按微信支付分智慧零售规范构建
     * name="商品信息", description=商品名, amount=单价(元), count=数量
     */
    private List<PayScoreCreateRequest.PostPayment> buildPostPayments(Long orderId, BigDecimal totalAmount) {
        List<PayScoreCreateRequest.PostPayment> payments = new ArrayList<>();
        try {
            List<OrderGoods> goodsList = orderGoodsMapper.selectList(
                    new LambdaQueryWrapper<OrderGoods>()
                            .eq(OrderGoods::getOrderId, orderId));

            if (goodsList == null || goodsList.isEmpty()) {
                log.warn("未找到订单商品信息，使用订单金额构建fallback post_payments - orderId: {}", orderId);
                Order order = this.getById(orderId);
                if (order != null) {
                    PayScoreCreateRequest.PostPayment payment = new PayScoreCreateRequest.PostPayment();
                    payment.setName("商品信息");
                    payment.setAmount(order.getTotalAmount() != null ? order.getTotalAmount() : BigDecimal.ZERO);
                    payment.setDescription(order.getOrderName() != null ? order.getOrderName() : "商品");
                    payment.setCount(1);
                    payments.add(payment);
                }
                return payments;
            }

            for (OrderGoods goods : goodsList) {
                PayScoreCreateRequest.PostPayment payment = new PayScoreCreateRequest.PostPayment();
                payment.setName("商品信息");
                // amount 为行总金额（单价 × 数量），微信校验: total_amount = sum(post_payments[].amount)
                BigDecimal unitPrice = goods.getPrice() != null ? goods.getPrice()
                        : (goods.getMoney() != null ? goods.getMoney() : BigDecimal.ZERO);
                int quantity = goods.getProductNum() != null ? goods.getProductNum() : 1;
                payment.setAmount(unitPrice.multiply(BigDecimal.valueOf(quantity)));
                payment.setDescription(goods.getProductName() != null ? goods.getProductName() : "未知商品");
                payment.setCount(1);
                payments.add(payment);
            }

            // 修正四舍五入累计误差：确保 sum(post_payments) 严格等于 totalAmount
            if (totalAmount != null && !payments.isEmpty()) {
                BigDecimal sum = payments.stream()
                        .map(PayScoreCreateRequest.PostPayment::getAmount)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal diff = totalAmount.subtract(sum);
                if (diff.compareTo(BigDecimal.ZERO) != 0) {
                    PayScoreCreateRequest.PostPayment last = payments.get(payments.size() - 1);
                    last.setAmount(last.getAmount().add(diff));
                    log.info("post_payments余额平账: 商品sum={}, 订单total={}, 差额={}, 调整末项amount为{}",
                            sum, totalAmount, diff, last.getAmount());
                }
            }

            log.info("构建post_payments成功 - orderId: {}, 商品数量: {}", orderId, payments.size());
        } catch (Exception e) {
            log.error("构建post_payments失败 - orderId: {}", orderId, e);
        }
        return payments;
    }

    /**
     * 使用支付分完结订单（扣费）
     *
     * 业务流程：
     * 1. 验证订单是否存在
     * 2. 检查是否创建了支付分服务订单
     * 3. 调用微信支付分完结接口进行扣费
     * 4. 扣费成功后触发邀请激活逻辑（异步）
     *
     * 注意：
     * - 如果订单未使用支付分，直接更新订单状态
     * - 优惠金额已在设备端计算，totalAmount为实付金额
     *
     * @param orderId 订单ID
     * @param totalAmount 订单总金额（设备端已计算优惠后的实付金额）
     * @return 是否完结成功
     */
    @Override
    @Transactional
    public boolean completeOrderWithPayScore(Long orderId, BigDecimal totalAmount) {
        Order order = this.getById(orderId);
        if (order == null) {
            log.error("[支付分集成] 订单不存在 - orderId: {}", orderId);
            return false;
        }

        if (order.getPayScoreOrderId() == null) {
            log.warn("[支付分集成] 订单未创建支付分服务订单，直接更新状态 - orderId: {}", orderId);
            order.setTotalAmount(totalAmount);
            order.setPayStatus(PayStatus.PAID.getCode());
            order.setStatus(OrderStatus.COMPLETED.getCode());
            order.setPayTime(LocalDateTime.now());
            boolean updateResult = this.updateById(order);

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

            return updateResult;
        }

        try {
            List<PayScoreCreateRequest.PostPayment> payments = buildPostPayments(orderId, totalAmount);
            PayScoreResult result = payScoreService.completePayScoreOrder(orderId, totalAmount, payments);

            if (result.isSuccess()) {
                log.info("[支付分集成] 支付分完结成功 - orderId: {}, state: {}", orderId, result.getState());

                // 订单完成后异步触发邀请激活逻辑
                triggerInviteActivationAsync(order.getUserId(), orderId);

                return true;
            } else {
                log.error("[支付分集成] 支付分完结失败 - orderId: {}, errorCode: {}, errorMsg: {}",
                        orderId, result.getErrorCode(), result.getErrorMsg());
                return false;
            }
        } catch (Exception e) {
            log.error("[支付分集成] 支付分完结异常 - orderId: {}", orderId, e);
            return false;
        }
    }

    /**
     * 异步触发邀请活动激活
     * 当被邀请人完成首单后，自动激活邀请关系并发放奖励优惠券
     *
     * 使用 @Async 异步执行，避免阻塞订单主流程
     * 邀请激活失败不影响订单流程的正常运行
     *
     * @param userId  下单用户ID（被邀请人）
     * @param orderId 订单ID
     */
    @Async("taskExecutor")
    public void triggerInviteActivationAsync(Long userId, Long orderId) {
        try {
            log.info("[邀请激活] 收到订单完成事件，开始处理邀请激活 - orderId: {}, userId: {}", orderId, userId);

            // 调用邀请服务激活邀请记录并发放奖励
            boolean success = inviteActivityService.activateInviteRecord(userId, orderId);

            if (success) {
                log.info("[邀请激活] 邀请激活成功 - orderId: {}, userId: {}", orderId, userId);
            } else {
                log.warn("[邀请激活] 邀请激活失败或无待激活记录（可能该用户未被邀请或已激活）- orderId: {}, userId: {}", orderId, userId);
            }
        } catch (Exception e) {
            // 邀请激活异常不应影响订单流程，仅记录错误日志
            // 失败的奖励可以通过定时任务或手动补发来处理
            log.error("[邀请激活] 处理订单完成事件时发生异常 - orderId: {}, userId: {}", orderId, userId, e);
        }
    }

    // ==================== 用户端订单业务方法 ====================

    @Override
    public List<Map<String, Object>> getUserOrderListWithProducts(Long userId, Integer status) {
        List<Order> orders = getOrderListByUserId(userId, status);
        if (orders.isEmpty()) {
            return new ArrayList<>();
        }
        return buildOrderListBatch(orders);
    }

    @Override
    public List<Map<String, Object>> getUserOrderListWithProducts(Long userId, Map<String, Object> params) {
        Integer status = null;
        if (params != null && params.containsKey("status")) {
            status = Integer.valueOf(params.get("status").toString());
        }
        return getUserOrderListWithProducts(userId, status);
    }

    @Override
    public Map<String, Object> getUserOrderDetail(Long userId, Long orderId, String orderNo, String outTradeNo) {
        Order order = null;

        if (orderId != null) {
            order = this.getById(orderId);
        } else if (orderNo != null && !orderNo.isEmpty()) {
            order = this.lambdaQuery()
                .eq(Order::getOrderNo, orderNo)
                .one();
        } else if (outTradeNo != null && !outTradeNo.isEmpty()) {
            order = this.getOrderByOutTradeNo(outTradeNo);
        }

        if (order == null) {
            return null;
        }

        if (!order.getUserId().equals(userId)) {
            return null;
        }

        // IN类型订单不在用户端展示
        if (OrderConstants.ORDER_TYPE_IN.equals(order.getOrderType())) {
            return null;
        }

        // 补充设备名称；历史订单未写入门店信息时，回退到 device→shop 查询
        if (order.getDeviceId() != null && !order.getDeviceId().isEmpty()) {
            try {
                Device device = deviceMapper.selectByDeviceId(order.getDeviceId());
                if (device != null) {
                    order.setDeviceName(device.getName());
                    if (order.getShopId() == null && device.getShopId() != null) {
                        order.setShopId(device.getShopId());
                        Shop shop = shopMapper.selectById(device.getShopId());
                        if (shop != null) {
                            order.setShopName(shop.getName());
                            order.setStoreName(shop.getName());
                        }
                    }
                }
            } catch (Exception e) {
                log.warn("获取订单关联门店信息失败: orderId={}, deviceId={}", order.getId(), order.getDeviceId(), e);
            }
        }

        Map<String, Object> detail = buildOrderMap(order);
        detail.put("statusText", OrderConstants.getStatusDesc(order.getStatus()));

        // 加载退款申请记录
        try {
            if (refundService != null) {
                List<com.haha.entity.Refund> refundList = refundService.getByOrderId(order.getId());
                if (refundList != null && !refundList.isEmpty()) {
                    List<Map<String, Object>> refundRecords = new ArrayList<>();
                    for (com.haha.entity.Refund refund : refundList) {
                        Map<String, Object> record = new HashMap<>();
                        record.put("id", refund.getId());
                        record.put("refundNo", refund.getRefundNo());
                        record.put("refundAmount", refund.getRefundAmount());
                        record.put("status", refund.getStatus());
                        record.put("reason", refund.getReason());
                        record.put("remark", refund.getRemark());
                        record.put("createTime", refund.getCreateTime());
                        record.put("reviewTime", refund.getReviewTime());
                        // 加载退款商品明细
                        List<com.haha.entity.RefundItem> items = refundService.getRefundItems(refund.getId());
                        if (items != null && !items.isEmpty()) {
                            List<Map<String, Object>> itemMaps = new ArrayList<>();
                            for (com.haha.entity.RefundItem item : items) {
                                Map<String, Object> im = new HashMap<>();
                                im.put("productName", item.getProductName());
                                im.put("quantity", item.getQuantity());
                                im.put("price", item.getPrice());
                                im.put("refundAmount", item.getRefundAmount());
                                itemMaps.add(im);
                            }
                            record.put("items", itemMaps);
                        }
                        refundRecords.add(record);
                    }
                    detail.put("refunds", refundRecords);
                }
            }
        } catch (Exception e) {
            log.warn("加载订单 {} 退款记录失败: {}", order.getId(), e.getMessage());
        }

        return detail;
    }

    @Override
    public Map<String, Object> getUserOrderDetail(Long userId, Map<String, Object> params) {
        Long orderId = null;
        String orderNo = null;
        String outTradeNo = null;

        if (params.containsKey("orderId")) {
            orderId = Long.valueOf(params.get("orderId").toString());
        } else if (params.containsKey("orderNo")) {
            orderNo = params.get("orderNo").toString();
        } else if (params.containsKey("outTradeNo")) {
            outTradeNo = params.get("outTradeNo").toString();
        } else {
            return null;
        }

        return getUserOrderDetail(userId, orderId, orderNo, outTradeNo);
    }

    @Override
    public boolean cancelUserOrder(Long userId, Long orderId) {
        Order order = this.getById(orderId);
        if (order == null) {
            return false;
        }
        if (!order.getUserId().equals(userId)) {
            return false;
        }
        if (order.getStatus() != OrderConstants.STATUS_PENDING_PAYMENT) {
            return false;
        }
        return cancelOrder(orderId);
    }

    @Override
    public boolean cancelUserOrder(Long userId, Map<String, Object> params) {
        if (params == null || !params.containsKey("orderId")) {
            return false;
        }
        Long orderId = Long.valueOf(params.get("orderId").toString());
        return cancelUserOrder(userId, orderId);
    }

    /**
     * 批量构建订单列表（一次查询商品和退款数据，避免 N+1）
     */
    private List<Map<String, Object>> buildOrderListBatch(List<Order> orders) {
        List<Long> orderIds = orders.stream().map(Order::getId).collect(Collectors.toList());

        // 批量查询所有订单的商品
        Map<Long, List<OrderItemVO>> goodsMap = orderGoodsService.getVOByOrderIds(orderIds);

        // 批量查询所有订单的退款商品数量
        Map<Long, Map<Long, Integer>> refundQtyMap = null;
        if (refundService != null) {
            refundQtyMap = refundService.getRefundedQuantityMapByOrderIds(orderIds);
        }

        List<Map<String, Object>> orderList = new ArrayList<>();
        for (Order order : orders) {
            Map<String, Object> orderMap = buildOrderMapBase(order);
            List<OrderItemVO> goodsList = goodsMap.getOrDefault(order.getId(), new ArrayList<>());
            Map<Long, Integer> refundQtys = refundQtyMap != null
                    ? refundQtyMap.getOrDefault(order.getId(), new HashMap<>())
                    : new HashMap<>();
            orderMap.put("products", buildProductList(goodsList, refundQtys));
            orderList.add(orderMap);
        }
        return orderList;
    }

    /**
     * 构建订单Map基础字段（不含 products）
     */
    private Map<String, Object> buildOrderMapBase(Order order) {
        Map<String, Object> orderMap = new HashMap<>();
        orderMap.put("id", order.getId());
        orderMap.put("orderNo", order.getOrderNo());
        orderMap.put("orderName", order.getOrderName() != null ? order.getOrderName() : "");
        orderMap.put("outTradeNo", order.getOutTradeNo());
        orderMap.put("deviceId", order.getDeviceId());
        orderMap.put("storeName", order.getStoreName() != null ? order.getStoreName() : "");
        orderMap.put("totalAmount", order.getTotalAmount());
        orderMap.put("discountAmount", order.getDiscountAmount() != null ? order.getDiscountAmount() : 0);
        orderMap.put("paidAmount", order.getPaidAmount() != null ? order.getPaidAmount() : order.getTotalAmount());
        orderMap.put("payStatus", order.getPayStatus());
        orderMap.put("payChannel", order.getPayChannel());
        orderMap.put("status", order.getStatus());
        orderMap.put("createTime", order.getCreateTime());
        orderMap.put("payTime", order.getPayTime());
        orderMap.put("confidence", order.getConfidence());
        orderMap.put("refundStatus", order.getRefundStatus());
        orderMap.put("refundAmount", order.getRefundAmount());
        orderMap.put("currentRefundId", order.getCurrentRefundId());
        orderMap.put("payScoreOrderId", order.getPayScoreOrderId());
        return orderMap;
    }

    /**
     * 构建商品列表（使用预查询数据）
     */
    private List<Map<String, Object>> buildProductList(List<OrderItemVO> goodsList, Map<Long, Integer> refundQtys) {
        List<Map<String, Object>> products = new ArrayList<>();
        for (OrderItemVO goods : goodsList) {
            Map<String, Object> product = new HashMap<>();
            product.put("id", goods.getId());
            product.put("orderGoodsId", goods.getId());
            product.put("productId", goods.getProductId());
            product.put("name", goods.getProductName());
            product.put("price", goods.getPrice());
            product.put("quantity", goods.getProductNum());
            product.put("image", normalizeImageUrl(goods.getPic()));
            product.put("pic", goods.getPic());
            product.put("subtotal", goods.getPrice() != null && goods.getProductNum() != null
                    ? goods.getPrice().multiply(new BigDecimal(goods.getProductNum()))
                    : new BigDecimal(0));
            product.put("refundedQuantity", refundQtys.getOrDefault(goods.getId(), 0));
            products.add(product);
        }
        return products;
    }

    /**
     * 构建订单Map（含商品信息）
     */
    private Map<String, Object> buildOrderMap(Order order) {
        Map<String, Object> orderMap = new HashMap<>();
        orderMap.put("id", order.getId());
        orderMap.put("orderNo", order.getOrderNo());
        orderMap.put("orderName", order.getOrderName() != null ? order.getOrderName() : "");
        orderMap.put("outTradeNo", order.getOutTradeNo());
        orderMap.put("deviceId", order.getDeviceId());
        orderMap.put("storeName", order.getStoreName() != null ? order.getStoreName() : "");
        orderMap.put("totalAmount", order.getTotalAmount());
        orderMap.put("discountAmount", order.getDiscountAmount() != null ? order.getDiscountAmount() : 0);
        orderMap.put("paidAmount", order.getPaidAmount() != null ? order.getPaidAmount() : order.getTotalAmount());
        orderMap.put("payStatus", order.getPayStatus());
        orderMap.put("payChannel", order.getPayChannel());
        orderMap.put("status", order.getStatus());
        orderMap.put("createTime", order.getCreateTime());
        orderMap.put("payTime", order.getPayTime());
        orderMap.put("confidence", order.getConfidence());
        orderMap.put("refundStatus", order.getRefundStatus());
        orderMap.put("refundAmount", order.getRefundAmount());
        orderMap.put("currentRefundId", order.getCurrentRefundId());
        orderMap.put("payScoreOrderId", order.getPayScoreOrderId());
        orderMap.put("products", getProductsFromDatabase(order.getId()));
        return orderMap;
    }

    /**
     * 从数据库查询订单商品信息
     */
    private List<Map<String, Object>> getProductsFromDatabase(Long orderId) {
        List<Map<String, Object>> products = new ArrayList<>();
        if (orderId == null) {
            return products;
        }
        try {
            // 查询已退款数量
            Map<Long, Integer> refundedQuantityMap = null;
            try {
                if (refundService != null) {
                    refundedQuantityMap = refundService.getRefundedQuantityMap(orderId);
                }
            } catch (Exception e) {
                log.warn("查询订单 {} 已退款商品数量失败: {}", orderId, e.getMessage());
            }

            List<OrderItemVO> goodsList = orderGoodsService.getVOByOrderId(orderId);
            if (goodsList != null && !goodsList.isEmpty()) {
                for (OrderItemVO goods : goodsList) {
                    Map<String, Object> product = new HashMap<>();
                    product.put("id", goods.getId());
                    product.put("orderGoodsId", goods.getId());
                    product.put("productId", goods.getProductId());
                    product.put("name", goods.getProductName());
                    product.put("price", goods.getPrice());
                    product.put("quantity", goods.getProductNum());
                    product.put("image", normalizeImageUrl(goods.getPic()));
                    product.put("pic", goods.getPic());
                    product.put("subtotal", goods.getPrice() != null && goods.getProductNum() != null
                        ? goods.getPrice().multiply(new BigDecimal(goods.getProductNum()))
                        : new BigDecimal(0));
                    int refundedQty = refundedQuantityMap != null
                            ? refundedQuantityMap.getOrDefault(goods.getId(), 0) : 0;
                    product.put("refundedQuantity", refundedQty);
                    products.add(product);
                }
            }
        } catch (Exception e) {
            log.error("查询订单 {} 的商品信息失败：{}", orderId, e.getMessage());
        }
        return products;
    }

    /**
     * 修复缺失商品记录的订单：解析 orders.items (sku_list) 补写 t_order_goods
     * 优先使用订单 paidAmount，其次 totalAmount 作为商品金额基准
     *
     * @param activityId 指定 activityId 修复单个订单，为 null 则批量修复所有缺失商品的订单
     * @return 修复的订单数
     */
    @Transactional(rollbackFor = Exception.class)
    public int repairOrdersMissingGoods(String activityId) {
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.isNotNull(Order::getItems).ne(Order::getItems, "").ne(Order::getItems, "[]");
        if (activityId != null && !activityId.isEmpty()) {
            wrapper.eq(Order::getActivityId, activityId);
        }

        List<Order> orders = this.list(wrapper);
        int fixed = 0;

        // 1. 收集所有商品编码，批量查询（1 次 SELECT IN）
        java.util.Set<String> allCodes = new java.util.HashSet<>();
        for (Order order : orders) {
            String items = order.getItems();
            if (items == null || items.isEmpty()) continue;
            JSONArray skuList = JSON.parseArray(items);
            if (skuList == null || skuList.isEmpty()) continue;
            for (int i = 0; i < skuList.size(); i++) {
                String code = skuList.getJSONObject(i).getString("code");
                if (code != null && !code.isEmpty()) allCodes.add(code);
            }
        }
        Map<String, com.haha.entity.Product> productMap = new HashMap<>();
        if (!allCodes.isEmpty()) {
            List<com.haha.entity.Product> products = productService.listByCodes(allCodes);
            for (com.haha.entity.Product p : products) {
                productMap.put(p.getCode(), p);
            }
        }

        // 2. 收集所有要删除的 orderId，批量删除旧记录（1 次 DELETE IN）
        // 同时构建所有 OrderGoods
        List<Long> orderIdsToClear = new ArrayList<>();
        List<OrderGoods> allGoods = new ArrayList<>();

        for (Order order : orders) {
            String items = order.getItems();
            if (items == null || items.isEmpty()) continue;

            try {
                JSONArray skuList = JSON.parseArray(items);
                if (skuList == null || skuList.isEmpty()) continue;

                orderIdsToClear.add(order.getId());

                BigDecimal orderAmount = order.getPaidAmount() != null
                        && order.getPaidAmount().compareTo(BigDecimal.ZERO) > 0
                        ? order.getPaidAmount()
                        : order.getTotalAmount() != null ? order.getTotalAmount() : BigDecimal.ZERO;

                int totalQty = 0;
                for (int i = 0; i < skuList.size(); i++) {
                    Integer number = skuList.getJSONObject(i).getInteger("number");
                    totalQty += (number != null ? Math.abs(number) : 1);
                }

                BigDecimal unitPrice = totalQty > 0
                        ? orderAmount.divide(BigDecimal.valueOf(totalQty), 2, RoundingMode.HALF_UP)
                        : orderAmount;

                for (int i = 0; i < skuList.size(); i++) {
                    JSONObject sku = skuList.getJSONObject(i);
                    String code = sku.getString("code");
                    Integer number = sku.getInteger("number");
                    if (code == null || code.isEmpty()) continue;

                    int qty = number != null ? Math.abs(number) : 1;
                    com.haha.entity.Product product = productMap.get(code);

                    OrderGoods goods = new OrderGoods();
                    goods.setOrderId(order.getId());
                    goods.setOrderNo(order.getOrderNo());
                    goods.setActivityId(order.getActivityId());
                    goods.setDeviceId(order.getDeviceId());
                    goods.setUserId(order.getUserId());
                    goods.setCode(code);
                    goods.setProductNum(qty);
                    goods.setCreateTime(LocalDateTime.now());
                    goods.setPrice(unitPrice);
                    goods.setMoney(unitPrice.multiply(BigDecimal.valueOf(qty)));

                    if (product != null) {
                        goods.setProductId(product.getId());
                        goods.setBarCode(product.getBarcode());
                        goods.setProductName(product.getName());
                        goods.setPic(product.getPic());
                    }
                    allGoods.add(goods);
                }

                fixed++;
                log.info("补写订单商品成功 - orderId: {}, activityId: {}, 金额基准: {}",
                        order.getId(), order.getActivityId(), orderAmount);
            } catch (Exception e) {
                log.error("补写订单商品失败 - orderId: {}", order.getId(), e);
            }
        }

        // 3. 批量删除旧记录 + 批量插入新记录（共 2 次批量操作）
        if (!orderIdsToClear.isEmpty()) {
            orderGoodsMapper.delete(
                    new LambdaQueryWrapper<OrderGoods>().in(OrderGoods::getOrderId, orderIdsToClear));
        }
        if (!allGoods.isEmpty()) {
            orderGoodsService.saveBatch(allGoods);
        }

        return fixed;
    }

    /**
     * 批量修复已支付订单的支付状态同步到哈哈平台
     * 匹配规则：优先 hahaOrderId，其次 16 位纯数字 orderNo（曾被哈哈覆盖过的历史数据），否则跳过
     *
     * @return { synced: 成功数, skipped: 跳过数, failed: 失败数 }
     */
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> repairPayStatusSync() {
        List<Order> orders = lambdaQuery()
                .eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID)
                .list();

        int synced = 0, skipped = 0, failed = 0;
        for (Order order : orders) {
            String hahaRef = order.getHahaOrderId();
            if (hahaRef == null || hahaRef.isEmpty()) {
                // 历史订单可能被哈哈短号覆盖过 orderNo（16位纯数字 = 旧行为）
                if (order.getOrderNo() != null && order.getOrderNo().matches("^\\d{16}$")) {
                    hahaRef = order.getOrderNo();
                }
            }
            if (hahaRef == null || hahaRef.isEmpty()) {
                log.info("跳过同步 - orderNo: {}, 无法确定哈哈订单号", order.getOrderNo());
                skipped++;
                continue;
            }

            try {
                hahaClient.getOrderApi().setPayStatus(hahaRef);
                synced++;
                log.info("支付状态同步成功 - hahaRef: {}, localOrderNo: {}", hahaRef, order.getOrderNo());
            } catch (Exception e) {
                failed++;
                log.error("支付状态同步失败 - hahaRef: {}, localOrderNo: {}, error: {}",
                        hahaRef, order.getOrderNo(), e.getMessage());
            }
        }

        Map<String, Object> result = new HashMap<>();
        result.put("total", orders.size());
        result.put("synced", synced);
        result.put("skipped", skipped);
        result.put("failed", failed);
        log.info("批量同步支付状态完成 - total: {}, synced: {}, skipped: {}, failed: {}",
                orders.size(), synced, skipped, failed);
        return result;
    }

    /**
     * 修复指定订单的支付分扣费，支持订单ID或订单编号
     *
     * @param orderIdOrNo       订单ID（数字）或订单编号
     * @param payScoreOrderId   微信支付分服务订单号（outOrderNo），为空则使用订单上的值
     * @return { success: true/false, message: "..." }
     */
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> repairPayScorePayment(String orderIdOrNo, String payScoreOrderId) {
        Order order;
        if (orderIdOrNo.matches("^\\d{1,19}$")) {
            order = this.getById(Long.parseLong(orderIdOrNo));
        } else {
            order = lambdaQuery().eq(Order::getOrderNo, orderIdOrNo).one();
        }
        if (order == null) {
            return Map.of("success", false, "message", "订单不存在: " + orderIdOrNo);
        }

        // 如果本地丢失 payScoreOrderId，尝试从 Redis 自动恢复
        if ((order.getPayScoreOrderId() == null || order.getPayScoreOrderId().isEmpty())
                && (payScoreOrderId == null || payScoreOrderId.isEmpty())) {
            String recovered = payScoreService.tryRecoverPayScoreOrderId(order.getUserId(), order.getDeviceId());
            if (recovered != null) {
                payScoreOrderId = recovered;
                log.info("[支付分修复] 自动恢复 payScoreOrderId - orderId: {}, recovered: {}", order.getId(), recovered);
            }
        }

        // 如果提供了 outOrderNo（手动或自动恢复），先回填到本地订单
        if (payScoreOrderId != null && !payScoreOrderId.isEmpty()) {
            if (order.getPayScoreOrderId() == null || order.getPayScoreOrderId().isEmpty()) {
                order.setPayScoreOrderId(payScoreOrderId);
                order.setPayScoreState(PayScoreState.DOING.getCode());
                order.setPayChannel(PaymentChannel.WECHAT_PAYSCORE.getCode());
                order.setPayType("微信支付分");
                if (order.getServiceId() == null && payScoreService.getServiceId() != null) {
                    order.setServiceId(payScoreService.getServiceId());
                }
                this.updateById(order);
                log.info("[支付分修复] 回填 payScoreOrderId - orderId: {}, orderNo: {}, payScoreOrderId: {}",
                        order.getId(), order.getOrderNo(), payScoreOrderId);
            } else if (!payScoreOrderId.equals(order.getPayScoreOrderId())) {
                return Map.of("success", false, "message",
                        "提供的 outOrderNo 与订单上的不一致: " + order.getPayScoreOrderId());
            }
        }

        // 重新加载以获取最新状态
        order = this.getById(order.getId());

        if (order.getPayScoreOrderId() == null || order.getPayScoreOrderId().isEmpty()) {
            return Map.of("success", false, "message",
                    "未找到支付分商户单号，请从微信商户后台查找后手动输入");
        }

        if (PayScoreState.isFinished(order.getPayScoreState())) {
            return Map.of("success", false, "message", "支付分订单已完结，无需修复: " + order.getPayScoreState());
        }

        if (!OrderConstants.PAY_STATUS_UNPAID.equals(order.getPayStatus())) {
            return Map.of("success", false, "message", "订单已支付，无需修复");
        }

        if (order.getTotalAmount() == null || order.getTotalAmount().compareTo(BigDecimal.ZERO) <= 0) {
            return Map.of("success", false, "message", "订单金额为0，无法扣费");
        }

        BigDecimal amount = order.getPaidAmount() != null
                && order.getPaidAmount().compareTo(BigDecimal.ZERO) > 0
                ? order.getPaidAmount() : order.getTotalAmount();

        boolean result = completeOrderWithPayScore(order.getId(), amount);
        log.info("[支付分修复] orderId: {}, orderNo: {}, payScoreOrderId: {}, amount: {}, result: {}",
                order.getId(), order.getOrderNo(), order.getPayScoreOrderId(), amount, result);

        return result
                ? Map.of("success", true, "message", "扣费成功")
                : Map.of("success", false, "message", "扣费失败，请查看服务端日志");
    }

    /**
     * 标准化图片URL
     */
    private String normalizeImageUrl(String picUrl) {
        if (picUrl == null || picUrl.isEmpty()) {
            return picUrl;
        }
        if (picUrl.startsWith("http://") || picUrl.startsWith("https://")) {
            return picUrl;
        }
        return commonConfig.getImageDomainPrefix() + picUrl;
    }
}
