package com.ruoyi.app.order;

/**
 * 订单商家操作
 */

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ruoyi.app.order.dto.OrderCreatItem;
import com.ruoyi.app.order.dto.OrderCreateInput;
import com.ruoyi.app.order.dto.OrderPushBodyDto;
import com.ruoyi.app.pay.LinePayOrderGuard;
import com.ruoyi.app.pay.LinePayRefundService;
import com.ruoyi.app.utils.PayPush;
import com.ruoyi.app.utils.event.PushEventService;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.service.*;
import com.ruoyi.system.utils.Auth;
import com.ruoyi.system.utils.AuthContext;
import com.ruoyi.system.utils.JwtUtil;
import com.ruoyi.system.domain.dto.InvalidInvoiceDto;
import com.ruoyi.system.utils.OrderLogHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

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

/**
 * PosOrderShOprateController
 *
 * @author ruoyi
 * @date 2023-05-23
 */
@RestController
@RequestMapping("/system/orderShOprate")
public class PosOrderShOprateController extends BaseController {
    @Autowired
    private IPosOrderService posOrderService;
    @Autowired
    private IInfoUserService infoUserService;
    @Autowired
    private PushEventService pushEventService;
    @Autowired
    private OrderLogHelper orderLogHelper;
    @Autowired
    private IPosStoreService posStoreService;
    @Autowired  //经营时间
    private IOperatingHoursService operatingHoursService;
    @Autowired
    private IOrderParentService orderParentService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private OrderInvoiceService orderInvoiceService;
    @Autowired
    private LinePayOrderGuard linePayOrderGuard;
    @Autowired
    private LinePayRefundService linePayRefundService;
    @Autowired
    private IPosOrderLinePaymentService linePaymentService;
    @Autowired
    private OrderLifecycleService orderLifecycleService;
    @Autowired
    private DeliveryOrderNotificationService deliveryOrderNotificationService;
    @Autowired
    private MerchantStoreAccessService merchantStoreAccessService;



    /**
     * 商家端查询订单发票（状态/发票号/凭证）
     */

    @GetMapping("/getInvoice")
    @Auth(session = true)
    @Anonymous
    public AjaxResult getInvoice(@RequestHeader String token, @RequestParam Long orderId) {
        MerchantAccessContext context = requireManagedOrder(orderId);
        return AjaxResult.success(orderInvoiceService.getInvoiceForMerchant(orderId, context.ownerUserId()));
    }

    /**
     * 商家端作废订单发票（仅已开，调 ezPay invoice_invalid）。入参可选 {invalidReason}
     */

    @PutMapping("/invalidInvoice/{orderId}")
    @Auth(session = true)
    @Anonymous
    public AjaxResult invalidInvoice(@RequestHeader String token, @PathVariable Long orderId,
                                     @RequestBody(required = false) InvalidInvoiceDto dto) {
        MerchantAccessContext context = requireManagedOrder(orderId);
        String reason = dto == null ? null : dto.getInvalidReason();
        return toAjax(orderInvoiceService.invalidForMerchant(orderId, reason, context.ownerUserId()));
    }

    /**
     * 商家端下单
     */
    @PostMapping("/createOrder")
    @Auth(session = true)
    @Anonymous
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult createOrder(@RequestHeader String token, @RequestBody OrderCreateInput input)
    {
        Long loginUserId = AuthContext.requireUserId();
        InfoUser merchant = infoUserService.getOne(new LambdaQueryWrapper<InfoUser>()
                .eq(InfoUser::getUserId, loginUserId));
        validateMerchantOrderInput(merchant, input);
        Long ownerUserId = resolveOrderOwner(merchant);
        String shdz=null;
        createOrderParent(input,ownerUserId,shdz);
        createOrderChild(input,ownerUserId,ownerUserId,shdz);

        OrderParent result = orderParentService.getOne(new LambdaQueryWrapper<OrderParent>().eq(OrderParent::getDdId, input.getDdId().toString()));
        System.out.println("创建返回信息："+result);
        return super.success(result);
    }

