package com.ruoyi.app.order;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ruoyi.app.order.dto.AdminOrderActionRequest;
import com.ruoyi.app.order.dto.AdminOrderStatusContext;
import com.ruoyi.app.order.dto.AdminOrderStatusUpdateRequest;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.system.domain.PointsTransaction;
import com.ruoyi.system.domain.PosOrder;
import com.ruoyi.system.domain.PosOrderLinePayment;
import com.ruoyi.system.domain.PosOrderLineRefund;
import com.ruoyi.system.domain.UserWallet;
import com.ruoyi.system.service.IPosOrderService;
import com.ruoyi.system.service.IPosOrderLinePaymentService;
import com.ruoyi.system.service.IPosOrderLineRefundService;
import com.ruoyi.system.service.IPointsTransactionService;
import com.ruoyi.system.service.IUserWalletService;
import com.ruoyi.system.utils.OrderLogHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

@Service
public class OrderLifecycleService {

    public static final String PAY_TYPE_OFFLINE = "1";
    public static final String PAY_TYPE_OMG = "2";
    /** 现金支付：仅商家创建订单可用(客户端下单拒绝)；创建时未支付，商家App确认收款后置已支付 */
    public static final String PAY_TYPE_CASH = "4";
    /** 線下轉賬支付：用户线下银行转账，商家确认收款(payStatus 从 0 置 1)后解锁骑手接单 */
    public static final String PAY_TYPE_TRANSFER = "6";
    /** Apple Pay（023 重定义：历史 payType=5 无业务价值，5 现专指 Apple Pay） */
    public static final String PAY_TYPE_APPLE_PAY = "5";

    /** 银行卡类支付组（023）：信用卡与 Apple Pay 共用同一支付商（当前为 OMG）；判定订单是否走 OMG 渠道时用本方法而非单比 payType */
    public static boolean isCardWalletPayType(String payType) {
        return PAY_TYPE_OMG.equals(payType) || PAY_TYPE_APPLE_PAY.equals(payType);
    }

    private final IPosOrderService posOrderService;
    private final OrderService billingService;
    private final OrderLogHelper orderLogHelper;
    private final IUserWalletService userWalletService;
    private final IPointsTransactionService pointsTransactionService;
    private final IPosOrderLinePaymentService linePaymentService;
    private final IPosOrderLineRefundService lineRefundService;
    private final RiderDeliveryLockService riderDeliveryLockService;
    private final RiderDeliveryExclusivityService riderDeliveryExclusivityService;

    public OrderLifecycleService(IPosOrderService posOrderService,
                                 OrderService billingService,
                                 OrderLogHelper orderLogHelper,
                                 IUserWalletService userWalletService,
                                 IPointsTransactionService pointsTransactionService) {
        this(posOrderService, billingService, orderLogHelper, userWalletService,
                pointsTransactionService, null, null, null, null);
    }

    public OrderLifecycleService(IPosOrderService posOrderService,
                                 OrderService billingService,
                                 OrderLogHelper orderLogHelper,
                                 IUserWalletService userWalletService,
                                 IPointsTransactionService pointsTransactionService,
                                 IPosOrderLinePaymentService linePaymentService,
                                 IPosOrderLineRefundService lineRefundService) {
        this(posOrderService, billingService, orderLogHelper, userWalletService,
                pointsTransactionService, linePaymentService, lineRefundService, null, null);
    }

    @Autowired
    public OrderLifecycleService(IPosOrderService posOrderService,
                                 OrderService billingService,
                                 OrderLogHelper orderLogHelper,
                                 IUserWalletService userWalletService,
                                 IPointsTransactionService pointsTransactionService,
                                 IPosOrderLinePaymentService linePaymentService,
                                 IPosOrderLineRefundService lineRefundService,
                                 RiderDeliveryLockService riderDeliveryLockService,
                                 RiderDeliveryExclusivityService riderDeliveryExclusivityService) {
        this.posOrderService = posOrderService;
        this.billingService = billingService;
        this.orderLogHelper = orderLogHelper;
        this.userWalletService = userWalletService;
        this.pointsTransactionService = pointsTransactionService;
        this.linePaymentService = linePaymentService;
        this.lineRefundService = lineRefundService;
        this.riderDeliveryLockService = riderDeliveryLockService;
        this.riderDeliveryExclusivityService = riderDeliveryExclusivityService;
    }

