package shop.alien.dining.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import shop.alien.dining.config.BaseRedisService;
import shop.alien.dining.service.CartService;
import shop.alien.dining.service.StoreOrderService;
import shop.alien.dining.util.TokenUtil;
import shop.alien.entity.store.*;
import shop.alien.entity.store.dto.CartDTO;
import shop.alien.entity.store.dto.CartItemDTO;
import shop.alien.entity.store.dto.CreateOrderDTO;
import shop.alien.entity.store.vo.OrderChangeLogBatchVO;
import shop.alien.entity.store.vo.OrderChangeLogItemVO;
import shop.alien.entity.store.vo.OrderInfoVO;
import shop.alien.entity.store.vo.StoreOrderPageVO;
import shop.alien.entity.store.vo.OrderCuisineItemVO;
import shop.alien.entity.store.vo.OrderDetailWithChangeLogVO;
import shop.alien.mapper.*;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 订单服务实现类
 *
 * @author system
 * @since 2025-01-XX
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOrder> implements StoreOrderService {


    private final StoreOrderDetailMapper orderDetailMapper;
    private final StoreTableMapper storeTableMapper;
    private final StoreTableLogMapper storeTableLogMapper;
    private final StoreCuisineMapper storeCuisineMapper;
    private final LifeDiscountCouponMapper lifeDiscountCouponMapper;
    private final CartService cartService;
    private final StoreOrderLockMapper storeOrderLockMapper;
    private final StoreCouponUsageMapper storeCouponUsageMapper;
    private final StoreCartMapper storeCartMapper;
    private final BaseRedisService baseRedisService;
    private final StoreInfoMapper storeInfoMapper;
    private final StoreOrderChangeLogMapper orderChangeLogMapper;
    private final shop.alien.dining.service.SseService sseService;
    private final shop.alien.dining.service.OrderLockService orderLockService;

    @Override
    public StoreOrder createOrder(CreateOrderDTO dto) {
        log.info("创建订单, dto={}", dto);

        // 获取当前用户信息
        Object[] userInfo = getCurrentUserInfo();
        Integer userId = (Integer) userInfo[0];
        String userPhone = (String) userInfo[1];

        // 检查订单锁定状态
        Integer lockUserId = orderLockService.checkOrderLock(dto.getTableId());
        if (lockUserId != null && !lockUserId.equals(userId)) {
            throw new RuntimeException("订单已被其他用户锁定，无法下单");
        }

        // 验证桌号
        StoreTable table = storeTableMapper.selectById(dto.getTableId());
        if (table == null) {
            throw new RuntimeException("桌号不存在");
        }

        // 查询门店信息（用于获取餐具费）
        StoreInfo storeInfo = storeInfoMapper.selectById(table.getStoreId());
        if (storeInfo == null) {
            throw new RuntimeException("门店不存在");
        }

        // 获取购物车
        CartDTO cart = cartService.getCart(dto.getTableId());
        if (cart.getItems() == null || cart.getItems().isEmpty()) {
            throw new RuntimeException("购物车为空");
        }
        
        // 检查是否有新增商品或商品数量增加
        boolean hasNewItems = false; // 是否有新增商品（未下单过的商品）
        boolean hasQuantityIncrease = false; // 是否有商品数量增加
        
        for (shop.alien.entity.store.dto.CartItemDTO item : cart.getItems()) {
            Integer lockedQuantity = item.getLockedQuantity();
            Integer currentQuantity = item.getQuantity();
            
            if (lockedQuantity == null || lockedQuantity == 0) {
                // 有新增商品（未下单过的商品）
                hasNewItems = true;
                log.debug("发现新增商品, cuisineId={}, quantity={}", item.getCuisineId(), currentQuantity);
            } else if (currentQuantity != null && currentQuantity > lockedQuantity) {
                // 有商品数量增加（当前数量大于已下单数量）
                hasQuantityIncrease = true;
                log.debug("发现商品数量增加, cuisineId={}, currentQuantity={}, orderedQuantity={}", 
                        item.getCuisineId(), currentQuantity, lockedQuantity);
            }
        }
        
        // 如果没有新增商品且没有商品数量增加，不允许创建/更新订单（下单后只能增不能减，不支持减量同步）
        if (!hasNewItems && !hasQuantityIncrease) {
            throw new RuntimeException("购物车中没有新增商品或商品数量未增加，无法创建订单");
        }

        // 直接使用前端传入的值
        BigDecimal totalAmount = dto.getTotalAmount() != null ? dto.getTotalAmount() : BigDecimal.ZERO;
        BigDecimal tablewareFee = dto.getTablewareFee() != null ? dto.getTablewareFee() : BigDecimal.ZERO;
        BigDecimal discountAmount = dto.getDiscountAmount() != null ? dto.getDiscountAmount() : BigDecimal.ZERO;
        BigDecimal payAmount = dto.getPayAmount() != null ? dto.getPayAmount() : BigDecimal.ZERO;
        
        // 优惠券仅校验是否存在及是否属于该门店，不做金额校验；订单总金额、餐具费、优惠金额、实付金额完全采用前端传参
        LifeDiscountCoupon coupon = null;
        
        if (dto.getCouponId() != null) {
            // 检查桌号是否已使用优惠券，如果已使用则替换为新优惠券
            if (cartService.hasUsedCoupon(dto.getTableId())) {
                // 获取旧的优惠券使用记录
                LambdaQueryWrapper<StoreCouponUsage> oldUsageWrapper = new LambdaQueryWrapper<>();
                oldUsageWrapper.eq(StoreCouponUsage::getTableId, dto.getTableId());
                oldUsageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
                oldUsageWrapper.in(StoreCouponUsage::getUsageStatus, 0, 1); // 已标记使用、已下单
                oldUsageWrapper.orderByDesc(StoreCouponUsage::getCreatedTime);
                oldUsageWrapper.last("LIMIT 1");
                StoreCouponUsage oldUsage = storeCouponUsageMapper.selectOne(oldUsageWrapper);
                
                if (oldUsage != null) {
                    // 如果旧优惠券已经关联到订单（已下单状态），需要将旧优惠券使用记录状态改为"已取消"
                    if (oldUsage.getUsageStatus() == 1 && oldUsage.getOrderId() != null) {
                        oldUsage.setUsageStatus(3); // 已取消
                        oldUsage.setUpdatedTime(new Date());
                        storeCouponUsageMapper.updateById(oldUsage);
                        log.info("替换优惠券：取消旧优惠券使用记录, tableId={}, oldCouponId={}, newCouponId={}", 
                                dto.getTableId(), oldUsage.getCouponId(), dto.getCouponId());
                    } else {
                        // 如果只是已标记使用但未下单，直接逻辑删除
                        storeCouponUsageMapper.deleteById(oldUsage.getId());
                        log.info("替换优惠券：删除未下单的旧优惠券使用记录, tableId={}, oldCouponId={}, newCouponId={}", 
                                dto.getTableId(), oldUsage.getCouponId(), dto.getCouponId());
                    }
                }
                
                // 清除旧的优惠券使用标记
                cartService.clearCouponUsed(dto.getTableId());
                log.info("替换优惠券：清除旧优惠券标记, tableId={}, newCouponId={}", dto.getTableId(), dto.getCouponId());
            }

            // 验证优惠券（只查询一次）
            coupon = lifeDiscountCouponMapper.selectByIdIncludeDeleted(dto.getCouponId());
            if (coupon == null) {
                throw new RuntimeException("优惠券不存在");
            }

            // 验证优惠券是否属于该门店（空安全：coupon.storeId 为 String，table.storeId 为 Integer）
            String couponStoreId = coupon.getStoreId();
            Integer tableStoreId = table.getStoreId();
            if (couponStoreId == null || tableStoreId == null
                    || !couponStoreId.equals(String.valueOf(tableStoreId))) {
                throw new RuntimeException("优惠券不属于该门店");
            }

            // 标记桌号已使用新优惠券
            cartService.markCouponUsed(dto.getTableId(), dto.getCouponId());
        } else {
            // 直接使用前端传入的值，如果为null则设为0
            if (discountAmount == null) {
                discountAmount = BigDecimal.ZERO;
            }
        }

        Date now = new Date();
        StoreOrder order = null;
        String orderNo = null;
        boolean isUpdate = false; // 是否是更新订单
        
        // 检查桌号是否已绑定订单
        if (table.getCurrentOrderId() != null) {
            // 查询已存在的订单
            StoreOrder existingOrder = this.getById(table.getCurrentOrderId());
            if (existingOrder != null && existingOrder.getOrderStatus() == 0 && existingOrder.getPayStatus() == 0) {
                // 订单存在且是待支付状态，更新订单
                isUpdate = true;
                order = existingOrder;
                orderNo = order.getOrderNo(); // 使用原订单号
                log.info("桌号已绑定订单，更新订单信息, orderId={}, orderNo={}", order.getId(), orderNo);
                
                // 更新订单信息（完全采用前端传参，不做金额校验）
                order.setDinerCount(dto.getDinerCount());
                order.setContactPhone(dto.getContactPhone());
                order.setTablewareFee(tablewareFee);
                order.setTotalAmount(totalAmount);
                order.setCouponId(dto.getCouponId());
                order.setCurrentCouponId(dto.getCouponId());
                order.setDiscountAmount(discountAmount);
                order.setPayAmount(payAmount);
                order.setRemark(dto.getRemark());
                order.setUpdatedUserId(userId);
                order.setUpdatedTime(now);
                this.updateById(order);
                
                // 逻辑删除旧的订单明细
                LambdaQueryWrapper<StoreOrderDetail> detailWrapper = new LambdaQueryWrapper<>();
                detailWrapper.eq(StoreOrderDetail::getOrderId, order.getId());
                detailWrapper.eq(StoreOrderDetail::getDeleteFlag, 0);
                List<StoreOrderDetail> oldDetails = orderDetailMapper.selectList(detailWrapper);
                if (oldDetails != null && !oldDetails.isEmpty()) {
                    List<Integer> oldDetailIds = oldDetails.stream()
                            .map(StoreOrderDetail::getId)
                            .collect(Collectors.toList());
                    orderDetailMapper.deleteBatchIds(oldDetailIds);
                    log.info("删除旧订单明细, orderId={}, count={}", order.getId(), oldDetailIds.size());
                }
            } else {
                log.info("桌号绑定的订单不存在或已支付/已取消，将创建新订单");
            }
        }
        
        // 如果没有订单需要更新，创建新订单
        if (!isUpdate) {
            // 生成订单号
            orderNo = generateOrderNo();
            
            // 创建订单
            order = new StoreOrder();
            order.setOrderNo(orderNo);
            order.setStoreId(table.getStoreId());
            order.setTableId(table.getId());
            order.setTableNumber(table.getTableNumber());
            order.setDinerCount(dto.getDinerCount());
            order.setContactPhone(dto.getContactPhone());
            order.setTablewareFee(tablewareFee);
            order.setPayUserId(userId);
            order.setPayUserPhone(userPhone);
            order.setOrderStatus(0); // 待支付
            order.setTotalAmount(totalAmount);
            order.setCouponId(dto.getCouponId());
            order.setCurrentCouponId(dto.getCouponId());
            order.setDiscountAmount(discountAmount);
            order.setPayAmount(payAmount);
            
            // 如果immediatePay为0，只创建订单不支付；为1则创建订单并支付
            // 暂时不实现立即支付，由前端调用支付接口
            // payType在支付时设置
            order.setPayStatus(0); // 未支付
            order.setRemark(dto.getRemark());
            order.setCreatedUserId(userId);
            order.setUpdatedUserId(userId);
            // 手动设置创建时间和更新时间（临时方案，避免自动填充未生效导致 created_time 为 null）
            order.setCreatedTime(now);
            order.setUpdatedTime(now);
            this.save(order);
            log.info("创建新订单, orderId={}, orderNo={}", order.getId(), orderNo);
        }
        
        // 确保 order 和 orderNo 已初始化（用于后续代码）
        if (order == null || orderNo == null) {
            throw new RuntimeException("订单创建失败，系统错误");
        }
        final StoreOrder finalOrder = order;
        final String finalOrderNo = orderNo;
        final boolean finalIsUpdate = isUpdate; // 用于 lambda 表达式

        // 更新优惠券使用记录状态为已下单
        if (dto.getCouponId() != null) {
            LambdaQueryWrapper<StoreCouponUsage> usageWrapper = new LambdaQueryWrapper<>();
            usageWrapper.eq(StoreCouponUsage::getTableId, dto.getTableId());
            usageWrapper.eq(StoreCouponUsage::getCouponId, dto.getCouponId());
            usageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
            usageWrapper.orderByDesc(StoreCouponUsage::getCreatedTime);
            usageWrapper.last("LIMIT 1");
            StoreCouponUsage usage = storeCouponUsageMapper.selectOne(usageWrapper);
            if (usage != null) {
                usage.setOrderId(finalOrder.getId());
                usage.setUsageStatus(1); // 已下单
                usage.setUpdatedTime(new Date());
                storeCouponUsageMapper.updateById(usage);
            }
        }
        
        // 如果是更新订单，且优惠券发生变化，需要处理旧优惠券的使用记录
        if (isUpdate && finalOrder.getCouponId() != null && 
            (dto.getCouponId() == null || !finalOrder.getCouponId().equals(dto.getCouponId()))) {
            // 订单的优惠券被替换或取消，需要将旧优惠券使用记录状态改为"已取消"
            LambdaQueryWrapper<StoreCouponUsage> oldUsageWrapper = new LambdaQueryWrapper<>();
            oldUsageWrapper.eq(StoreCouponUsage::getOrderId, finalOrder.getId());
            oldUsageWrapper.eq(StoreCouponUsage::getCouponId, finalOrder.getCouponId());
            oldUsageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
            oldUsageWrapper.orderByDesc(StoreCouponUsage::getCreatedTime);
            oldUsageWrapper.last("LIMIT 1");
            StoreCouponUsage oldUsage = storeCouponUsageMapper.selectOne(oldUsageWrapper);
            if (oldUsage != null) {
                oldUsage.setUsageStatus(3); // 已取消
                oldUsage.setUpdatedTime(new Date());
                storeCouponUsageMapper.updateById(oldUsage);
                log.info("更新订单时替换优惠券：取消旧优惠券使用记录, orderId={}, oldCouponId={}, newCouponId={}", 
                        finalOrder.getId(), finalOrder.getCouponId(), dto.getCouponId());
            }
        }

        // 创建订单明细（单价、小计来自购物车）
        // 如果是更新订单，需要判断哪些商品是新增的或数量增加的，标记为加餐
        // 餐具的特殊ID（用于标识餐具项）
        final Integer TABLEWARE_CUISINE_ID = -1;
        
        List<StoreOrderDetail> orderDetails = cart.getItems().stream()
                .map(item -> {
                    StoreOrderDetail detail = new StoreOrderDetail();
                    detail.setOrderId(finalOrder.getId());
                    detail.setOrderNo(finalOrderNo);
                    detail.setCuisineId(item.getCuisineId());
                    detail.setCuisineName(item.getCuisineName());
                    
                    // 设置菜品类型：如果为null，根据是否为餐具设置默认值
                    Integer cuisineType = item.getCuisineType();
                    if (cuisineType == null) {
                        // 如果是餐具，设置为0；否则设置为1（默认单品）
                        if (TABLEWARE_CUISINE_ID.equals(item.getCuisineId())) {
                            cuisineType = 0; // 0表示餐具
                        } else {
                            // 尝试从菜品信息中获取，如果获取不到则默认为1（单品）
                            try {
                                StoreCuisine cuisine = storeCuisineMapper.selectById(item.getCuisineId());
                                if (cuisine != null && cuisine.getCuisineType() != null) {
                                    cuisineType = cuisine.getCuisineType();
                                } else {
                                    cuisineType = 1; // 默认为单品
                                }
                            } catch (Exception e) {
                                log.warn("获取菜品类型失败, cuisineId={}, 使用默认值1", item.getCuisineId(), e);
                                cuisineType = 1; // 默认为单品
                            }
                        }
                    }
                    detail.setCuisineType(cuisineType);
                    
                    detail.setCuisineImage(item.getCuisineImage());
                    detail.setUnitPrice(item.getUnitPrice());
                    detail.setQuantity(item.getQuantity());
                    detail.setSubtotalAmount(item.getSubtotalAmount());
                    detail.setAddUserId(item.getAddUserId());
                    detail.setAddUserPhone(item.getAddUserPhone());
                    detail.setRemark(item.getRemark());
                    detail.setCreatedUserId(userId);
                    detail.setCreatedTime(now);
                    detail.setUpdatedTime(now);
                    
                    // 如果是更新订单，判断是否为新增商品或数量增加的商品
                    if (finalIsUpdate) {
                        Integer lockedQuantity = item.getLockedQuantity();
                        // 如果是新增商品（lockedQuantity 为 null 或 0）或数量增加的商品，标记为加餐
                        if (lockedQuantity == null || lockedQuantity == 0 || 
                            (item.getQuantity() != null && item.getQuantity() > lockedQuantity)) {
                            detail.setIsAddDish(1); // 标记为加餐
                            detail.setAddDishTime(now);
                        }
                    }
                    
                    return detail;
                })
                .collect(Collectors.toList());

        for (StoreOrderDetail detail : orderDetails) {
            orderDetailMapper.insert(detail);
        }

        // 记录订单变更日志
        recordOrderChangeLog(finalOrder.getId(), finalOrderNo, cart.getItems(), finalIsUpdate ? 3 : 1, now, userId, userPhone);

        // 更新桌号的当前订单ID和状态（显式用 LambdaUpdateWrapper 写入，避免 updateById 忽略更新）
        // 约定：首次下单 → 餐桌状态=就餐中(1)；后续下单(更新订单/加餐) → 餐桌状态=加餐(3)
        Integer tableId = table.getId();
        if (!finalIsUpdate) {
            // 首次下单：设置订单ID，餐桌状态为就餐中（1）
            LambdaUpdateWrapper<StoreTable> newTableWrapper = new LambdaUpdateWrapper<>();
            newTableWrapper.eq(StoreTable::getId, tableId)
                    .set(StoreTable::getCurrentOrderId, finalOrder.getId())
                    .set(StoreTable::getStatus, 1)
                    .set(StoreTable::getUpdatedTime, now);
            if (userId != null) {
                newTableWrapper.set(StoreTable::getUpdatedUserId, userId);
            }
            storeTableMapper.update(null, newTableWrapper);
        } else {
            // 后续下单（更新订单/加餐）：餐桌状态设为加餐（3）
            LambdaUpdateWrapper<StoreTable> addDishTableWrapper = new LambdaUpdateWrapper<>();
            addDishTableWrapper.eq(StoreTable::getId, tableId)
                    .set(StoreTable::getStatus, 3)
                    .set(StoreTable::getUpdatedTime, now);
            if (userId != null) {
                addDishTableWrapper.set(StoreTable::getUpdatedUserId, userId);
            }
            storeTableMapper.update(null, addDishTableWrapper);
            log.info("更新订单(加餐)，设置餐桌状态为加餐, tableId={}, orderId={}", tableId, finalOrder.getId());
        }

        // 锁定购物车商品数量（禁止减少或删除已下单的商品）
        cartService.lockCartItems(dto.getTableId());

        // 下单后不清空购物车，允许加餐（加餐时添加到同一订单）
        // 只有在支付完成后才清空购物车

        // 创建订单成功后，自动解锁订单锁定
        try {
            orderLockService.unlockOrder(dto.getTableId(), userId);
            log.info("订单创建成功后自动解锁订单锁定, tableId={}, userId={}", dto.getTableId(), userId);
        } catch (Exception e) {
            log.warn("自动解锁订单锁定失败, tableId={}, userId={}, error={}", dto.getTableId(), userId, e.getMessage());
            // 解锁失败不影响订单创建，只记录警告日志
        }

        if (isUpdate) {
            log.info("订单更新成功, orderId={}, orderNo={}", finalOrder.getId(), finalOrderNo);
        } else {
            log.info("订单创建成功, orderId={}, orderNo={}", finalOrder.getId(), finalOrderNo);
        }
        return finalOrder;
    }

    @Override
    public StoreOrder payOrder(Integer orderId, Integer payType) {
        log.info("支付订单, orderId={}, payType={}", orderId, payType);

        // 获取当前用户信息
        Object[] userInfo = getCurrentUserInfo();
        Integer userId = (Integer) userInfo[0];

        // 检查结算锁定状态
        Integer lockUserId = orderLockService.checkSettlementLock(orderId);
        if (lockUserId != null && !lockUserId.equals(userId)) {
            throw new RuntimeException("订单结算已被其他用户锁定，无法支付");
        }

        // 验证订单状态
        StoreOrder order = validateOrderForOperation(orderId, 0, "支付");

        // 支付时重新计算优惠券金额和实付金额（此时订单金额已确定，不会再变化）
        BigDecimal discountAmount = BigDecimal.ZERO;
        BigDecimal tablewareFee = order.getTablewareFee() != null ? order.getTablewareFee() : BigDecimal.ZERO;
        BigDecimal totalAmount = order.getTotalAmount() != null ? order.getTotalAmount() : BigDecimal.ZERO;
        BigDecimal totalWithTableware = totalAmount.add(tablewareFee);
        
        if (order.getCouponId() != null) {
            // 查询优惠券信息
            LifeDiscountCoupon coupon = lifeDiscountCouponMapper.selectByIdIncludeDeleted(order.getCouponId());
            if (coupon == null) {
                throw new RuntimeException("优惠券不存在");
            }
            
            // 验证最低消费（菜品总价 + 餐具费）
            if (coupon.getMinimumSpendingAmount() != null
                    && totalWithTableware.compareTo(coupon.getMinimumSpendingAmount()) < 0) {
                throw new RuntimeException("订单金额未达到优惠券最低消费要求（" + coupon.getMinimumSpendingAmount() + "元）");
            }
            
            // 计算优惠金额：根据优惠券类型（满减券或折扣券）计算
            discountAmount = calculateDiscountAmount(coupon, totalWithTableware);
        }
        
        // 计算实付金额（菜品总价 + 餐具费 - 优惠金额）
        BigDecimal payAmount = totalWithTableware.subtract(discountAmount);
        
        // 更新订单信息（包括优惠金额和实付金额）
        order.setDiscountAmount(discountAmount);
        order.setPayAmount(payAmount);
        order.setOrderStatus(1); // 已支付
        order.setPayStatus(1); // 已支付
        order.setPayType(payType);
        order.setPayTime(new Date());
        order.setPayTradeNo("TRADE_" + System.currentTimeMillis()); // 模拟交易号
        order.setUpdatedTime(new Date());
        order.setUpdatedUserId(userId);

        this.updateById(order);

        // 更新优惠券使用记录状态为已支付
        if (order.getCouponId() != null) {
            LambdaQueryWrapper<StoreCouponUsage> usageWrapper = new LambdaQueryWrapper<>();
            usageWrapper.eq(StoreCouponUsage::getOrderId, orderId);
            usageWrapper.eq(StoreCouponUsage::getCouponId, order.getCouponId());
            usageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
            usageWrapper.orderByDesc(StoreCouponUsage::getCreatedTime);
            usageWrapper.last("LIMIT 1");
            StoreCouponUsage usage = storeCouponUsageMapper.selectOne(usageWrapper);
            if (usage != null) {
                usage.setUsageStatus(2); // 已支付
                usage.setUpdatedTime(new Date());
                storeCouponUsageMapper.updateById(usage);
            }
        }

        // 支付完成后，清空购物车和重置餐桌状态（保留订单数据，不删除订单）
        // resetTableAfterPayment 方法会清空购物车和重置餐桌状态，但不会删除订单数据
        resetTableAfterPayment(order.getTableId());

        // 支付订单成功后，自动解锁结算锁定
        try {
            orderLockService.unlockSettlement(orderId, userId);
            log.info("订单支付成功后自动解锁结算锁定, orderId={}, userId={}", orderId, userId);
        } catch (Exception e) {
            log.warn("自动解锁结算锁定失败, orderId={}, userId={}, error={}", orderId, userId, e.getMessage());
            // 解锁失败不影响订单支付，只记录警告日志
        }

        log.info("订单支付成功, orderId={}", orderId);
        return order;
    }

    @Override
    public boolean cancelOrder(Integer orderId) {
        log.info("取消订单, orderId={}", orderId);

        // 验证订单状态
        StoreOrder order = validateOrderForOperation(orderId, 0, "取消");

        order.setOrderStatus(2); // 已取消
        order.setUpdatedTime(new Date());

        // 获取当前用户信息
        Integer userId = TokenUtil.getCurrentUserId();
        if (userId != null) {
            order.setUpdatedUserId(userId);
        }

        this.updateById(order);

        // 恢复购物车的已下单数量（允许重新下单）
        cartService.unlockCartItems(order.getTableId());

        // 清除优惠券使用标记
        cartService.clearCouponUsed(order.getTableId());

        // 更新桌号状态：显式清空 currentOrderId（updateById 会忽略 null，必须用 LambdaUpdateWrapper）
        Integer tableId = order.getTableId();
        StoreTable table = storeTableMapper.selectById(tableId);
        if (table != null) {
            LambdaUpdateWrapper<StoreTable> tableWrapper = new LambdaUpdateWrapper<>();
            tableWrapper.eq(StoreTable::getId, tableId)
                    .set(StoreTable::getCurrentOrderId, null)
                    .set(StoreTable::getUpdatedTime, new Date());
            CartDTO cart = cartService.getCart(tableId);
            if (cart.getItems() == null || cart.getItems().isEmpty()) {
                tableWrapper.set(StoreTable::getStatus, 0).set(StoreTable::getDinerCount, null);
            } else {
                tableWrapper.set(StoreTable::getStatus, 1); // 就餐中
            }
            if (userId != null) {
                tableWrapper.set(StoreTable::getUpdatedUserId, userId);
            }
            storeTableMapper.update(null, tableWrapper);
        }

        log.info("订单取消成功, orderId={}", orderId);
        return true;
    }

    @Override
    public StoreOrder getOrderByOrderNo(String orderNo) {
        LambdaQueryWrapper<StoreOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreOrder::getOrderNo, orderNo);
        wrapper.eq(StoreOrder::getDeleteFlag, 0);
        return this.getOne(wrapper);
    }

    @Override
    public StoreOrder getOrderById(Integer orderId) {
        return this.getById(orderId);
    }

    /** 前端只传 0=进行中、3=已完成。进行中对应库表 0待支付+1已支付，已完成对应 3。 */
    private List<Integer> resolveOrderStatusFilter(Integer orderStatus) {
        if (orderStatus == null) {
            return null;
        }
        if (orderStatus == 0) {
            return Arrays.asList(0, 1); // 进行中 = 待支付 + 已支付
        }
        if (orderStatus == 3) {
            return Collections.singletonList(3); // 已完成
        }
        return null; // 其他值不参与筛选
    }

    @Override
    public IPage<StoreOrder> getOrderPage(Page<StoreOrder> page, Integer storeId, Integer tableId, Integer orderStatus, String keyword) {
        // 前端只传 0=进行中、3=已完成。进行中=待支付(0)+已支付(1)，已完成=3
        List<Integer> orderStatusList = resolveOrderStatusFilter(orderStatus);
        LambdaQueryWrapper<StoreOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreOrder::getDeleteFlag, 0);
        if (storeId != null) {
            wrapper.eq(StoreOrder::getStoreId, storeId);
        }
        if (tableId != null) {
            wrapper.eq(StoreOrder::getTableId, tableId);
        }
        if (orderStatusList != null && !orderStatusList.isEmpty()) {
            wrapper.in(StoreOrder::getOrderStatus, orderStatusList);
        }
        
        // 搜索功能：按订单编号模糊搜索
        if (StringUtils.hasText(keyword)) {
            // 限制搜索关键词长度（15字）
            String searchKeyword = keyword.length() > 15 ? keyword.substring(0, 15) : keyword;
            wrapper.like(StoreOrder::getOrderNo, searchKeyword);
        }
        
        wrapper.orderByDesc(StoreOrder::getCreatedTime);
        return this.page(page, wrapper);
    }

    @Override
    public IPage<StoreOrderPageVO> getOrderPageWithCuisines(Page<StoreOrder> page, Integer storeId, Integer tableId, Integer orderStatus, String keyword) {
        // 前端只传 0=进行中、3=已完成。进行中=待支付(0)+已支付(1)，已完成=3
        List<Integer> orderStatusList = resolveOrderStatusFilter(orderStatus);
        log.info("分页查询订单列表（包含菜品信息）, storeId={}, tableId={}, orderStatus={}, keyword={}", storeId, tableId, orderStatusList, keyword);
        
        // 限制搜索关键词长度（15字）
        String searchKeyword = null;
        if (StringUtils.hasText(keyword)) {
            searchKeyword = keyword.length() > 15 ? keyword.substring(0, 15) : keyword;
        }
        
        // 1. 如果有关键词，需要同时支持按订单编号和菜品名称搜索
        final Set<Integer> matchingOrderIds;
        if (StringUtils.hasText(searchKeyword)) {
            Set<Integer> orderIdsSet = new HashSet<>();
            
            // 1.1 按订单编号搜索
            LambdaQueryWrapper<StoreOrder> orderNoWrapper = new LambdaQueryWrapper<>();
            orderNoWrapper.eq(StoreOrder::getDeleteFlag, 0)
                    .like(StoreOrder::getOrderNo, searchKeyword);
            if (storeId != null) {
                orderNoWrapper.eq(StoreOrder::getStoreId, storeId);
            }
            if (tableId != null) {
                orderNoWrapper.eq(StoreOrder::getTableId, tableId);
            }
            if (orderStatusList != null && !orderStatusList.isEmpty()) {
                orderNoWrapper.in(StoreOrder::getOrderStatus, orderStatusList);
            }
            List<StoreOrder> orderNoMatches = this.list(orderNoWrapper);
            orderNoMatches.forEach(order -> orderIdsSet.add(order.getId()));
            
            // 1.2 按菜品名称搜索
            LambdaQueryWrapper<StoreOrderDetail> detailSearchWrapper = new LambdaQueryWrapper<>();
            detailSearchWrapper.select(StoreOrderDetail::getOrderId)
                    .like(StoreOrderDetail::getCuisineName, searchKeyword)
                    .eq(StoreOrderDetail::getDeleteFlag, 0);
            
            // 如果有限制条件，需要先查询符合条件的订单ID
            if (storeId != null || tableId != null || (orderStatusList != null && !orderStatusList.isEmpty())) {
                LambdaQueryWrapper<StoreOrder> filterWrapper = new LambdaQueryWrapper<>();
                filterWrapper.eq(StoreOrder::getDeleteFlag, 0)
                        .select(StoreOrder::getId);
                if (storeId != null) {
                    filterWrapper.eq(StoreOrder::getStoreId, storeId);
                }
                if (tableId != null) {
                    filterWrapper.eq(StoreOrder::getTableId, tableId);
                }
                if (orderStatusList != null && !orderStatusList.isEmpty()) {
                    filterWrapper.in(StoreOrder::getOrderStatus, orderStatusList);
                }
                List<StoreOrder> filteredOrders = this.list(filterWrapper);
                Set<Integer> filteredOrderIds = filteredOrders.stream()
                        .map(StoreOrder::getId)
                        .collect(Collectors.toSet());
                if (!filteredOrderIds.isEmpty()) {
                    detailSearchWrapper.in(StoreOrderDetail::getOrderId, filteredOrderIds);
                } else {
                    // 如果没有符合条件的订单，直接返回空结果
                    Page<StoreOrderPageVO> emptyPage = new Page<>(page.getCurrent(), page.getSize());
                    emptyPage.setTotal(0);
                    emptyPage.setPages(0);
                    return emptyPage;
                }
            }
            
            List<StoreOrderDetail> matchingDetails = orderDetailMapper.selectList(detailSearchWrapper);
            matchingDetails.forEach(detail -> orderIdsSet.add(detail.getOrderId()));
            
            matchingOrderIds = orderIdsSet;
            
            // 如果没有任何匹配的订单，返回空结果
            if (matchingOrderIds.isEmpty()) {
                Page<StoreOrderPageVO> emptyPage = new Page<>(page.getCurrent(), page.getSize());
                emptyPage.setTotal(0);
                emptyPage.setPages(0);
                return emptyPage;
            }
        } else {
            matchingOrderIds = null;
        }
        
        // 2. 查询订单列表
        LambdaQueryWrapper<StoreOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreOrder::getDeleteFlag, 0);
        if (storeId != null) {
            wrapper.eq(StoreOrder::getStoreId, storeId);
        }
        if (tableId != null) {
            wrapper.eq(StoreOrder::getTableId, tableId);
        }
        if (orderStatusList != null && !orderStatusList.isEmpty()) {
            wrapper.in(StoreOrder::getOrderStatus, orderStatusList);
        }
        // 如果有关键词搜索，只查询匹配的订单ID
        if (matchingOrderIds != null && !matchingOrderIds.isEmpty()) {
            wrapper.in(StoreOrder::getId, matchingOrderIds);
        }
        wrapper.orderByDesc(StoreOrder::getCreatedTime);
        
        IPage<StoreOrder> orderPage = this.page(page, wrapper);
        
        // 3. 获取所有订单ID
        List<StoreOrder> orders = orderPage.getRecords();
        if (orders == null || orders.isEmpty()) {
            // 如果没有订单，返回空的分页结果
            Page<StoreOrderPageVO> resultPage = new Page<>(page.getCurrent(), page.getSize());
            resultPage.setTotal(orderPage.getTotal());
            resultPage.setPages(orderPage.getPages());
            return resultPage;
        }
        
        List<Integer> orderIds = orders.stream()
                .map(StoreOrder::getId)
                .collect(Collectors.toList());
        
        // 3. 批量查询所有订单的菜品详情
        LambdaQueryWrapper<StoreOrderDetail> detailWrapper = new LambdaQueryWrapper<>();
        detailWrapper.in(StoreOrderDetail::getOrderId, orderIds);
        detailWrapper.eq(StoreOrderDetail::getDeleteFlag, 0);
        detailWrapper.orderByAsc(StoreOrderDetail::getOrderId);
        detailWrapper.orderByAsc(StoreOrderDetail::getCreatedTime);
        List<StoreOrderDetail> allDetails = orderDetailMapper.selectList(detailWrapper);
        
        // 4. 按订单ID分组菜品详情
        Map<Integer, List<StoreOrderDetail>> detailsMap = allDetails.stream()
                .collect(Collectors.groupingBy(StoreOrderDetail::getOrderId));
        
        // 4.1 批量查询菜品标签（用于分页列表展示）
        Set<Integer> cuisineIds = allDetails.stream()
                .map(StoreOrderDetail::getCuisineId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Map<Integer, String> cuisineIdToTags = new HashMap<>();
        if (!cuisineIds.isEmpty()) {
            List<StoreCuisine> cuisines = storeCuisineMapper.selectBatchIds(new ArrayList<>(cuisineIds));
            if (cuisines != null) {
                for (StoreCuisine c : cuisines) {
                    if (c.getTags() != null) {
                        cuisineIdToTags.put(c.getId(), c.getTags());
                    }
                }
            }
        }
        Map<Integer, String> finalCuisineIdToTags = cuisineIdToTags;
        
        // 5. 批量查询门店名称
        Set<Integer> storeIds = orders.stream().map(StoreOrder::getStoreId).filter(Objects::nonNull).collect(Collectors.toSet());
        Map<Integer, String> storeNameMap = new HashMap<>();
        if (!storeIds.isEmpty()) {
            List<StoreInfo> storeList = storeInfoMapper.selectBatchIds(storeIds);
            if (storeList != null) {
                for (StoreInfo s : storeList) {
                    storeNameMap.put(s.getId(), s.getStoreName());
                }
            }
        }
        
        // 6. 构建返回结果
        List<StoreOrderPageVO> voList = orders.stream().map(order -> {
            StoreOrderPageVO vo = new StoreOrderPageVO();
            vo.setOrder(order);
            vo.setStoreName(storeNameMap.getOrDefault(order.getStoreId(), ""));
            
            // 获取该订单的菜品列表（含菜品标签）
            List<StoreOrderDetail> orderDetails = detailsMap.getOrDefault(order.getId(), new ArrayList<>());
            List<OrderCuisineItemVO> cuisineItems = orderDetails.stream()
                    .map(detail -> {
                        OrderCuisineItemVO item = new OrderCuisineItemVO();
                        item.setCuisineId(detail.getCuisineId());
                        item.setCuisineName(detail.getCuisineName());
                        item.setCuisineImage(detail.getCuisineImage());
                        item.setQuantity(detail.getQuantity());
                        item.setUnitPrice(detail.getUnitPrice());
                        item.setTags(detail.getCuisineId() != null ? finalCuisineIdToTags.get(detail.getCuisineId()) : null);
                        return item;
                    })
                    .collect(Collectors.toList());
            vo.setCuisineItems(cuisineItems);
            
            return vo;
        }).collect(Collectors.toList());
        
        // 7. 构建分页结果
        Page<StoreOrderPageVO> resultPage = new Page<>(page.getCurrent(), page.getSize());
        resultPage.setRecords(voList);
        resultPage.setTotal(orderPage.getTotal());
        resultPage.setPages(orderPage.getPages());
        
        return resultPage;
    }

    @Override
    public boolean completeOrder(Integer orderId) {
        log.info("完成订单, orderId={}", orderId);

        StoreOrder order = this.getById(orderId);
        if (order == null) {
            throw new RuntimeException("订单不存在");
        }

        // 检查订单状态：只有已支付状态(1)的订单才能完成
//        if (order.getOrderStatus() != 1) {
//            throw new RuntimeException("订单状态不正确，只有已支付状态的订单才能完成");
//        }

        // 检查支付状态：确保订单已支付
        if (order.getPayStatus() != 1) {
            throw new RuntimeException("订单未支付，无法完成");
        }

        order.setOrderStatus(3); // 已完成
        order.setUpdatedTime(new Date());

        // 从 token 获取用户信息
        Integer userId = TokenUtil.getCurrentUserId();
        if (userId != null) {
            order.setUpdatedUserId(userId);
        }

        this.updateById(order);

        // 更新桌号状态：显式清空 currentOrderId（updateById 会忽略 null，必须用 LambdaUpdateWrapper）
        Integer tableId = order.getTableId();
        StoreTable table = storeTableMapper.selectById(tableId);
        if (table != null) {
            LambdaUpdateWrapper<StoreTable> tableWrapper = new LambdaUpdateWrapper<>();
            tableWrapper.eq(StoreTable::getId, tableId)
                    .set(StoreTable::getCurrentOrderId, null)
                    .set(StoreTable::getStatus, 0)
                    .set(StoreTable::getDinerCount, null)
                    .set(StoreTable::getUpdatedTime, new Date());
            if (userId != null) {
                tableWrapper.set(StoreTable::getUpdatedUserId, userId);
            }
            storeTableMapper.update(null, tableWrapper);
        }

        log.info("订单完成成功, orderId={}", orderId);
        return true;
    }

    @Override
    public boolean completeOrderByMerchant(Integer orderId) {
        log.info("商家手动完成订单, orderId={}", orderId);

        StoreOrder order = this.getById(orderId);
        if (order == null) {
            throw new RuntimeException("订单不存在");
        }

        // 商家手动完成订单，不校验支付状态，直接设置为已完成
        order.setOrderStatus(3); // 已完成
        order.setUpdatedTime(new Date());

        // 从 token 获取用户信息
        Integer userId = TokenUtil.getCurrentUserId();
        if (userId != null) {
            order.setUpdatedUserId(userId);
        }

        this.updateById(order);

        // 更新桌号状态：显式清空 currentOrderId（updateById 会忽略 null，必须用 LambdaUpdateWrapper）
        Integer tableId = order.getTableId();
        StoreTable table = storeTableMapper.selectById(tableId);
        if (table != null) {
            LambdaUpdateWrapper<StoreTable> tableWrapper = new LambdaUpdateWrapper<>();
            tableWrapper.eq(StoreTable::getId, tableId)
                    .set(StoreTable::getCurrentOrderId, null)
                    .set(StoreTable::getStatus, 0)
                    .set(StoreTable::getDinerCount, null)
                    .set(StoreTable::getUpdatedTime, new Date());
            if (userId != null) {
                tableWrapper.set(StoreTable::getUpdatedUserId, userId);
            }
            storeTableMapper.update(null, tableWrapper);
        }

        log.info("商家手动完成订单成功, orderId={}", orderId);
        return true;
    }

    @Override
    public StoreOrder updateOrderCoupon(Integer orderId, Integer couponId) {
        log.info("更新订单优惠券, orderId={}, couponId={}", orderId, couponId);

        // 验证订单状态
        StoreOrder order = validateOrderForOperation(orderId, 0, "修改优惠券");

        BigDecimal discountAmount = BigDecimal.ZERO;

        if (couponId != null) {
            // 验证优惠券
            LifeDiscountCoupon coupon = lifeDiscountCouponMapper.selectByIdIncludeDeleted(couponId);
            if (coupon == null) {
                throw new RuntimeException("优惠券不存在");
            }

            // 验证优惠券是否属于该门店
            if (!coupon.getStoreId().equals(String.valueOf(order.getStoreId()))) {
                throw new RuntimeException("优惠券不属于该门店");
            }

            // 验证最低消费（菜品总价 + 餐具费）
            BigDecimal totalWithTableware = order.getTotalAmount().add(order.getTablewareFee() != null ? order.getTablewareFee() : BigDecimal.ZERO);
            if (coupon.getMinimumSpendingAmount() != null
                    && totalWithTableware.compareTo(coupon.getMinimumSpendingAmount()) < 0) {
                throw new RuntimeException("订单金额未达到优惠券最低消费要求");
            }

            // 计算优惠金额：根据优惠券类型（满减券或折扣券）计算
            discountAmount = calculateDiscountAmount(coupon, totalWithTableware);
        }

        // 如果之前有优惠券，且优惠券发生变化（包括取消优惠券），需要处理旧优惠券使用记录
        if (order.getCouponId() != null && (couponId == null || !order.getCouponId().equals(couponId))) {
            // 清除旧优惠券的使用标记（如果取消优惠券或更换优惠券）
            cartService.clearCouponUsed(order.getTableId());
            
            LambdaQueryWrapper<StoreCouponUsage> oldUsageWrapper = new LambdaQueryWrapper<>();
            oldUsageWrapper.eq(StoreCouponUsage::getOrderId, orderId);
            oldUsageWrapper.eq(StoreCouponUsage::getCouponId, order.getCouponId());
            oldUsageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
            oldUsageWrapper.orderByDesc(StoreCouponUsage::getCreatedTime);
            oldUsageWrapper.last("LIMIT 1");
            StoreCouponUsage oldUsage = storeCouponUsageMapper.selectOne(oldUsageWrapper);
            if (oldUsage != null) {
                oldUsage.setUsageStatus(3); // 已取消
                oldUsage.setUpdatedTime(new Date());
                storeCouponUsageMapper.updateById(oldUsage);
            }
        }

        // 如果新设置了优惠券，需要标记桌号已使用优惠券，并更新或创建使用记录
        if (couponId != null) {
            // 检查桌号是否已使用优惠券（如果更换优惠券，之前的标记已清除）
            if (!cartService.hasUsedCoupon(order.getTableId())) {
                cartService.markCouponUsed(order.getTableId(), couponId);
            }
            LambdaQueryWrapper<StoreCouponUsage> usageWrapper = new LambdaQueryWrapper<>();
            usageWrapper.eq(StoreCouponUsage::getTableId, order.getTableId());
            usageWrapper.eq(StoreCouponUsage::getCouponId, couponId);
            usageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
            usageWrapper.orderByDesc(StoreCouponUsage::getCreatedTime);
            usageWrapper.last("LIMIT 1");
            StoreCouponUsage usage = storeCouponUsageMapper.selectOne(usageWrapper);
            if (usage != null) {
                usage.setOrderId(orderId);
                usage.setUsageStatus(1); // 已下单
                usage.setDiscountAmount(discountAmount);
                usage.setUpdatedTime(new Date());
                storeCouponUsageMapper.updateById(usage);
            } else {
                // 创建新的使用记录
                StoreTable table = storeTableMapper.selectById(order.getTableId());
                if (table != null) {
                    Date now = new Date();
                    StoreCouponUsage newUsage = new StoreCouponUsage();
                    newUsage.setTableId(order.getTableId());
                    newUsage.setStoreId(order.getStoreId());
                    newUsage.setOrderId(orderId);
                    newUsage.setCouponId(couponId);
                    newUsage.setDiscountAmount(discountAmount);
                    newUsage.setUsageStatus(1); // 已下单
                    newUsage.setCreatedTime(now);
                    newUsage.setUpdatedTime(now); // 设置更新时间，避免数据库约束错误
                    Integer userId = TokenUtil.getCurrentUserId();
                    if (userId != null) {
                        newUsage.setCreatedUserId(userId);
                    }
                    storeCouponUsageMapper.insert(newUsage);
                }
            }
        }

        // 重新计算实付金额（菜品总价 + 餐具费 - 优惠金额）
        BigDecimal tablewareFee = order.getTablewareFee() != null ? order.getTablewareFee() : BigDecimal.ZERO;
        BigDecimal payAmount = order.getTotalAmount().add(tablewareFee).subtract(discountAmount);

        order.setCouponId(couponId);
        order.setCurrentCouponId(couponId);
        order.setDiscountAmount(discountAmount);
        order.setPayAmount(payAmount);
        order.setUpdatedTime(new Date());

        // 从 token 获取用户信息
        Integer userId = TokenUtil.getCurrentUserId();
        if (userId != null) {
            order.setUpdatedUserId(userId);
        }

        this.updateById(order);

        log.info("更新订单优惠券成功, orderId={}", orderId);
        return order;
    }

    @Override
    public boolean resetTable(Integer tableId) {
        log.info("管理员重置餐桌, tableId={}", tableId);
        
        // 验证餐桌是否存在
        StoreTable table = storeTableMapper.selectById(tableId);
        if (table == null) {
            throw new RuntimeException("餐桌不存在");
        }
        
        // 1. 删除购物车数据（逻辑删除，使用 MyBatis-Plus 的 removeBatchIds）
        LambdaQueryWrapper<StoreCart> cartWrapper = new LambdaQueryWrapper<>();
        cartWrapper.eq(StoreCart::getTableId, tableId);
        cartWrapper.eq(StoreCart::getDeleteFlag, 0);
        List<StoreCart> cartList = storeCartMapper.selectList(cartWrapper);
        if (cartList != null && !cartList.isEmpty()) {
            List<Integer> cartIds = cartList.stream()
                    .map(StoreCart::getId)
                    .collect(Collectors.toList());
            // 使用 removeBatchIds 进行逻辑删除（MyBatis-Plus 会自动处理 @TableLogic）
            storeCartMapper.deleteBatchIds(cartIds);
            log.info("删除购物车数据, tableId={}, count={}", tableId, cartList.size());
        }
        
        // 2. 只删除未支付或已取消的订单（保留已支付/已完成的订单，避免数据丢失）
        // 订单状态：0-待支付，1-已支付，2-已取消，3-已完成
        LambdaQueryWrapper<StoreOrder> orderWrapper = new LambdaQueryWrapper<>();
        orderWrapper.eq(StoreOrder::getTableId, tableId);
        orderWrapper.eq(StoreOrder::getDeleteFlag, 0);
        // 只查询未支付(0)或已取消(2)的订单
        orderWrapper.in(StoreOrder::getOrderStatus, 0, 2);
        List<StoreOrder> orderList = this.list(orderWrapper);
        List<Integer> orderIds = new ArrayList<>();
        if (orderList != null && !orderList.isEmpty()) {
            orderIds = orderList.stream()
                    .map(StoreOrder::getId)
                    .collect(Collectors.toList());
            
            // 删除订单明细（逻辑删除，使用 MyBatis-Plus 的 deleteBatchIds）
            for (Integer orderId : orderIds) {
                LambdaQueryWrapper<StoreOrderDetail> detailWrapper = new LambdaQueryWrapper<>();
                detailWrapper.eq(StoreOrderDetail::getOrderId, orderId);
                detailWrapper.eq(StoreOrderDetail::getDeleteFlag, 0);
                List<StoreOrderDetail> detailList = orderDetailMapper.selectList(detailWrapper);
                if (detailList != null && !detailList.isEmpty()) {
                    List<Integer> detailIds = detailList.stream()
                            .map(StoreOrderDetail::getId)
                            .collect(Collectors.toList());
                    // 使用 deleteBatchIds 进行逻辑删除（MyBatis-Plus 会自动处理 @TableLogic）
                    orderDetailMapper.deleteBatchIds(detailIds);
                    log.info("删除订单明细, orderId={}, count={}", orderId, detailList.size());
                }
            }
            
            // 删除订单变更记录（逻辑删除，使用 MyBatis-Plus 的 deleteBatchIds）
            for (Integer orderId : orderIds) {
                LambdaQueryWrapper<StoreOrderChangeLog> changeLogWrapper = new LambdaQueryWrapper<>();
                changeLogWrapper.eq(StoreOrderChangeLog::getOrderId, orderId);
                changeLogWrapper.eq(StoreOrderChangeLog::getDeleteFlag, 0);
                List<StoreOrderChangeLog> changeLogList = orderChangeLogMapper.selectList(changeLogWrapper);
                if (changeLogList != null && !changeLogList.isEmpty()) {
                    List<Integer> changeLogIds = changeLogList.stream()
                            .map(StoreOrderChangeLog::getId)
                            .collect(Collectors.toList());
                    // 使用 deleteBatchIds 进行逻辑删除（MyBatis-Plus 会自动处理 @TableLogic）
                    orderChangeLogMapper.deleteBatchIds(changeLogIds);
                    log.info("删除订单变更记录, orderId={}, count={}", orderId, changeLogList.size());
                }
            }
            
            // 删除订单（逻辑删除，使用 MyBatis-Plus 的 removeByIds）
            // 使用 removeByIds 进行逻辑删除（MyBatis-Plus 会自动处理 @TableLogic）
            this.removeByIds(orderIds);
            log.info("删除未支付/已取消订单数据, tableId={}, count={}", tableId, orderList.size());
        }
        
        // 查询该桌号的所有订单（包括已支付/已完成的），用于后续处理锁定记录
        LambdaQueryWrapper<StoreOrder> allOrderWrapper = new LambdaQueryWrapper<>();
        allOrderWrapper.eq(StoreOrder::getTableId, tableId);
        allOrderWrapper.eq(StoreOrder::getDeleteFlag, 0);
        List<StoreOrder> allOrderList = this.list(allOrderWrapper);
        List<Integer> allOrderIds = new ArrayList<>();
        if (allOrderList != null && !allOrderList.isEmpty()) {
            allOrderIds = allOrderList.stream()
                    .map(StoreOrder::getId)
                    .collect(Collectors.toList());
        }
        
        // 3. 只删除未下单的优惠券使用记录（保留已下单/已支付的记录，避免数据丢失）
        // usageStatus: 0-已标记使用, 1-已下单, 2-已支付, 3-已取消
        LambdaQueryWrapper<StoreCouponUsage> couponUsageWrapper = new LambdaQueryWrapper<>();
        couponUsageWrapper.eq(StoreCouponUsage::getTableId, tableId);
        couponUsageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
        // 只删除已标记使用但未下单的记录（usageStatus=0）
        couponUsageWrapper.eq(StoreCouponUsage::getUsageStatus, 0);
        List<StoreCouponUsage> couponUsageList = storeCouponUsageMapper.selectList(couponUsageWrapper);
        if (couponUsageList != null && !couponUsageList.isEmpty()) {
            List<Integer> couponUsageIds = couponUsageList.stream()
                    .map(StoreCouponUsage::getId)
                    .collect(Collectors.toList());
            // 使用 deleteBatchIds 进行逻辑删除（MyBatis-Plus 会自动处理 @TableLogic）
            storeCouponUsageMapper.deleteBatchIds(couponUsageIds);
            log.info("删除未下单的优惠券使用记录, tableId={}, count={}", tableId, couponUsageList.size());
        }
        
        // 4. 删除该桌号的所有订单锁定记录（逻辑删除）
        // 包括下单锁定（lock_type=1，通过 tableId 查找）和结算锁定（lock_type=2，通过订单ID关联）
        
        // 删除下单锁定（通过 tableId 查找）
        LambdaQueryWrapper<StoreOrderLock> tableLockWrapper = new LambdaQueryWrapper<>();
        tableLockWrapper.eq(StoreOrderLock::getTableId, tableId);
        tableLockWrapper.eq(StoreOrderLock::getDeleteFlag, 0);
        List<StoreOrderLock> tableLockList = storeOrderLockMapper.selectList(tableLockWrapper);
        if (tableLockList != null && !tableLockList.isEmpty()) {
            List<Integer> tableLockIds = tableLockList.stream()
                    .map(StoreOrderLock::getId)
                    .collect(Collectors.toList());
            storeOrderLockMapper.deleteBatchIds(tableLockIds);
            log.info("删除下单锁定记录, tableId={}, count={}", tableId, tableLockList.size());
        }
        
        // 删除结算锁定（通过 orderId 查找，如果有订单的话）
        // 注意：这里使用 allOrderIds，包括所有订单（已删除和未删除的），因为锁定记录可能关联已支付的订单
        if (!allOrderIds.isEmpty()) {
            LambdaQueryWrapper<StoreOrderLock> orderLockWrapper = new LambdaQueryWrapper<>();
            orderLockWrapper.in(StoreOrderLock::getOrderId, allOrderIds);
            orderLockWrapper.eq(StoreOrderLock::getDeleteFlag, 0);
            List<StoreOrderLock> orderLockList = storeOrderLockMapper.selectList(orderLockWrapper);
            if (orderLockList != null && !orderLockList.isEmpty()) {
                List<Integer> orderLockIds = orderLockList.stream()
                        .map(StoreOrderLock::getId)
                        .collect(Collectors.toList());
                storeOrderLockMapper.deleteBatchIds(orderLockIds);
                log.info("删除结算锁定记录, orderIds={}, count={}", allOrderIds, orderLockList.size());
            }
        }
        
        // 5. 清空Redis中的购物车缓存
        String cartKey = "cart:table:" + tableId;
        baseRedisService.delete(cartKey);
        log.info("清空Redis购物车缓存, tableId={}", tableId);
        
        // 6. 清除优惠券使用标记（Redis中的标记）
        cartService.clearCouponUsed(tableId);
        log.info("清除优惠券使用标记, tableId={}", tableId);
        
        // 7. 重置餐桌表（使用 LambdaUpdateWrapper 来显式设置 null 值）
        LambdaUpdateWrapper<StoreTable> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(StoreTable::getId, tableId)
                .set(StoreTable::getCurrentOrderId, null)  // 显式设置 null
                .set(StoreTable::getCurrentCouponId, null)  // 显式设置 null
                .set(StoreTable::getCartItemCount, 0)
                .set(StoreTable::getCartTotalAmount, BigDecimal.ZERO)
                .set(StoreTable::getStatus, 0)  // 空闲
                .set(StoreTable::getDinerCount, null)  // 清空就餐人数
                .set(StoreTable::getUpdatedTime, new Date());
        Integer userId = TokenUtil.getCurrentUserId();
        if (userId != null) {
            updateWrapper.set(StoreTable::getUpdatedUserId, userId);
        }
        storeTableMapper.update(null, updateWrapper);
        log.info("重置餐桌表完成, tableId={}", tableId);
        
        return true;
    }

    /**
     * 支付完成后重置餐桌（保留订单数据，只重置餐桌绑定关系）
     *
     * @param tableId 餐桌ID
     */
    @Override
    public void resetTableAfterPayment(Integer tableId) {
        log.info("支付完成后重置餐桌, tableId={}", tableId);

        // 验证餐桌是否存在
        StoreTable table = storeTableMapper.selectById(tableId);
        if (table == null) {
            log.warn("餐桌不存在，跳过重置, tableId={}", tableId);
            return;
        }

        // 1. 完全清空购物车（包括已下单的商品，因为订单已支付完成）
        // 逻辑删除所有购物车数据
        LambdaQueryWrapper<StoreCart> cartWrapper = new LambdaQueryWrapper<>();
        cartWrapper.eq(StoreCart::getTableId, tableId);
        cartWrapper.eq(StoreCart::getDeleteFlag, 0);
        List<StoreCart> cartList = storeCartMapper.selectList(cartWrapper);
        if (cartList != null && !cartList.isEmpty()) {
            List<Integer> cartIds = cartList.stream()
                    .map(StoreCart::getId)
                    .collect(Collectors.toList());
            storeCartMapper.deleteBatchIds(cartIds);
            log.info("支付完成后删除购物车数据, tableId={}, count={}", tableId, cartList.size());
        }

        // 2. 清空Redis中的购物车缓存
        String cartKey = "cart:table:" + tableId;
        baseRedisService.delete(cartKey);
        log.info("清空Redis购物车缓存, tableId={}", tableId);

        // 3. 清除优惠券使用标记
        cartService.clearCouponUsed(tableId);
        log.info("清除优惠券使用标记, tableId={}", tableId);

        // 4. 重置餐桌表（使用 LambdaUpdateWrapper 来显式设置 null 值）
        LambdaUpdateWrapper<StoreTable> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(StoreTable::getId, tableId)
                .set(StoreTable::getCurrentOrderId, null)  // 显式设置 null
                .set(StoreTable::getCurrentCouponId, null)  // 显式设置 null
                .set(StoreTable::getCartItemCount, 0)
                .set(StoreTable::getCartTotalAmount, BigDecimal.ZERO)
                .set(StoreTable::getStatus, 0)  // 空闲
                .set(StoreTable::getDinerCount, null)  // 清空就餐人数
                .set(StoreTable::getUpdatedTime, new Date());
        Integer userId = TokenUtil.getCurrentUserId();
        if (userId != null) {
            updateWrapper.set(StoreTable::getUpdatedUserId, userId);
        }
        storeTableMapper.update(null, updateWrapper);
        log.info("支付完成后重置餐桌表完成, tableId={}", tableId);
    }

    @Override
    public IPage<StoreOrder> getMyOrders(Page<StoreOrder> page, String type) {
        log.info("查询我的订单, type={}", type);

        // 获取当前用户ID
        Integer userId = TokenUtil.getCurrentUserId();
        if (userId == null) {
            throw new RuntimeException("用户未登录");
        }

        LambdaQueryWrapper<StoreOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreOrder::getDeleteFlag, 0);
        wrapper.eq(StoreOrder::getCreatedUserId, userId); // 查询当前用户创建的订单

        // 根据类型过滤订单
        if ("0".equals(type) || "unpaid".equalsIgnoreCase(type)) {
            // 未支付订单：orderStatus=0 且 payStatus=0
            wrapper.eq(StoreOrder::getOrderStatus, 0);
            wrapper.eq(StoreOrder::getPayStatus, 0);
            log.info("查询未支付订单, userId={}", userId);
        } else if ("1".equals(type) || "history".equalsIgnoreCase(type)) {
            // 历史订单：已支付或已完成的订单（orderStatus=1 或 3，payStatus=1）
            wrapper.and(w -> w.and(w1 -> w1.eq(StoreOrder::getOrderStatus, 1).eq(StoreOrder::getPayStatus, 1))
                    .or(w2 -> w2.eq(StoreOrder::getOrderStatus, 3).eq(StoreOrder::getPayStatus, 1)));
            log.info("查询历史订单, userId={}", userId);
        } else {
            // 如果类型不明确，返回所有订单
            log.warn("订单类型不明确, type={}, 返回所有订单", type);
        }

        wrapper.orderByDesc(StoreOrder::getCreatedTime);
        return this.page(page, wrapper);
    }

    @Override
    public IPage<StoreOrderPageVO> getMyOrdersWithCuisines(Page<StoreOrder> page, String type) {
        log.info("查询我的订单（包含菜品信息）, type={}", type);

        // 1. 查询订单列表
        IPage<StoreOrder> orderPage = getMyOrders(page, type);

        // 2. 获取所有订单ID
        List<StoreOrder> orders = orderPage.getRecords();
        if (orders == null || orders.isEmpty()) {
            // 如果没有订单，返回空的分页结果
            Page<StoreOrderPageVO> resultPage = new Page<>(page.getCurrent(), page.getSize());
            resultPage.setTotal(orderPage.getTotal());
            resultPage.setPages(orderPage.getPages());
            return resultPage;
        }

        List<Integer> orderIds = orders.stream()
                .map(StoreOrder::getId)
                .collect(Collectors.toList());

        // 3. 批量查询所有订单的菜品详情
        LambdaQueryWrapper<StoreOrderDetail> detailWrapper = new LambdaQueryWrapper<>();
        detailWrapper.in(StoreOrderDetail::getOrderId, orderIds);
        detailWrapper.eq(StoreOrderDetail::getDeleteFlag, 0);
        detailWrapper.orderByAsc(StoreOrderDetail::getOrderId);
        detailWrapper.orderByAsc(StoreOrderDetail::getCreatedTime);
        List<StoreOrderDetail> allDetails = orderDetailMapper.selectList(detailWrapper);

        // 4. 按订单ID分组菜品详情
        Map<Integer, List<StoreOrderDetail>> detailsMap = allDetails.stream()
                .collect(Collectors.groupingBy(StoreOrderDetail::getOrderId));

        // 4.1 批量查询菜品标签（用于我的订单分页展示）
        Set<Integer> cuisineIdsMy = allDetails.stream()
                .map(StoreOrderDetail::getCuisineId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Map<Integer, String> cuisineIdToTagsMy = new HashMap<>();
        if (!cuisineIdsMy.isEmpty()) {
            List<StoreCuisine> cuisinesMy = storeCuisineMapper.selectBatchIds(new ArrayList<>(cuisineIdsMy));
            if (cuisinesMy != null) {
                for (StoreCuisine c : cuisinesMy) {
                    if (c.getTags() != null) {
                        cuisineIdToTagsMy.put(c.getId(), c.getTags());
                    }
                }
            }
        }
        Map<Integer, String> finalCuisineIdToTagsMy = cuisineIdToTagsMy;

        // 5. 批量查询门店名称
        Set<Integer> storeIds = orders.stream().map(StoreOrder::getStoreId).filter(Objects::nonNull).collect(Collectors.toSet());
        Map<Integer, String> storeNameMap = new HashMap<>();
        if (!storeIds.isEmpty()) {
            List<StoreInfo> storeList = storeInfoMapper.selectBatchIds(storeIds);
            if (storeList != null) {
                for (StoreInfo s : storeList) {
                    storeNameMap.put(s.getId(), s.getStoreName());
                }
            }
        }

        // 6. 构建返回结果
        List<StoreOrderPageVO> voList = orders.stream().map(order -> {
            StoreOrderPageVO vo = new StoreOrderPageVO();
            vo.setOrder(order);
            vo.setStoreName(storeNameMap.getOrDefault(order.getStoreId(), ""));

            // 获取该订单的菜品列表（含菜品标签）
            List<StoreOrderDetail> orderDetails = detailsMap.getOrDefault(order.getId(), new ArrayList<>());
            List<OrderCuisineItemVO> cuisineItems = orderDetails.stream()
                    .map(detail -> {
                        OrderCuisineItemVO item = new OrderCuisineItemVO();
                        item.setCuisineId(detail.getCuisineId());
                        item.setCuisineName(detail.getCuisineName());
                        item.setCuisineImage(detail.getCuisineImage());
                        item.setQuantity(detail.getQuantity());
                        item.setUnitPrice(detail.getUnitPrice());
                        item.setTags(detail.getCuisineId() != null ? finalCuisineIdToTagsMy.get(detail.getCuisineId()) : null);
                        return item;
                    })
                    .collect(Collectors.toList());
            vo.setCuisineItems(cuisineItems);

            return vo;
        }).collect(Collectors.toList());

        // 7. 构建分页结果
        Page<StoreOrderPageVO> resultPage = new Page<>(page.getCurrent(), page.getSize());
        resultPage.setRecords(voList);
        resultPage.setTotal(orderPage.getTotal());
        resultPage.setPages(orderPage.getPages());

        return resultPage;
    }

    @Override
    public OrderInfoVO getOrderInfo(Integer orderId) {
        log.info("查询订单信息, orderId={}", orderId);
        
        // 1. 查询订单基本信息
        StoreOrder order = this.getById(orderId);
        if (order == null || order.getDeleteFlag() == 1) {
            throw new RuntimeException("订单不存在");
        }
        
        // 2. 查询订单明细（菜品清单）
        LambdaQueryWrapper<StoreOrderDetail> detailWrapper = new LambdaQueryWrapper<>();
        detailWrapper.eq(StoreOrderDetail::getOrderId, orderId);
        detailWrapper.eq(StoreOrderDetail::getDeleteFlag, 0);
        detailWrapper.orderByDesc(StoreOrderDetail::getCreatedTime);
        List<StoreOrderDetail> details = orderDetailMapper.selectList(detailWrapper);
        
        // 批量查询菜品标签（订单明细无 tags，从价目表取）
        java.util.Set<Integer> cuisineIds = details.stream()
                .map(StoreOrderDetail::getCuisineId)
                .filter(java.util.Objects::nonNull)
                .collect(Collectors.toSet());
        java.util.Map<Integer, String> cuisineIdToTags = new java.util.HashMap<>();
        if (!cuisineIds.isEmpty()) {
            List<StoreCuisine> cuisines = storeCuisineMapper.selectBatchIds(cuisineIds);
            if (cuisines != null) {
                for (StoreCuisine c : cuisines) {
                    cuisineIdToTags.put(c.getId(), c.getTags());
                }
            }
        }
        final java.util.Map<Integer, String> tagsMap = cuisineIdToTags;
        
        // 转换为CartItemDTO（含 tags）
        List<CartItemDTO> items = details.stream().map(detail -> {
            CartItemDTO item = new CartItemDTO();
            item.setCuisineId(detail.getCuisineId());
            item.setCuisineName(detail.getCuisineName());
            item.setCuisineType(detail.getCuisineType());
            item.setCuisineImage(detail.getCuisineImage());
            item.setUnitPrice(detail.getUnitPrice());
            item.setQuantity(detail.getQuantity());
            item.setSubtotalAmount(detail.getSubtotalAmount());
            item.setAddUserId(detail.getAddUserId());
            item.setAddUserPhone(detail.getAddUserPhone());
            item.setRemark(detail.getRemark());
            item.setTags(detail.getCuisineId() != null ? tagsMap.get(detail.getCuisineId()) : null);
            return item;
        }).collect(Collectors.toList());
        
        // 3. 查询门店信息
        StoreInfo storeInfo = storeInfoMapper.selectById(order.getStoreId());
        String storeName = "";
        String storeTel = "";
        String storeAddress = "";
        String storeBlurb = "";
        String storeType = "";
        String smid = "";
        Integer businessStatus = null;
        if (storeInfo != null) {
            storeName = storeInfo.getStoreName();
            storeTel = storeInfo.getStoreTel();
            storeAddress = storeInfo.getStoreAddress();
            storeBlurb = storeInfo.getStoreBlurb();
            storeType = storeInfo.getStoreType();
            businessStatus = storeInfo.getBusinessStatus();
            smid = storeInfo.getAlipaySmid();
        }

        // 4. 查询优惠券信息（如果有）
        String couponName = null;
        Integer couponType = null;
        BigDecimal discountRate = null;
        BigDecimal nominalValue = null;
        BigDecimal minimumSpendingAmount = null;
        if (order.getCouponId() != null) {
            LifeDiscountCoupon coupon = lifeDiscountCouponMapper.selectByIdIncludeDeleted(order.getCouponId());
            if (coupon != null) {
                couponName = coupon.getName();
                couponType = coupon.getCouponType();
                discountRate = coupon.getDiscountRate();
                nominalValue = coupon.getNominalValue();
                minimumSpendingAmount = coupon.getMinimumSpendingAmount();
            }
        }

        // 5. 组装OrderInfoVO
        OrderInfoVO vo = new OrderInfoVO();
        vo.setOrderId(order.getId());
        vo.setOrderNo(order.getOrderNo());
        vo.setStoreId(order.getStoreId());
        vo.setStoreName(storeName);
        vo.setStoreTel(storeTel);
        vo.setStoreAddress(storeAddress);
        vo.setStoreBlurb(storeBlurb);
        vo.setStoreType(storeType);
        vo.setBusinessStatus(businessStatus);
        vo.setTableNumber(order.getTableNumber());
        vo.setDinerCount(order.getDinerCount());
        vo.setContactPhone(order.getContactPhone());
        vo.setRemark(order.getRemark());
        vo.setItems(items);
        vo.setTotalAmount(order.getTotalAmount());
        vo.setTablewareFee(order.getTablewareFee());
        vo.setCouponId(order.getCouponId());
        vo.setCouponName(couponName);
        vo.setCouponType(couponType);
        vo.setDiscountRate(discountRate);
        vo.setNominalValue(nominalValue);
        vo.setMinimumSpendingAmount(minimumSpendingAmount);
        vo.setDiscountAmount(order.getDiscountAmount());
        vo.setPayAmount(order.getPayAmount());
        vo.setOrderStatus(order.getOrderStatus());
        vo.setPayStatus(order.getPayStatus());
        vo.setPayType(order.getPayType());
        vo.setCreatedTime(order.getCreatedTime());
        vo.setPayTime(order.getPayTime());
        vo.setSmid(smid);
        
        log.info("查询订单信息完成, orderId={}, itemCount={}", orderId, items.size());
        return vo;
    }

    @Override
    public List<OrderChangeLogBatchVO> getOrderChangeLogs(Integer orderId) {
        log.info("查询订单变更记录, orderId={}", orderId);
        
        // 1. 查询订单的所有变更记录
        LambdaQueryWrapper<StoreOrderChangeLog> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreOrderChangeLog::getOrderId, orderId);
        wrapper.eq(StoreOrderChangeLog::getDeleteFlag, 0);
        wrapper.orderByAsc(StoreOrderChangeLog::getOperationTime);
        wrapper.orderByAsc(StoreOrderChangeLog::getBatchNo);
        List<StoreOrderChangeLog> logs = orderChangeLogMapper.selectList(wrapper);
        
        if (logs == null || logs.isEmpty()) {
            log.info("订单没有变更记录, orderId={}", orderId);
            return new ArrayList<>();
        }
        
        // 2. 按批次号分组
        Map<String, List<StoreOrderChangeLog>> batchMap = logs.stream()
                .collect(Collectors.groupingBy(StoreOrderChangeLog::getBatchNo));
        
        // 2.1 批量查询菜品标签（用于订单详情展示）
        Set<Integer> cuisineIds = logs.stream()
                .map(StoreOrderChangeLog::getCuisineId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Map<Integer, String> cuisineIdToTags = new HashMap<>();
        if (!cuisineIds.isEmpty()) {
            List<StoreCuisine> cuisines = storeCuisineMapper.selectBatchIds(new ArrayList<>(cuisineIds));
            if (cuisines != null) {
                for (StoreCuisine c : cuisines) {
                    if (c.getTags() != null) {
                        cuisineIdToTags.put(c.getId(), c.getTags());
                    }
                }
            }
        }
        
        // 3. 转换为批次VO列表
        List<OrderChangeLogBatchVO> batchList = new ArrayList<>();
        for (Map.Entry<String, List<StoreOrderChangeLog>> entry : batchMap.entrySet()) {
            String batchNo = entry.getKey();
            List<StoreOrderChangeLog> batchLogs = entry.getValue();
            
            if (batchLogs.isEmpty()) {
                continue;
            }
            
            // 取第一条记录作为批次信息（同一批次的操作类型、时间等信息相同）
            StoreOrderChangeLog firstLog = batchLogs.get(0);
            
            OrderChangeLogBatchVO batchVO = new OrderChangeLogBatchVO();
            batchVO.setBatchNo(batchNo);
            batchVO.setOperationType(firstLog.getOperationType());
            batchVO.setOperationTypeText(getOperationTypeText(firstLog.getOperationType()));
            batchVO.setOperationTime(firstLog.getOperationTime());
            batchVO.setOperatorUserId(firstLog.getOperatorUserId());
            batchVO.setOperatorUserPhone(firstLog.getOperatorUserPhone());
            batchVO.setRemark(firstLog.getRemark());
            
            // 计算批次统计信息
            Integer totalQuantityChange = batchLogs.stream()
                    .mapToInt(log -> log.getQuantityChange() != null ? log.getQuantityChange() : 0)
                    .sum();
            BigDecimal totalAmountChange = batchLogs.stream()
                    .map(log -> log.getAmountChange() != null ? log.getAmountChange() : BigDecimal.ZERO)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            
            batchVO.setTotalQuantityChange(totalQuantityChange);
            batchVO.setTotalAmountChange(totalAmountChange);
            batchVO.setItemCount(batchLogs.size());
            
            // 转换为商品项VO列表（含菜品标签）
            Map<Integer, String> finalCuisineIdToTags = cuisineIdToTags;
            List<OrderChangeLogItemVO> items = batchLogs.stream().map(log -> {
                OrderChangeLogItemVO itemVO = new OrderChangeLogItemVO();
                itemVO.setCuisineId(log.getCuisineId());
                itemVO.setCuisineName(log.getCuisineName());
                itemVO.setCuisineType(log.getCuisineType());
                itemVO.setCuisineImage(log.getCuisineImage());
                itemVO.setUnitPrice(log.getUnitPrice());
                itemVO.setQuantityChange(log.getQuantityChange());
                itemVO.setQuantityBefore(log.getQuantityBefore());
                itemVO.setQuantityAfter(log.getQuantityAfter());
                itemVO.setAmountChange(log.getAmountChange());
                itemVO.setRemark(log.getRemark());
                itemVO.setTags(log.getCuisineId() != null ? finalCuisineIdToTags.get(log.getCuisineId()) : null);
                return itemVO;
            }).collect(Collectors.toList());
            
            batchVO.setItems(items);
            batchList.add(batchVO);
        }
        
        log.info("查询订单变更记录完成, orderId={}, batchCount={}", orderId, batchList.size());
        return batchList;
    }

    @Override
    public OrderDetailWithChangeLogVO getOrderDetailWithChangeLog(Integer orderId) {
        log.info("查询订单详情（包含变更记录）, orderId={}", orderId);

        // 1. 查询订单基本信息
        StoreOrder order = this.getById(orderId);
        if (order == null || order.getDeleteFlag() == 1) {
            throw new RuntimeException("订单不存在");
        }

        // 2. 查询门店信息
        StoreInfo storeInfo = storeInfoMapper.selectById(order.getStoreId());
        String storeName = storeInfo != null ? storeInfo.getStoreName() : "";

        // 3. 查询优惠券信息（如果有）
        String couponName = null;
        if (order.getCouponId() != null) {
            LifeDiscountCoupon coupon = lifeDiscountCouponMapper.selectByIdIncludeDeleted(order.getCouponId());
            if (coupon != null) {
                couponName = coupon.getName();
            }
        }

        // 4. 查询订单变更记录（按批次分组）
        List<OrderChangeLogBatchVO> changeLogBatches = getOrderChangeLogs(orderId);

        // 5. 组装OrderDetailWithChangeLogVO
        OrderDetailWithChangeLogVO vo = new OrderDetailWithChangeLogVO();
        vo.setOrderId(order.getId());
        vo.setOrderNo(order.getOrderNo());
        vo.setStoreName(storeName);
        vo.setTableNumber(order.getTableNumber());
        vo.setDinerCount(order.getDinerCount());
        vo.setContactPhone(order.getContactPhone());
        vo.setRemark(order.getRemark());
        vo.setTotalAmount(order.getTotalAmount());
        vo.setTablewareFee(order.getTablewareFee());
        vo.setCouponId(order.getCouponId());
        vo.setCouponName(couponName);
        vo.setDiscountAmount(order.getDiscountAmount());
        vo.setPayAmount(order.getPayAmount());
        vo.setOrderStatus(order.getOrderStatus());
        vo.setPayStatus(order.getPayStatus());
        vo.setPayType(order.getPayType());
        vo.setCreatedTime(order.getCreatedTime());
        vo.setPayTime(order.getPayTime());
        vo.setChangeLogBatches(changeLogBatches);

        log.info("查询订单详情（包含变更记录）完成, orderId={}, batchCount={}", orderId, changeLogBatches.size());
        return vo;
    }
    
    /**
     * 获取操作类型文本
     */
    private String getOperationTypeText(Integer operationType) {
        if (operationType == null) {
            return "未知";
        }
        switch (operationType) {
            case 1:
                return "首次下单";
            case 3:
                return "更新订单";
            default:
                return "未知";
        }
    }

    /**
     * 记录订单变更日志
     *
     * @param orderId 订单ID
     * @param orderNo 订单号
     * @param items 商品列表
     * @param operationType 操作类型(1:首次下单, 3:更新订单)
     * @param operationTime 操作时间
     * @param userId 操作人ID
     * @param userPhone 操作人手机号
     */
    private void recordOrderChangeLog(Integer orderId, String orderNo, List<shop.alien.entity.store.dto.CartItemDTO> items,
                                      Integer operationType, Date operationTime, Integer userId, String userPhone) {
        if (items == null || items.isEmpty()) {
            log.warn("商品列表为空，不记录变更日志, orderId={}", orderId);
            return;
        }

        // 生成批次号：ORDER{orderId}_{yyyyMMddHHmmss}
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String timestamp = sdf.format(operationTime);
        String batchNo = "ORDER" + orderId + "_" + timestamp;

        List<StoreOrderChangeLog> changeLogs = new ArrayList<>();

        for (shop.alien.entity.store.dto.CartItemDTO item : items) {
            Integer lockedQuantity = item.getLockedQuantity(); // 已下单数量
            Integer currentQuantity = item.getQuantity(); // 当前数量
            Integer quantityChange = 0; // 数量变化
            Integer quantityBefore = 0; // 变化前数量
            Integer quantityAfter = 0; // 变化后数量

            if (operationType == 1) {
                // 首次下单：记录所有商品
                quantityBefore = 0;
                quantityAfter = currentQuantity != null ? currentQuantity : 0;
                quantityChange = quantityAfter;
            } else if (operationType == 3) {
                // 更新订单：只记录新增的商品或数量增加的商品
                if (lockedQuantity == null || lockedQuantity == 0) {
                    // 新增商品
                    quantityBefore = 0;
                    quantityAfter = currentQuantity != null ? currentQuantity : 0;
                    quantityChange = quantityAfter;
                } else if (currentQuantity != null && currentQuantity > lockedQuantity) {
                    // 数量增加
                    quantityBefore = lockedQuantity;
                    quantityAfter = currentQuantity;
                    quantityChange = quantityAfter - quantityBefore;
                } else {
                    // 没有变化，跳过
                    continue;
                }
            }

            // 只记录有数量变化的商品
            if (quantityChange == null || quantityChange == 0) {
                continue;
            }

            // 计算金额变化
            BigDecimal amountChange = item.getUnitPrice() != null
                    ? item.getUnitPrice().multiply(BigDecimal.valueOf(quantityChange))
                    : BigDecimal.ZERO;

            StoreOrderChangeLog changeLog = new StoreOrderChangeLog();
            changeLog.setOrderId(orderId);
            changeLog.setOrderNo(orderNo);
            changeLog.setBatchNo(batchNo);
            changeLog.setOperationType(operationType);
            changeLog.setCuisineId(item.getCuisineId());
            changeLog.setCuisineName(item.getCuisineName());
            changeLog.setCuisineType(item.getCuisineType());
            changeLog.setCuisineImage(item.getCuisineImage());
            changeLog.setUnitPrice(item.getUnitPrice());
            changeLog.setQuantityChange(quantityChange);
            changeLog.setQuantityBefore(quantityBefore);
            changeLog.setQuantityAfter(quantityAfter);
            changeLog.setAmountChange(amountChange);
            changeLog.setOperationTime(operationTime);
            changeLog.setOperatorUserId(userId);
            changeLog.setOperatorUserPhone(userPhone);
            changeLog.setRemark(item.getRemark());
            changeLog.setCreatedUserId(userId);
            changeLog.setCreatedTime(operationTime);
            changeLog.setUpdatedTime(operationTime);

            changeLogs.add(changeLog);
        }

        // 批量插入变更记录（使用 MyBatis-Plus 的批量插入）
        if (!changeLogs.isEmpty()) {
            // 使用循环插入（MyBatis-Plus 的 BaseMapper 没有批量插入方法，需要手动实现或使用 ServiceImpl 的 saveBatch）
            // 注意：如果变更记录数量很大，可以考虑使用 MyBatis 的批量插入
            for (StoreOrderChangeLog log : changeLogs) {
                orderChangeLogMapper.insert(log);
            }
            log.info("记录订单变更日志完成, orderId={}, batchNo={}, operationType={}, itemCount={}",
                    orderId, batchNo, operationType, changeLogs.size());
        } else {
            log.warn("没有需要记录的变更, orderId={}, operationType={}", orderId, operationType);
        }
    }

    /**
     * 生成订单号
     */
    private String generateOrderNo() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String timestamp = sdf.format(new Date());
        String random = String.valueOf((int) (Math.random() * 10000));
        return "ORD" + timestamp + String.format("%04d", Integer.parseInt(random));
    }


    @Override
    public void migrateTableData(Integer fromTableId, Integer toTableId, Integer userId) {
        log.info("换桌迁移数据, fromTableId={}, toTableId={}, userId={}", fromTableId, toTableId, userId);

        // 1. 查询原桌号信息
        StoreTable fromTable = storeTableMapper.selectById(fromTableId);
        if (fromTable == null) {
            throw new RuntimeException("原桌号不存在");
        }

        // 2. 查询目标桌号信息
        StoreTable toTable = storeTableMapper.selectById(toTableId);
        if (toTable == null) {
            throw new RuntimeException("目标桌号不存在");
        }

        // 3. 迁移未完成的订单（orderStatus=0 且 payStatus=0）
        if (fromTable.getCurrentOrderId() != null) {
            StoreOrder pendingOrder = this.getById(fromTable.getCurrentOrderId());
            if (pendingOrder != null && pendingOrder.getOrderStatus() == 0 && pendingOrder.getPayStatus() == 0) {
                // 更新订单的桌号信息
                pendingOrder.setTableId(toTableId);
                pendingOrder.setTableNumber(toTable.getTableNumber());
                pendingOrder.setUpdatedUserId(userId);
                pendingOrder.setUpdatedTime(new Date());
                this.updateById(pendingOrder);
                log.info("迁移未完成订单, orderId={}, fromTableId={}, toTableId={}", pendingOrder.getId(), fromTableId, toTableId);

                // 更新订单明细的订单号（如果需要，但通常订单号不变，所以这里只更新 table_id 关联）
                // 订单明细通过 order_id 关联，不需要单独更新
            }
        }

        // 4. 迁移所有未完成的订单（包括可能存在的其他未完成订单）
        LambdaQueryWrapper<StoreOrder> orderWrapper = new LambdaQueryWrapper<>();
        orderWrapper.eq(StoreOrder::getTableId, fromTableId);
        orderWrapper.eq(StoreOrder::getOrderStatus, 0); // 待支付
        orderWrapper.eq(StoreOrder::getPayStatus, 0); // 未支付
        orderWrapper.eq(StoreOrder::getDeleteFlag, 0);
        List<StoreOrder> pendingOrders = this.list(orderWrapper);
        
        if (pendingOrders != null && !pendingOrders.isEmpty()) {
            for (StoreOrder order : pendingOrders) {
                order.setTableId(toTableId);
                order.setTableNumber(toTable.getTableNumber());
                order.setUpdatedUserId(userId);
                order.setUpdatedTime(new Date());
            }
            this.updateBatchById(pendingOrders);
            log.info("迁移未完成订单, count={}, fromTableId={}, toTableId={}", pendingOrders.size(), fromTableId, toTableId);
        }

        // 5. 迁移优惠券使用记录
        LambdaQueryWrapper<StoreCouponUsage> couponUsageWrapper = new LambdaQueryWrapper<>();
        couponUsageWrapper.eq(StoreCouponUsage::getTableId, fromTableId);
        couponUsageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
        couponUsageWrapper.in(StoreCouponUsage::getUsageStatus, 0, 1, 2); // 已标记使用、已下单、已支付
        List<StoreCouponUsage> couponUsages = storeCouponUsageMapper.selectList(couponUsageWrapper);
        
        if (couponUsages != null && !couponUsages.isEmpty()) {
            Date now = new Date();
            for (StoreCouponUsage usage : couponUsages) {
                usage.setFromTableId(fromTableId);
                usage.setTableId(toTableId);
                usage.setMigrateTime(now);
                usage.setUpdatedUserId(userId);
                usage.setUpdatedTime(now);
            }
            // 批量更新
            for (StoreCouponUsage usage : couponUsages) {
                storeCouponUsageMapper.updateById(usage);
            }
            log.info("迁移优惠券使用记录, count={}, fromTableId={}, toTableId={}", couponUsages.size(), fromTableId, toTableId);
        }

        // 6. 更新桌号表的关联信息
        // 原桌号：清空 currentOrderId 和 currentCouponId
        LambdaUpdateWrapper<StoreTable> fromTableWrapper = new LambdaUpdateWrapper<>();
        fromTableWrapper.eq(StoreTable::getId, fromTableId)
                .set(StoreTable::getCurrentOrderId, null)
                .set(StoreTable::getCurrentCouponId, null)
                .set(StoreTable::getUpdatedTime, new Date());
        if (userId != null) {
            fromTableWrapper.set(StoreTable::getUpdatedUserId, userId);
        }
        storeTableMapper.update(null, fromTableWrapper);
        log.info("清空原桌号关联信息, fromTableId={}", fromTableId);

        // 目标桌号：设置 currentOrderId 和 currentCouponId（如果有）
        if (fromTable.getCurrentOrderId() != null || fromTable.getCurrentCouponId() != null) {
            LambdaUpdateWrapper<StoreTable> toTableWrapper = new LambdaUpdateWrapper<>();
            toTableWrapper.eq(StoreTable::getId, toTableId);
            
            if (fromTable.getCurrentOrderId() != null) {
                toTableWrapper.set(StoreTable::getCurrentOrderId, fromTable.getCurrentOrderId());
            }
            if (fromTable.getCurrentCouponId() != null) {
                toTableWrapper.set(StoreTable::getCurrentCouponId, fromTable.getCurrentCouponId());
            }
            toTableWrapper.set(StoreTable::getUpdatedTime, new Date());
            if (userId != null) {
                toTableWrapper.set(StoreTable::getUpdatedUserId, userId);
            }
            storeTableMapper.update(null, toTableWrapper);
            log.info("设置目标桌号关联信息, toTableId={}, currentOrderId={}, currentCouponId={}", 
                    toTableId, fromTable.getCurrentOrderId(), fromTable.getCurrentCouponId());
        }

        log.info("换桌数据迁移完成, fromTableId={}, toTableId={}", fromTableId, toTableId);
    }

    @Override
    public shop.alien.entity.store.dto.CartDTO changeTable(Integer fromTableId, Integer toTableId, String changeReason, Integer userId) {
        log.info("换桌, fromTableId={}, toTableId={}, changeReason={}, userId={}", fromTableId, toTableId, changeReason, userId);

        // 0. 校验：目标桌只能是空桌（空闲且无当前订单）
        if (fromTableId.equals(toTableId)) {
            throw new RuntimeException("原桌号与目标桌号不能相同");
        }
        StoreTable fromTable = storeTableMapper.selectById(fromTableId);
        if (fromTable == null) {
            throw new RuntimeException("原桌号不存在");
        }
        StoreTable toTable = storeTableMapper.selectById(toTableId);
        if (toTable == null) {
            throw new RuntimeException("目标桌号不存在");
        }
        if (!fromTable.getStoreId().equals(toTable.getStoreId())) {
            throw new RuntimeException("原桌号与目标桌号须在同一门店");
        }
        // 空桌：状态为空闲(0)且无当前订单
        boolean emptyStatus = (toTable.getStatus() == null || toTable.getStatus() == 0);
        boolean noOrder = (toTable.getCurrentOrderId() == null);
        if (!emptyStatus || !noOrder) {
            throw new RuntimeException("只能换到空桌，请选择空闲且无订单的桌号");
        }

        // 1. 迁移购物车
        shop.alien.entity.store.dto.CartDTO cart = cartService.migrateCart(fromTableId, toTableId);

        // 2. 迁移所有关联数据（订单、订单变更记录、优惠券使用记录等）
        migrateTableData(fromTableId, toTableId, userId);

        // 3. 记录换桌日志（fromTable、toTable 已在步骤0中查询）
        Date now = new Date();
        StoreTableLog tableLog = new StoreTableLog();
        tableLog.setStoreId(cart.getStoreId());
        tableLog.setOrderId(fromTable.getCurrentOrderId()); // 有订单则记录，仅购物车换桌时为 null
        tableLog.setFromTableId(fromTableId);
        tableLog.setFromTableNumber(fromTable != null ? fromTable.getTableNumber() : null);
        tableLog.setToTableId(toTableId);
        tableLog.setToTableNumber(toTable != null ? toTable.getTableNumber() : null);
        tableLog.setChangeReason(changeReason);
        tableLog.setCreatedUserId(userId);
        tableLog.setCreatedTime(now);
        tableLog.setUpdatedTime(now);
        tableLog.setUpdatedUserId(userId);
        storeTableLogMapper.insert(tableLog);

        // 4. 推送购物车更新消息到新桌号
        sseService.pushCartUpdate(toTableId, cart);

        log.info("换桌完成, fromTableId={}, toTableId={}", fromTableId, toTableId);
        return cart;
    }

    /**
     * 验证订单是否存在且状态正确（用于支付、取消、加餐、更新优惠券等操作）
     *
     * @param orderId      订单ID
     * @param expectedStatus 期望的订单状态（null表示不校验状态）
     * @param operation    操作名称（用于错误提示）
     * @return 订单对象
     */
    private StoreOrder validateOrderForOperation(Integer orderId, Integer expectedStatus, String operation) {
        StoreOrder order = this.getById(orderId);
        if (order == null) {
            throw new RuntimeException("订单不存在");
        }
        if (expectedStatus != null && order.getOrderStatus() != expectedStatus) {
            throw new RuntimeException("订单状态不正确，无法" + operation);
        }
        return order;
    }

    /**
     * 获取当前登录用户信息
     *
     * @return 用户ID和手机号的数组 [userId, userPhone]
     */
    private Object[] getCurrentUserInfo() {
        Integer userId = TokenUtil.getCurrentUserId();
        String userPhone = TokenUtil.getCurrentUserPhone();
        if (userId == null) {
            throw new RuntimeException("用户未登录");
        }
        return new Object[]{userId, userPhone};
    }

    /**
     * 计算优惠金额：根据优惠券类型（满减券或折扣券）计算
     *
     * @param coupon           优惠券对象
     * @param totalWithTableware 订单总金额（含餐具费）
     * @return 优惠金额
     */
    private BigDecimal calculateDiscountAmount(LifeDiscountCoupon coupon, BigDecimal totalWithTableware) {
        if (coupon == null || totalWithTableware == null || totalWithTableware.compareTo(BigDecimal.ZERO) <= 0) {
            return BigDecimal.ZERO;
        }

        Integer couponType = coupon.getCouponType();
        BigDecimal discountAmount = BigDecimal.ZERO;

        if (couponType != null && couponType == 2) {
            // 折扣券：根据折扣率计算优惠金额
            // discountRate: 0-100，例如80表示8折，优惠金额 = 订单金额 * (100 - discountRate) / 100
            BigDecimal discountRate = coupon.getDiscountRate();
            if (discountRate != null && discountRate.compareTo(BigDecimal.ZERO) > 0 && discountRate.compareTo(new BigDecimal(100)) <= 0) {
                // 计算折扣后的金额
                BigDecimal discountedAmount = totalWithTableware.multiply(discountRate).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
                // 优惠金额 = 原价 - 折扣后价格
                discountAmount = totalWithTableware.subtract(discountedAmount);
            }
        } else {
            // 满减券（默认或couponType=1）：使用nominalValue
            discountAmount = coupon.getNominalValue();
            if (discountAmount == null) {
                discountAmount = BigDecimal.ZERO;
            }
            // 优惠金额不能超过订单总金额
            if (discountAmount.compareTo(totalWithTableware) > 0) {
                discountAmount = totalWithTableware;
            }
        }

        return discountAmount;
    }

}