    //创建父订单
    private void createOrderParent(OrderCreateInput input,Long UserId,String shdz){
        OrderParent orderParent = new OrderParent();
        orderParent.setUserId(UserId);
        orderParent.setOrderStatus(0L);
        orderParent.setTotalAmount(input.getTotalAmount());
        orderParent.setActualPayAmount(input.getActualPayAmount());
        orderParent.setPaymentMethod(input.getPaymentMethod());
//        orderParent.setPaymentTime(new Date());
        orderParent.setCreateTime(new Date());
//        orderParent.setUpdateTime(new Date());
        orderParent.setDdId(input.getDdId().toString());
        orderParent.setTableId(input.getTableId());
        orderParent.setShdzId(input.getShdzId());
        orderParent.setShAddress(shdz);
        orderParent.setType(input.getType());
        orderParent.setRemarks(input.getRemarks());
        orderParentService.save(orderParent);
    }
    //创建子订单
    private void createOrderChild(OrderCreateInput input,Long orderParentId,Long userId,String shdz){
        // 检查items是否为空
        if (input.getItems() == null || input.getItems().isEmpty()) {
            throw new ServiceException(MessageUtils.message("订单商品不能为空"));
        }
        String ddId = input.getDdId().toString();
        List<Long> mdIdList = input.getItems().stream().map(OrderCreatItem::getMdId).collect(Collectors.toList());
        // 将Long类型的门店ID转换为Integer类型用于查询（因为PosStore.getId()返回Integer）
        List<Integer> mdIdIntegerList = mdIdList.stream().map(Long::intValue).collect(Collectors.toList());
        List<PosStore> storeList = posStoreService.list(new LambdaQueryWrapper<PosStore>().in(PosStore::getId, mdIdIntegerList));
        LambdaQueryWrapper<OperatingHours> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(OperatingHours::getMdId, mdIdList);
        List<OperatingHours> hourslist = operatingHoursService.list(wrapper);
        boolean isMultiStore = input.getItems().size() > 1;
        // 循环items，为每个item创建一条PosOrder
        int index = 0;
        for (OrderCreatItem item : input.getItems()) {
            index++;
            // 单店铺：子订单号与父订单一致；多店铺：子订单号追加序号
            String subddId = isMultiStore ? ddId + String.format("%03d", index) : ddId;
            PosOrder posOrder = new PosOrder();
            posOrder.setIsDisplay(true);
            posOrder.setDisplayTime(new Date());
            posOrder.setShdzId(input.getShdzId());
            // 设置子订单的基本信息
            posOrder.setDdId(subddId);
            posOrder.setParentDdId(input.getDdId().toString()); // 设置父订单ID
            posOrder.setCretim(new Date());
            posOrder.setState(1L); // 初始状态
            // 根据item设置订单信息
            posOrder.setShId(item.getShId());
            posOrder.setMdId(item.getMdId());
            posOrder.setShdzId(input.getShdzId());
            posOrder.setUserId(userId);
            posOrder.setAmount(item.getAmount());
            posOrder.setRemarks(item.getRemarks());
            posOrder.setType(item.getType());
            posOrder.setDelryTime(item.getDelryTime());
            posOrder.setFood(JSON.toJSONString(item.getFood()));
            // 设置支付相关信息（从父订单继承）
            posOrder.setPayType(input.getPaymentMethod());
            posOrder.setOrderSource("MERCHANT");
            // 现金支付(4)：创建时未支付，待商家App触发确认收款后置为已支付
            if (OrderLifecycleService.PAY_TYPE_CASH.equals(input.getPaymentMethod())) {
                posOrder.setPayStatus(0L);
            }
            //设置桌号（从父订单继承）
            posOrder.setTableId(input.getTableId());
            posOrder.setTableNo(input.getTableNo());
            posOrder.setLogo(item.getLogo());
            posOrder.setPosName(item.getPosName());
            posOrder.setJvli(item.getJvli());
            posOrder.setFreight(item.getFreight());
            posOrder.setShdzId(input.getShdzId());
            posOrder.setShAddress(shdz);
            posOrder.setFoodAmount(item.getFoodAmount());
            Optional<PosStore> storeOptional = storeList.stream()
                    .filter(x -> item.getMdId().equals(Long.valueOf(x.getId())))
                    .findFirst();
            if (storeOptional.isEmpty()) {
                throw new ServiceException(MessageUtils.message("no.mendian.not.exist"));
            }
            PosStore store = storeOptional.get();
            posOrder.setLongitude(store.getLongitude());
            posOrder.setLatitude(store.getLatitude());
            //设置订单分类
            storeList.stream().filter(s -> Long.valueOf(s.getId()).equals(item.getMdId())).findFirst().ifPresent(st -> {
                posOrder.setOrderCategory(String.valueOf(st.getType()));
            });
            setPickUpNum(posOrder);
            posOrderService.save(posOrder);
        }
    }