    public AdminOrderStatusContext getStatusContext(Long id) {
        return buildContext(requireOrder(id));
    }

    @Transactional(rollbackFor = Exception.class)
    public Long reserveLineRefund(Long id, String source) {
        PosOrder order = posOrderService.getOne(new LambdaQueryWrapper<PosOrder>()
                .eq(PosOrder::getId, id).last("FOR UPDATE"));
        if (order == null) {
            throw new ServiceException(lineMessage("line.pay.order.not.found", "LINE Pay order not found"));
        }
        if (!"3".equals(order.getPayType()) || Long.valueOf(3L).equals(order.getState())
                || !Long.valueOf(1L).equals(order.getPayStatus())
                || !Long.valueOf(0L).equals(order.getAfterSaleStatus())) {
            throw new ServiceException(lineMessage("line.pay.refund.not.allowed",
                    "Current order state does not allow LINE Pay refund"));
        }
        PosOrderLinePayment payment = linePaymentService == null
                ? null : selectLinePaymentForAdmin(
                linePaymentService.getByDdId(String.valueOf(order.getDdId())));
        if (payment == null || !"PAID".equals(payment.getStatus())) {
            throw new ServiceException(lineMessage("line.pay.refund.payment.not.found",
                    "No refundable LINE Pay payment exists"));
        }
        PosOrderLineRefund refund = lineRefundService == null
                ? null : lineRefundService.getByPaymentId(payment.getId());
        if (refund != null && "REFUNDED".equals(refund.getStatus())) {
            throw new ServiceException(lineMessage("line.pay.refund.already.completed",
                    "LINE Pay payment is already refunded"));
        }
        lineRefundService.createIfAbsent(payment, source);
        return payment.getId();
    }

    public boolean isRealLineOrder(PosOrder order) {
        if (order == null || !"3".equals(order.getPayType()) || order.getDdId() == null
                || linePaymentService == null) {
            return false;
        }
        List<PosOrderLinePayment> attempts = linePaymentService
                .getByDdId(String.valueOf(order.getDdId()));
        return attempts != null && !attempts.isEmpty();
    }

    @Transactional(rollbackFor = Exception.class)
    public void completePaidLineOrder(Long id) {
        PosOrder order = posOrderService.getOne(new LambdaQueryWrapper<PosOrder>()
                .eq(PosOrder::getId, id).last("FOR UPDATE"));
        if (!isRealLineOrder(order) || !Long.valueOf(2L).equals(order.getState())
                || !Long.valueOf(1L).equals(order.getPayStatus())
                || !Long.valueOf(0L).equals(order.getAfterSaleStatus())) {
            throw new ServiceException(lineMessage("line.pay.order.completion.not.allowed",
                    "Current LINE Pay order state does not allow completion"));
        }
        PosOrder update = new PosOrder();
        update.setState(3L);
        applyCas(order, update);
        order.setState(3L);
        completeSideEffects(order);
    }

    @Transactional(rollbackFor = Exception.class)
    public void acceptDeliveryByRider(Long id, Long riderId) {
        riderDeliveryLockService.withLock(riderId, () -> {
            riderDeliveryExclusivityService.assertCanAcceptFood(riderId);
            acceptDeliveryByRiderLocked(id, riderId);
            return null;
        });
    }