    void validateMerchantOrderInput(InfoUser merchant, OrderCreateInput input) {
        if (merchant == null || merchant.getUserId() == null
                || "0".equals(merchant.getUserType()) || "2".equals(merchant.getUserType())) {
            throw new ServiceException(MessageUtils.message("line.pay.offline.merchant.required"));
        }
        if (input == null || input.getItems() == null || input.getItems().size() != 1) {
            throw new ServiceException(MessageUtils.message("line.pay.offline.single.store.required"));
        }
        OrderCreatItem item = input.getItems().get(0);
        if (item == null || item.getMdId() == null || item.getAmount() == null
                || item.getAmount() <= 0) {
            throw new ServiceException(MessageUtils.message("line.pay.offline.order.invalid"));
        }
        if ("5".equals(merchant.getUserType())) {
            MerchantAccessContext context = merchantStoreAccessService.resolve(merchant.getUserId());
            merchantStoreAccessService.requireStoreAccess(merchant.getUserId(), item.getMdId());
            item.setShId(context.ownerUserId());
            return;
        }
        boolean directMerchant = "1".equals(merchant.getUserType())
                || "3".equals(merchant.getUserType());
        PosStore store = directMerchant ? posStoreService.getById(item.getMdId()) : null;
        boolean owned = directMerchant
                ? store != null && merchant.getUserId().equals(item.getShId())
                && merchant.getUserId().equals(store.getUserId())
                : merchant.getStoreId() != null && merchant.getStoreId().equals(item.getMdId());
        if (!owned) {
            throw new ServiceException(MessageUtils.message("line.pay.offline.order.forbidden"));
        }
    }

    private Long resolveOrderOwner(InfoUser merchant) {
        if (merchant != null && "5".equals(merchant.getUserType())) {
            return merchantStoreAccessService.resolve(merchant.getUserId()).ownerUserId();
        }
        return merchant == null ? null : merchant.getUserId();
    }

    //生成取餐码，根据门店id,当天取餐码从1开始累加
    private void setPickUpNum(PosOrder order) {
        if (order == null || order.getMdId() == null) {
            return;
        }
        try {
            // 获取当前日期，格式为 yyyy-MM-dd
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
            String today = dateFormat.format(new Date());

            // 查询当天该门店的最大取餐码
            LambdaQueryWrapper<PosOrder> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(PosOrder::getMdId, order.getMdId());
            queryWrapper.like(PosOrder::getCretim, today);
            queryWrapper.orderByDesc(PosOrder::getPickUpNum);
            queryWrapper.last("LIMIT 1");

            PosOrder lastOrder = posOrderService.getOne(queryWrapper);
            long nextNum = 1L;
            if (lastOrder != null && lastOrder.getPickUpNum() != null) {
                // 直接使用Long类型的取餐码
                nextNum = lastOrder.getPickUpNum() + 1;
            }
            // 生成新的取餐码：直接使用Long数字
            order.setPickUpNum(nextNum);
            logger.info("生成取餐码成功：门店ID={}, 取餐码={}", order.getMdId(), nextNum);

        } catch (Exception e) {
            logger.error("生成取餐码失败：门店ID={}, 错误信息={}", order.getMdId(), e.getMessage(), e);
            // 生成失败时使用时间戳作为备用方案
            Long fallbackPickUpNum = System.currentTimeMillis() % 10000;
            order.setPickUpNum(fallbackPickUpNum);
        }
    }