    private void acceptDeliveryByRiderLocked(Long id, Long riderId) {
        PosOrder order = requireOrder(id);
        if (!Long.valueOf(0L).equals(order.getType()) || !Long.valueOf(0L).equals(order.getState())
                || !Long.valueOf(0L).equals(order.getDeliveryStatus())
                || !Long.valueOf(1L).equals(order.getPayStatus())
                || !Long.valueOf(0L).equals(order.getAfterSaleStatus()) || order.getQsId() != null) {
            throw conflict();
        }
        PosOrder update = new PosOrder();
        update.setDeliveryStatus(1L);
        update.setQsId(riderId);
        applyCas(order, update);
    }

    @Transactional(rollbackFor = Exception.class)
    public void pickupDeliveryByRider(Long id, Long riderId, String riderImage) {
        PosOrder order = requireOrder(id);
        if (!Long.valueOf(0L).equals(order.getType()) || !Long.valueOf(2L).equals(order.getState())
                || !Long.valueOf(1L).equals(order.getDeliveryStatus())
                || !Long.valueOf(0L).equals(order.getAfterSaleStatus())
                || order.getQsId() == null || !order.getQsId().equals(riderId)) {
            throw conflict();
        }
        PosOrder update = new PosOrder();
        update.setDeliveryStatus(2L);
        update.setQsImg(riderImage);
        applyCas(order, update);
    }

    public void auditExternalAction(Long id, AdminOrderActionRequest request,
                                    Long operatorId, String operatorName, String action) {
        PosOrder order = requireOrder(id);
        logStatusChange(order, request, operatorId, operatorName,
                request.getExpectedState(), request.getExpectedDeliveryStatus(),
                request.getExpectedPayStatus(), request.getExpectedAfterSaleStatus(), action);
    }

    @Transactional(rollbackFor = Exception.class)
    public AdminOrderStatusContext updateStatus(Long id, AdminOrderStatusUpdateRequest request,
                                                Long operatorId, String operatorName) {
        requireReason(request);
        PosOrder order = requireOrder(id);
        validateSnapshot(order, request);
        rejectNormalAdjustmentWhenBlocked(order);

        Long targetState = request.getTargetState();
        Long targetDelivery = request.getTargetDeliveryStatus();
        if (targetState == null && targetDelivery == null) {
            throw new ServiceException("请选择需要调整的状态");
        }

        Long nextState = order.getState();
        Long nextDelivery = order.getDeliveryStatus();
        Date deliveredAt = order.getSdTime();

        if (targetDelivery != null && !Objects.equals(targetDelivery, order.getDeliveryStatus())) {
            validateDeliveryTransition(order, targetDelivery);
            nextDelivery = targetDelivery;
            if (targetDelivery == 3L) {
                nextState = 3L;
                deliveredAt = new Date();
            }
        }

        if (targetState != null && !Objects.equals(targetState, order.getState())) {
            validateOrderTransition(order, targetState, nextDelivery);
            nextState = targetState;
            if (order.getState() == 1L && targetState == 2L
                    && order.getType() == 0L && nextDelivery == null) {
                nextDelivery = 0L;
            }
        }

        if (Objects.equals(nextState, order.getState())
                && Objects.equals(nextDelivery, order.getDeliveryStatus())) {
            return buildContext(order);
        }
        validateResultInvariants(order, nextState, nextDelivery, order.getPayStatus(), order.getAfterSaleStatus());

        PosOrder update = new PosOrder();
        update.setState(nextState);
        update.setDeliveryStatus(nextDelivery);
        if (nextState == 3L && order.getState() != 3L) {
            update.setSdTime(deliveredAt == null ? new Date() : deliveredAt);
        }
        applyCas(order, update);

        order.setState(nextState);
        order.setDeliveryStatus(nextDelivery);
        if (update.getSdTime() != null) {
            order.setSdTime(update.getSdTime());
        }
        if (nextState == 3L) {
            completeSideEffects(order);
        }
        logStatusChange(order, request, operatorId, operatorName,
                request.getExpectedState(), request.getExpectedDeliveryStatus(),
                request.getExpectedPayStatus(), request.getExpectedAfterSaleStatus(),
                "平台调整[订单/配送]");
        return buildContext(order);
    }

    @Transactional(rollbackFor = Exception.class)
    public AdminOrderStatusContext confirmOfflinePayment(Long id, AdminOrderActionRequest request,
                                                         Long operatorId, String operatorName) {
        requireReason(request);
        PosOrder order = requireOrder(id);
        validateSnapshot(order, request);
        if (!PAY_TYPE_OFFLINE.equals(order.getPayType())) {
            throw new ServiceException("仅线下支付订单可以确认收款，OMG 订单请使用支付补单");
        }
        if (order.getPayStatus() != 0L || order.getState() == 3L || order.getState() == 4L
                || order.getAfterSaleStatus() != 0L) {
            throw new ServiceException("当前订单状态不允许确认线下收款");
        }

        PosOrder update = new PosOrder();
        update.setPayStatus(1L);
        applyCas(order, update);
        order.setPayStatus(1L);
        logStatusChange(order, request, operatorId, operatorName,
                request.getExpectedState(), request.getExpectedDeliveryStatus(),
                request.getExpectedPayStatus(), request.getExpectedAfterSaleStatus(),
                "平台确认线下收款");
        return buildContext(order);
    }

    @Transactional(rollbackFor = Exception.class)
    public AdminOrderStatusContext confirmOfflineRefund(Long id, AdminOrderActionRequest request,
                                                        Long operatorId, String operatorName) {
        requireReason(request);
        PosOrder order = requireOrder(id);
        validateSnapshot(order, request);
        if (!PAY_TYPE_OFFLINE.equals(order.getPayType())) {
            throw new ServiceException("仅线下支付订单可以确认线下退款");
        }
        validateRefundableOrder(order);

        PosOrder update = refundedOrderUpdate();
        applyCas(order, update);
        order.setState(4L);
        order.setPayStatus(2L);
        order.setAfterSaleStatus(3L);
        refundPoints(order);
        logStatusChange(order, request, operatorId, operatorName,
                request.getExpectedState(), request.getExpectedDeliveryStatus(),
                request.getExpectedPayStatus(), request.getExpectedAfterSaleStatus(),
                "平台确认线下退款");
        return buildContext(order);
    }

    @Transactional(rollbackFor = Exception.class)
    public AdminOrderStatusContext finalizeSystemLineRefund(Long id) {
        PosOrder order = requireOrder(id);
        if (order.getState() == 4L && order.getPayStatus() == 2L && order.getAfterSaleStatus() == 3L) {
            return buildContext(order);
        }
        if (!"3".equals(order.getPayType()) || order.getPayStatus() != 2L
                || order.getAfterSaleStatus() != 0L || order.getState() == 3L) {
            throw new ServiceException("LINE Pay refund order state requires reconciliation");
        }
        Long beforeState = order.getState();
        PosOrder update = refundedOrderUpdate();
        applyCas(order, update);
        order.setState(4L);
        order.setPayStatus(2L);
        order.setAfterSaleStatus(3L);
        refundPoints(order);
        orderLogHelper.logSync(String.valueOf(order.getDdId()), 0, null, "system",
                "LINE Pay refund synchronized: state " + beforeState + ", pay 1->2, afterSale 0->3");
        return buildContext(order);
    }

    @Transactional(rollbackFor = Exception.class)
    public AdminOrderStatusContext completeDeliveryByRider(Long id, Long riderId, String riderName) {
        return completeDeliveryByRider(id, riderId, riderName, null);
    }