    /**
     * 商家接单：state 从 0 改为 1
     */
    @Anonymous
    @Auth(session = true)
    @GetMapping("/acceptOrder")
    public AjaxResult acceptOrder(@RequestHeader String token, @RequestParam Long id) {
        PosOrder order = posOrderService.getOne(new LambdaQueryWrapper<PosOrder>().eq(PosOrder::getId, id));
        InfoUser currentUser = requireMerchantOrderAccess(order);
        if (order == null || order.getState() == null || order.getState() != 0L) {
            throw new ServiceException("订单不存在或状态不允许接单");
        }
        linePayOrderGuard.requirePaidBeforeAccept(order);
        requireRiderAssigned(order);
        PosOrder update = new PosOrder();
        update.setId(order.getId());
        update.setState(1L);
        posOrderService.saveOrUpdate(update);
        InfoUser shUser = infoUserService.getOne(new LambdaQueryWrapper<InfoUser>().eq(InfoUser::getUserId, Long.valueOf(new JwtUtil().getusid(token))));
        String shName = shUser != null ? shUser.getNickName() : "";
        orderLogHelper.log(String.valueOf(order.getDdId()), 2, Long.valueOf(new JwtUtil().getusid(token)), shName, "商家" + shName + "已接单");
        return AjaxResult.success();
    }

    /**
     * 商家出餐：state 从 1 改为 2
     * 外送订单保持 deliveryStatus=1（骑手已接单）
     */
    @Anonymous
    @Auth(session = true)
    @GetMapping("/dispatchOrder")
    public AjaxResult dispatchOrder(@RequestHeader String token, @RequestParam Long id) {
        PosOrder order = posOrderService.getOne(new LambdaQueryWrapper<PosOrder>().eq(PosOrder::getId, id));
        requireMerchantOrderAccess(order);
        if (order == null || order.getState() == null || order.getState() != 1L) {
            throw new ServiceException("订单不存在或状态不允许出餐");
        }
        linePayOrderGuard.requirePaidBeforeAccept(order);
        requireRiderAssigned(order);
        PosOrder update = new PosOrder();
        update.setId(order.getId());
        update.setState(2L);
        posOrderService.saveOrUpdate(update);
        InfoUser shUser = infoUserService.getOne(new LambdaQueryWrapper<InfoUser>().eq(InfoUser::getUserId, Long.valueOf(new JwtUtil().getusid(token))));
        String shName = shUser != null ? shUser.getNickName() : "";
        orderLogHelper.log(String.valueOf(order.getDdId()), 2, Long.valueOf(new JwtUtil().getusid(token)), shName, "商家" + shName + "已出餐");
        // 出餐推送
        chuCan(order, update);
        // 出餐自动开票（010 Phase 11）：按订单发票意图自动开，异常不阻断出餐，失败单由运营后台重试
        try {
            orderInvoiceService.autoIssue(order.getId());
        } catch (Exception ignore) {
        }
        return AjaxResult.success();
    }