    @Transactional(rollbackFor = Exception.class)
    public AdminOrderStatusContext completeDeliveryByRider(Long id, Long riderId, String riderName,
                                                           String riderImage) {
        PosOrder order = requireOrder(id);
        if (order.getType() != 0L || order.getState() != 2L || order.getDeliveryStatus() == null
                || order.getDeliveryStatus() != 2L || order.getAfterSaleStatus() != 0L
                || order.getQsId() == null || !order.getQsId().equals(riderId)) {
            throw new ServiceException("当前订单状态不允许确认送达");
        }
        Long nextPayStatus = order.getPayStatus();
        if (nextPayStatus != 1L) {
            if (nextPayStatus == 0L && (PAY_TYPE_OFFLINE.equals(order.getPayType())
                    || "1".equals(order.getCollectPayment()))) {
                nextPayStatus = 1L;
            } else {
                throw new ServiceException("订单尚未支付，不能确认送达");
            }
        }

        PosOrder update = new PosOrder();
        update.setState(3L);
        update.setDeliveryStatus(3L);
        update.setPayStatus(nextPayStatus);
        update.setSdTime(new Date());
        if (riderImage != null && !riderImage.isBlank()) {
            update.setQsImg(riderImage);
        }
        applyCas(order, update);
        Long oldPayStatus = order.getPayStatus();
        order.setState(3L);
        order.setDeliveryStatus(3L);
        order.setPayStatus(nextPayStatus);
        order.setSdTime(update.getSdTime());
        completeSideEffects(order);
        orderLogHelper.logSync(String.valueOf(order.getDdId()), 3, riderId, safeName(riderName),
                "骑手确认送达：state 2→3，delivery 2→3，pay " + oldPayStatus + "→" + nextPayStatus);
        return buildContext(order);
    }

    private PosOrder refundedOrderUpdate() {
        PosOrder update = new PosOrder();
        update.setState(4L);
        update.setPayStatus(2L);
        update.setAfterSaleStatus(3L);
        return update;
    }

    private void validateRefundableOrder(PosOrder order) {
        if (order.getState() == 3L) {
            throw new ServiceException("已完成订单需结算冲正，本期不支持退款");
        }
        if (order.getState() == 4L || order.getPayStatus() != 1L || order.getAfterSaleStatus() != 0L) {
            throw new ServiceException("当前订单状态不允许退款");
        }
    }

    private void rejectNormalAdjustmentWhenBlocked(PosOrder order) {
        if (order.getState() == 3L || order.getState() == 4L || order.getPayStatus() == 2L) {
            throw new ServiceException("终态订单不能重新调整状态");
        }
        if (order.getAfterSaleStatus() != 0L) {
            throw new ServiceException("订单存在售后流程，请先处理售后");
        }
    }

    private void validateOrderTransition(PosOrder order, Long targetState, Long effectiveDelivery) {
        Long current = order.getState();
        boolean valid = current == 0L && targetState == 1L
                || current == 1L && targetState == 2L
                || current == 2L && targetState == 3L
                || (current == 0L || current == 1L) && targetState == 4L;
        if (!valid) {
            throw new ServiceException("订单状态只能按规则向前推进");
        }
        if (current == 0L && targetState == 1L
                && isCardWalletPayType(order.getPayType()) && order.getPayStatus() != 1L) {
            throw new ServiceException("OMG 订单支付成功后才能接单");
        }
        if (targetState == 4L && order.getPayStatus() != 0L) {
            throw new ServiceException("已支付订单请使用退款操作");
        }
        if (targetState == 3L) {
            if (order.getPayStatus() != 1L) {
                throw new ServiceException("订单支付完成后才能完成");
            }
            if (order.getType() == 0L && !Long.valueOf(3L).equals(effectiveDelivery)) {
                throw new ServiceException("外送订单送达后才能完成");
            }
        }
    }

    private void validateDeliveryTransition(PosOrder order, Long targetDelivery) {
        if (order.getType() != 0L) {
            throw new ServiceException("自取或堂食订单不能修改配送状态");
        }
        if (order.getState() != 2L) {
            throw new ServiceException("订单出餐后才能推进配送状态");
        }
        Long current = order.getDeliveryStatus();
        boolean valid = current == null && targetDelivery == 0L
                || current != null && targetDelivery == current + 1L;
        if (!valid) {
            throw new ServiceException("配送状态只能逐步向前推进");
        }
        if (targetDelivery >= 1L && order.getQsId() == null) {
            throw new ServiceException("订单尚未指派骑手");
        }
        if (targetDelivery == 3L && order.getPayStatus() != 1L) {
            throw new ServiceException("订单支付完成后才能确认送达");
        }
    }