    /**
     * 商家完成（自取/堂食）：state 从 2 改为 3，payStatus 从 0 改为 1
     */
    @Anonymous
    @Auth(session = true)
    @Transactional(rollbackFor = Exception.class)
    @GetMapping("/completeOrder")
    public AjaxResult completeOrder(@RequestHeader String token, @RequestParam Long id) {
        PosOrder order = posOrderService.getOne(new LambdaQueryWrapper<PosOrder>().eq(PosOrder::getId, id));
        requireMerchantOrderAccess(order);
        if (order == null || order.getState() == null || order.getState() != 2L) {
            throw new ServiceException("订单不存在或状态不允许完成");
        }
        linePayOrderGuard.requirePaidBeforeAccept(order);
        // 仅限自取(type=1)或堂食(type=2)
        if (order.getType() == null || (order.getType() != 1L && order.getType() != 2L)) {
            throw new ServiceException("仅自取和堂食订单支持此操作");
        }
        if (orderLifecycleService.isRealLineOrder(order)) {
            orderLifecycleService.completePaidLineOrder(order.getId());
        } else {
            PosOrder update = new PosOrder();
            update.setId(order.getId());
            update.setState(3L);
            update.setPayStatus(1L);
            posOrderService.saveOrUpdate(update);
        }
        InfoUser shUser = infoUserService.getOne(new LambdaQueryWrapper<InfoUser>().eq(InfoUser::getUserId, Long.valueOf(new JwtUtil().getusid(token))));
        String shName = shUser != null ? shUser.getNickName() : "";
        orderLogHelper.log(String.valueOf(order.getDdId()), 2, Long.valueOf(new JwtUtil().getusid(token)), shName, "商家" + shName + "已完成订单");
        // 商家完成订单时生成商家账单
        PosOrder fullOrder = posOrderService.getById(order.getId());
        if (!orderLifecycleService.isRealLineOrder(order)) {
            orderService.setSanghuBilling(fullOrder);
        }
        return AjaxResult.success();
    }

    /**
     * 商家确认现金收款：payType=4 的订单 payStatus 0→1（现金单创建时未支付，商家收到现金后在App触发）
     */
    @Anonymous
    @Auth(session = true)
    @GetMapping("/confirmCashPayment")
    public AjaxResult confirmCashPayment(@RequestHeader String token, @RequestParam Long id) {
        PosOrder order = posOrderService.getOne(new LambdaQueryWrapper<PosOrder>().eq(PosOrder::getId, id));
        requireMerchantOrderAccess(order);
        if (order == null) {
            throw new ServiceException(MessageUtils.message("no.order.not.exist"));
        }
        if (!OrderLifecycleService.PAY_TYPE_CASH.equals(order.getPayType())) {
            throw new ServiceException(MessageUtils.message("no.order.paytype.not.cash"));
        }
        // 已取消订单不允许确认收款：否则出现 state=4+payStatus=1，无现金退款流程可恢复，只能手工改库
        if (order.getState() != null && order.getState() == 4L) {
            throw new ServiceException(MessageUtils.message("no.order.cash.cancelled"));
        }
        if (Long.valueOf(1L).equals(order.getPayStatus())) {
            throw new ServiceException(MessageUtils.message("no.order.cash.already.paid"));
        }
        PosOrder update = new PosOrder();
        update.setId(order.getId());
        update.setPayStatus(1L);
        posOrderService.saveOrUpdate(update);
        InfoUser shUser = infoUserService.getOne(new LambdaQueryWrapper<InfoUser>().eq(InfoUser::getUserId, Long.valueOf(new JwtUtil().getusid(token))));
        String shName = shUser != null ? shUser.getNickName() : "";
        orderLogHelper.log(String.valueOf(order.getDdId()), 2, Long.valueOf(new JwtUtil().getusid(token)), shName, "商家" + shName + "确认现金收款");
        return AjaxResult.success();
    }