    private void validateResultInvariants(PosOrder order, Long state, Long delivery,
                                          Long payStatus, Long afterSaleStatus) {
        if (order.getType() != 0L && delivery != null) {
            throw new ServiceException("非外送订单不能存在配送状态");
        }
        if (delivery != null && delivery == 3L && state != 3L) {
            throw new ServiceException("送达订单必须同步完成");
        }
        if (state == 3L && (payStatus != 1L || afterSaleStatus != 0L)) {
            throw new ServiceException("订单状态组合不合法");
        }
    }

    private void validateSnapshot(PosOrder order, AdminOrderActionRequest request) {
        if (!Objects.equals(order.getState(), request.getExpectedState())
                || !Objects.equals(order.getDeliveryStatus(), request.getExpectedDeliveryStatus())
                || !Objects.equals(order.getPayStatus(), request.getExpectedPayStatus())
                || !Objects.equals(order.getAfterSaleStatus(), request.getExpectedAfterSaleStatus())) {
            throw conflict();
        }
    }

    private void applyCas(PosOrder order, PosOrder update) {
        LambdaUpdateWrapper<PosOrder> wrapper = new LambdaUpdateWrapper<PosOrder>()
                .eq(PosOrder::getId, order.getId())
                .eq(PosOrder::getState, order.getState())
                .eq(PosOrder::getPayStatus, order.getPayStatus())
                .eq(PosOrder::getAfterSaleStatus, order.getAfterSaleStatus());
        if (Long.valueOf(3L).equals(update.getState())) {
            wrapper.notExists("SELECT 1 FROM pos_order_line_payment lp "
                    + "JOIN pos_order_line_refund lr ON lr.payment_id = lp.id "
                    + "WHERE lp.dd_id = pos_order.dd_id "
                    + "AND lr.status <> 'FAILED'");
        }
        if (update.getDeliveryStatus() != null) {
            if (order.getDeliveryStatus() == null) {
                wrapper.isNull(PosOrder::getDeliveryStatus);
            } else {
                wrapper.eq(PosOrder::getDeliveryStatus, order.getDeliveryStatus());
            }
        }
        if (!posOrderService.update(update, wrapper)) {
            throw conflict();
        }
    }

    private ServiceException conflict() {
        return new ServiceException("订单状态已变化，请刷新后重试");
    }

    private String lineMessage(String key, String fallback) {
        try {
            return MessageUtils.message(key);
        } catch (RuntimeException ignored) {
            return fallback;
        }
    }

    private void completeSideEffects(PosOrder order) {
        billingService.setSanghuBilling(order);
        if (order.getType() == 0L && order.getQsId() != null) {
            billingService.setQishouBilling(order);
        }
    }

    private void refundPoints(PosOrder order) {
        if (order.getPoints() == null || order.getPoints() <= 0) {
            return;
        }
        PointsTransaction existing = pointsTransactionService.getOne(
                new LambdaQueryWrapper<PointsTransaction>()
                        .eq(PointsTransaction::getDdId, String.valueOf(order.getDdId()))
                        .eq(PointsTransaction::getType, "2"));
        if (existing != null) {
            return;
        }
        UserWallet wallet = userWalletService.getOne(new LambdaQueryWrapper<UserWallet>()
                .eq(UserWallet::getUserId, order.getUserId())
                .isNull(UserWallet::getStoreId));
        if (wallet == null || wallet.getPointsWallet() == null) {
            throw new ServiceException("用户积分钱包不存在");
        }
        int oldVersion = wallet.getVersion();
        wallet.setPointsWallet(wallet.getPointsWallet() + order.getPoints());
        wallet.setVersion(oldVersion + 1);
        boolean updated = userWalletService.update(wallet, new LambdaQueryWrapper<UserWallet>()
                .eq(UserWallet::getId, wallet.getId())
                .eq(UserWallet::getVersion, oldVersion));
        if (!updated) {
            throw new ServiceException("积分返还冲突，请稍后重试");
        }
        PointsTransaction transaction = new PointsTransaction();
        transaction.setUserId(order.getUserId());
        transaction.setPointsChange("+" + order.getPoints());
        transaction.setCurrentPoints(String.valueOf(wallet.getPointsWallet()));
        transaction.setDdId(String.valueOf(order.getDdId()));
        transaction.setType("2");
        transaction.setCreateTime(new Date());
        pointsTransactionService.save(transaction);
    }

    private void logStatusChange(PosOrder after, AdminOrderActionRequest request,
                                 Long operatorId, String operatorName,
                                 Long beforeState, Long beforeDelivery, Long beforePay, Long beforeAfterSale,
                                 String action) {
        String content = action + "：state " + value(beforeState) + "→" + value(after.getState())
                + "，delivery " + value(beforeDelivery) + "→" + value(after.getDeliveryStatus())
                + "，pay " + value(beforePay) + "→" + value(after.getPayStatus())
                + "，afterSale " + value(beforeAfterSale) + "→" + value(after.getAfterSaleStatus())
                + "；原因：" + request.normalizedReason();
        orderLogHelper.logSync(String.valueOf(after.getDdId()), 1, operatorId,
                safeName(operatorName), content);
    }

    private AdminOrderStatusContext buildContext(PosOrder order) {
        AdminOrderStatusContext context = new AdminOrderStatusContext();
        context.setId(order.getId());
        context.setDdId(String.valueOf(order.getDdId()));
        context.setType(order.getType());
        context.setPayType(order.getPayType());
        context.setState(order.getState());
        context.setDeliveryStatus(order.getDeliveryStatus());
        context.setPayStatus(order.getPayStatus());
        context.setAfterSaleStatus(order.getAfterSaleStatus());
        context.setSdTime(order.getSdTime());
        context.setRiderAssigned(order.getQsId() != null);
        context.setAllowedOrderStates(allowedOrderStates(order));
        context.setAllowedDeliveryStatuses(allowedDeliveryStates(order));

        boolean active = order.getState() != 3L && order.getState() != 4L
                && order.getPayStatus() != 2L && order.getAfterSaleStatus() == 0L;
        context.setCanConfirmOfflinePayment(active && PAY_TYPE_OFFLINE.equals(order.getPayType())
                && order.getPayStatus() == 0L);
        context.setCanConfirmOfflineRefund(active && PAY_TYPE_OFFLINE.equals(order.getPayType())
                && order.getPayStatus() == 1L);

        if (linePaymentService != null) {
            List<PosOrderLinePayment> attempts = linePaymentService.getByDdId(String.valueOf(order.getDdId()));
            PosOrderLinePayment line = selectLinePaymentForAdmin(attempts);
            if (line != null) {
                context.setLinePaymentId(line.getId());
                context.setLinePaymentStatus(line.getStatus());
                context.setLineTransactionId(line.getTransactionId());
                PosOrderLineRefund refund = lineRefundService == null
                        ? null : lineRefundService.getByPaymentId(line.getId());
                context.setLineRefundStatus(refund == null ? null : refund.getStatus());
                context.setCanReconcileLine(!"PAID".equals(line.getStatus())
                        && !"CANCELLED_OR_EXPIRED".equals(line.getStatus())
                        && !"FAILED".equals(line.getStatus()));
                context.setCanRefundLine(!Long.valueOf(3L).equals(order.getState())
                        && order.getPayStatus() == 1L
                        && order.getAfterSaleStatus() == 0L && "PAID".equals(line.getStatus())
                        && (refund == null || !"REFUNDED".equals(refund.getStatus())));
            }
        }
        return context;
    }