    /**
     * 商家确认转账收款：payType=6 的订单 payStatus 从 0 置 1（用户线下转账、商家核对到账后触发）
     * 外送单确认后推送附近骑手开放接单；与现金确认(confirmCashPayment)相互独立
     */
    @Anonymous
    @Auth(session = true)
    @GetMapping("/confirmTransferPayment")
    public AjaxResult confirmTransferPayment(@RequestHeader String token, @RequestParam Long id) {
        PosOrder order = posOrderService.getOne(new LambdaQueryWrapper<PosOrder>().eq(PosOrder::getId, id));
        requireMerchantOrderAccess(order);
        if (order == null) {
            throw new ServiceException(MessageUtils.message("no.order.not.exist"));
        }
        if (!OrderLifecycleService.PAY_TYPE_TRANSFER.equals(order.getPayType())) {
            throw new ServiceException(MessageUtils.message("no.order.paytype.not.transfer"));
        }
        // 已取消订单不允许确认收款：避免出现已取消+已支付的不可恢复状态（同现金确认）
        if (order.getState() != null && order.getState() == 4L) {
            throw new ServiceException(MessageUtils.message("no.order.transfer.cancelled"));
        }
        if (Long.valueOf(1L).equals(order.getPayStatus())) {
            throw new ServiceException(MessageUtils.message("no.order.transfer.already.paid"));
        }
        PosOrder update = new PosOrder();
        update.setId(order.getId());
        update.setPayStatus(1L);
        posOrderService.saveOrUpdate(update);
        InfoUser shUser = infoUserService.getOne(new LambdaQueryWrapper<InfoUser>().eq(InfoUser::getUserId, Long.valueOf(new JwtUtil().getusid(token))));
        String shName = shUser != null ? shUser.getNickName() : "";
        orderLogHelper.log(String.valueOf(order.getDdId()), 2, Long.valueOf(new JwtUtil().getusid(token)), shName, "商家" + shName + "确认转账收款");
        // 外送单：确认收款即支付完成，通知附近骑手开放接单（同 OMG 支付成功链路）
        if (Long.valueOf(0L).equals(order.getType())) {
            deliveryOrderNotificationService.notifyOrderAvailable(order);
        }
        return AjaxResult.success();
    }

    /**
     * 商家取消订单：校验 state IN (0,1)，设 state=4
     */
    @Anonymous
    @Auth(session = true)
    @GetMapping("/cancelOrder")
    public AjaxResult cancelOrder(@RequestHeader String token, @RequestParam Long id) {
        PosOrder order = posOrderService.getOne(new LambdaQueryWrapper<PosOrder>().eq(PosOrder::getId, id));
        InfoUser currentUser = requireMerchantOrderAccess(order);
        if (order == null || order.getState() == null) {
            throw new ServiceException("订单不存在");
        }
        if (order.getState() != 0L && order.getState() != 1L) {
            throw new ServiceException("当前状态不允许取消");
        }
        PosOrder update = new PosOrder();
        update.setState(4L);
        boolean cancelled = posOrderService.update(update, new LambdaUpdateWrapper<PosOrder>()
                .eq(PosOrder::getId, order.getId())
                .in(PosOrder::getState, 0L, 1L));
        if (!cancelled) {
            throw new ServiceException("订单状态已变化，请刷新后重试");
        }

        // 取消落库后按最新支付状态退款，避免漏掉与取消并发到达的成功回调。
        PosOrder latest = posOrderService.getById(order.getId());
        requestLineRefundIfPaid(latest, "STORE_CANCEL");
        InfoUser shUser = infoUserService.getOne(new LambdaQueryWrapper<InfoUser>().eq(InfoUser::getUserId, Long.valueOf(new JwtUtil().getusid(token))));
        String shName = shUser != null ? shUser.getNickName() : "";
        orderLogHelper.log(String.valueOf(order.getDdId()), 2, Long.valueOf(new JwtUtil().getusid(token)), shName, "商家" + shName + "取消订单");
        deliveryOrderNotificationService.notifyOrderCancelled(order, currentUser.getUserId());
        return AjaxResult.success();
    }

    private void requireRiderAssigned(PosOrder order) {
        if (Long.valueOf(0L).equals(order.getType())
                && (!Long.valueOf(1L).equals(order.getDeliveryStatus()) || order.getQsId() == null)) {
            throw new ServiceException(MessageUtils.message("no.order.rider.accept.required"));
        }
    }

    private InfoUser currentMerchant() {
        Long userId = AuthContext.requireUserId();
        InfoUser user = infoUserService.getOne(new LambdaQueryWrapper<InfoUser>()
                .eq(InfoUser::getUserId, userId));
        if (user == null) {
            throw new ServiceException("用户信息不存在");
        }
        return user;
    }

    private InfoUser requireMerchantOrderAccess(PosOrder order) {
        InfoUser user = currentMerchant();
        if ("1".equals(user.getUserType()) || "5".equals(user.getUserType())) {
            merchantStoreAccessService.requireOrderAccess(user.getUserId(), order == null ? null : order.getId());
        } else {
            linePayOrderGuard.requireMerchantOwnership(order, user);
        }
        return user;
    }

    private MerchantAccessContext requireManagedOrder(Long orderId) {
        Long loginUserId = AuthContext.requireUserId();
        InfoUser user = infoUserService.getOne(new LambdaQueryWrapper<InfoUser>()
                .eq(InfoUser::getUserId, loginUserId));
        if (user != null && ("1".equals(user.getUserType()) || "5".equals(user.getUserType()))) {
            MerchantAccessContext context = merchantStoreAccessService.resolve(loginUserId);
            merchantStoreAccessService.requireOrderAccess(loginUserId, orderId);
            return context;
        }
        PosOrder order = posOrderService.getById(orderId);
        linePayOrderGuard.requireMerchantOwnership(order, user);
        return new MerchantAccessContext(loginUserId, loginUserId, true,
                order == null || order.getMdId() == null ? Set.of() : Set.of(order.getMdId()));
    }

    private void requestLineRefundIfPaid(PosOrder order, String source) {
        if (order == null || !Long.valueOf(1L).equals(order.getPayStatus())) {
            return;
        }
        linePaymentService.getByDdId(String.valueOf(order.getDdId())).stream()
                .filter(payment -> "PAID".equals(payment.getStatus()))
                .findFirst()
                .ifPresent(payment -> linePayRefundService.createRefundIntent(payment.getId(), source));
    }

    /**
     * 商家出餐推送：给用户和骑手推送通知
     */
    public void chuCan(PosOrder oldOrder, PosOrder posOrder) {
        List<Long> ids = new ArrayList<>();
        ids.add(oldOrder.getUserId());
        if (oldOrder.getQsId() != null) {
            ids.add(oldOrder.getQsId());
        }
        List<InfoUser> users = infoUserService.list(new LambdaQueryWrapper<InfoUser>().in(InfoUser::getUserId, ids));
        Optional<InfoUser> user = users.stream().filter(x -> "0".equals(x.getUserType())).findFirst();
        Optional<InfoUser> qsUser = users.stream().filter(x -> "2".equals(x.getUserType())).findFirst();

        String title = "no.message.push.message";
        String content = "no.message.push.merchant.ready.content";
        Long stateVal = posOrder.getState() != null ? posOrder.getState() : oldOrder.getState();
        String stateStr = stateVal != null ? String.valueOf(stateVal) : "2";
        String body = OrderPushBodyDto.getJson(String.valueOf(oldOrder.getDdId()), stateStr);
        String ddId = String.valueOf(oldOrder.getDdId());

        if (user.isPresent()) {
            InfoUser u = user.get();
            PayPush push = new PayPush();
            Long uUserId = u.getUserId();
            String uCid = u.getCid();
            AsyncManager.me().execute(new TimerTask() {
                @Override
                public void run() {
                    PayPush.userPushHandleLocal(push, pushEventService, uUserId, uCid, title, content, body, "", ddId);
                }
            });
        }
        if (qsUser.isPresent()) {
            InfoUser qs = qsUser.get();
            if (!StringUtils.isEmpty(qs.getCid())) {
                PayPush push = new PayPush();
                Long qsUserId = qs.getUserId();
                String qsCid = qs.getCid();
                AsyncManager.me().execute(new TimerTask() {
                    @Override
                    public void run() {
                        PayPush.qsPushHandleLocal(push, pushEventService, qsUserId, qsCid, title, content, body, "", ddId);
                    }
                });
            }
        }
    }