    private PosOrderLinePayment selectLinePaymentForAdmin(List<PosOrderLinePayment> attempts) {
        List<PosOrderLinePayment> unrefundedPaid = attempts.stream()
                .filter(payment -> "PAID".equals(payment.getStatus()))
                .filter(payment -> {
                    PosOrderLineRefund refund = lineRefundService == null
                            ? null : lineRefundService.getByPaymentId(payment.getId());
                    return refund == null || !"REFUNDED".equals(refund.getStatus());
                }).toList();
        if (unrefundedPaid.size() == 1) {
            return unrefundedPaid.get(0);
        }
        if (unrefundedPaid.size() > 1) {
            return null;
        }
        return attempts.stream().filter(payment -> payment.getActiveDdId() != null)
                .findFirst().orElse(attempts.isEmpty() ? null : attempts.get(0));
    }

    private List<Long> allowedOrderStates(PosOrder order) {
        List<Long> allowed = new ArrayList<>();
        allowed.add(order.getState());
        if (order.getState() == 3L || order.getState() == 4L || order.getPayStatus() == 2L
                || order.getAfterSaleStatus() != 0L) {
            return allowed;
        }
        if (order.getState() == 0L) {
            if (!requiresOnlinePaymentBeforeProgress(order)) {
                allowed.add(1L);
            }
            if (order.getPayStatus() == 0L) {
                allowed.add(4L);
            }
        } else if (order.getState() == 1L) {
            if (!requiresOnlinePaymentBeforeProgress(order)) {
                allowed.add(2L);
            }
            if (order.getPayStatus() == 0L) {
                allowed.add(4L);
            }
        } else if (order.getState() == 2L && order.getPayStatus() == 1L
                && (order.getType() != 0L || Long.valueOf(3L).equals(order.getDeliveryStatus()))) {
            allowed.add(3L);
        }
        return allowed;
    }

    private boolean requiresOnlinePaymentBeforeProgress(PosOrder order) {
        if (order.getPayStatus() == 1L) {
            return false;
        }
        if (isCardWalletPayType(order.getPayType())) {
            return true;
        }
        return "3".equals(order.getPayType()) && linePaymentService != null
                && !linePaymentService.getByDdId(String.valueOf(order.getDdId())).isEmpty();
    }

    private List<Long> allowedDeliveryStates(PosOrder order) {
        List<Long> allowed = new ArrayList<>();
        if (order.getType() != 0L) {
            return allowed;
        }
        if (order.getDeliveryStatus() != null) {
            allowed.add(order.getDeliveryStatus());
        }
        if (order.getState() != 2L || order.getPayStatus() == 2L || order.getAfterSaleStatus() != 0L) {
            return allowed;
        }
        Long current = order.getDeliveryStatus();
        if (current == null) {
            allowed.add(0L);
        } else if (current < 2L && order.getQsId() != null) {
            allowed.add(current + 1L);
        } else if (current == 2L && order.getQsId() != null && order.getPayStatus() == 1L) {
            allowed.add(3L);
        }
        return allowed;
    }

    private PosOrder requireOrder(Long id) {
        PosOrder order = id == null ? null : posOrderService.getById(id);
        if (order == null) {
            throw new ServiceException("订单不存在");
        }
        if (order.getState() == null || order.getPayStatus() == null || order.getAfterSaleStatus() == null
                || order.getType() == null) {
            throw new ServiceException("订单状态数据不完整");
        }
        return order;
    }

    private void requireReason(AdminOrderActionRequest request) {
        if (request == null || request.normalizedReason().isEmpty()
                || request.normalizedReason().length() > 200) {
            throw new ServiceException("请填写1至200字的调整原因");
        }
    }

    private String value(Object value) {
        return value == null ? "NULL" : String.valueOf(value);
    }

    private String safeName(String name) {
        return name == null ? "" : name;
    }
}