    /**
     * 商家端订单列表（Tab分页）
     * ta
     */
    @Anonymous
    @Auth(session = true)
    @GetMapping("/orderList")
    public AjaxResult orderList(@RequestHeader String token,
                                @RequestParam(defaultValue = "1") int page,
                                @RequestParam(defaultValue = "10") int size,
                                @RequestParam(required = false) String tab,
                                @RequestParam(required = false) Long mdId,
                                @RequestParam(required = false) String type) {
        Long loginUserId = AuthContext.requireUserId();
        // 查询当前用户信息
        InfoUser currentUser = infoUserService.getOne(new LambdaQueryWrapper<InfoUser>().eq(InfoUser::getUserId, loginUserId));
        if (currentUser == null) {
            throw new ServiceException("用户信息不存在");
        }

        LambdaQueryWrapper<PosOrder> wrapper = new LambdaQueryWrapper<>();
        String userType = currentUser.getUserType();
        if ("1".equals(userType) || "5".equals(userType)) {
            Set<Long> storeIds = merchantStoreAccessService.getAccessibleStoreIds(loginUserId);
            if (mdId != null) {
                merchantStoreAccessService.requireStoreAccess(loginUserId, mdId);
                wrapper.eq(PosOrder::getMdId, mdId);
            } else if (storeIds.isEmpty()) {
                wrapper.apply("1 = 0");
            } else {
                wrapper.in(PosOrder::getMdId, storeIds);
            }
        } else if ("3".equals(userType)) {
            // 夜市商家：shId等于用户id
            wrapper.eq(PosOrder::getShId, loginUserId).eq(mdId != null, PosOrder::getMdId, mdId);
        } else {
            // 摊位商家：mdId等于用户表中的storeId
            if (currentUser.getStoreId() == null) {
                throw new ServiceException("摊位关联门店信息不存在");
            }
            wrapper.eq(PosOrder::getMdId, currentUser.getStoreId());
        }
        if (type != null && !type.isEmpty()) {
            wrapper.eq(PosOrder::getType, Long.valueOf(type));
        }
        switch (tab == null ? "" : tab) {
            case "pending":
                wrapper.eq(PosOrder::getState, 0L)
                       // 现金自取/堂食可直接待受理；在线支付的自取/堂食必须先完成付款。
                       .and(w -> w.eq(PosOrder::getPayStatus, 1L)
                               .or(cash -> cash.eq(PosOrder::getPayType, "1")
                                       .in(PosOrder::getType, 1L, 2L)));
                break;
            case "preparing":
                wrapper.eq(PosOrder::getState, 1L);
                break;
            case "ready":
                wrapper.eq(PosOrder::getState, 2L).eq(PosOrder::getAfterSaleStatus, 0L);
                break;
            case "completed":
                wrapper.eq(PosOrder::getState, 3L).eq(PosOrder::getAfterSaleStatus, 0L);
                break;
            case "cancelled":
                wrapper.eq(PosOrder::getState, 4L).eq(PosOrder::getAfterSaleStatus, 0L);
                break;
            case "refund":
                wrapper.gt(PosOrder::getAfterSaleStatus, 0L);
                break;
            default:
               break;
        }
        wrapper.orderByDesc(PosOrder::getCretim);

        com.baomidou.mybatisplus.extension.plugins.pagination.Page<PosOrder> pageParam =
                new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(page, size);
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<PosOrder> result = posOrderService.page(pageParam, wrapper);

        return success(result);
    }

    @Anonymous
    @Auth(session = true)
    @GetMapping("/orderDetail")
    public AjaxResult orderDetail(@RequestHeader String token, @RequestParam Long id) {
        requireManagedOrder(id);
        PosOrder order = posOrderService.getById(id);
        if (order == null) {
            throw new ServiceException(MessageUtils.message("merchant.order.not.found"));
        }
        return success(order);
    }

}
