package com.ruoyi.bst.order.service.impl;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import com.github.pagehelper.PageHelper;
import com.ruoyi.bst.area.domain.AreaVO;
import com.ruoyi.bst.area.service.AreaService;
import com.ruoyi.bst.areaJoin.domain.enums.AreaJoinPermission;
import com.ruoyi.bst.areaSub.domain.AreaSubVO;
import com.ruoyi.bst.areaSub.service.AreaSubService;
import com.ruoyi.bst.bonus.domain.Bonus;
import com.ruoyi.bst.bonus.domain.enums.BonusBstType;
import com.ruoyi.bst.bonus.service.BonusConverter;
import com.ruoyi.bst.bonus.service.BonusService;
import com.ruoyi.bst.channel.service.ChannelService;
import com.ruoyi.bst.device.domain.Device;
import com.ruoyi.bst.device.domain.DeviceVO;
import com.ruoyi.bst.device.domain.enums.DeviceLocationType;
import com.ruoyi.bst.device.domain.enums.DeviceUnLockType;
import com.ruoyi.bst.device.domain.vo.DeviceIotVO;
import com.ruoyi.bst.device.service.DeviceAssembler;
import com.ruoyi.bst.device.service.DeviceIotService;
import com.ruoyi.bst.device.service.DeviceService;
import com.ruoyi.bst.device.utils.DeviceUtil;
import com.ruoyi.bst.fault.domain.Fault;
import com.ruoyi.bst.fault.service.FaultConverter;
import com.ruoyi.bst.fault.service.FaultService;
import com.ruoyi.bst.feeLog.domain.FeeLog;
import com.ruoyi.bst.feeLog.service.FeeLogConverter;
import com.ruoyi.bst.feeLog.service.FeeLogService;
import com.ruoyi.bst.locationLog.domain.LocationLog;
import com.ruoyi.bst.locationLog.service.LocationLogConverter;
import com.ruoyi.bst.locationLog.utils.LocationLogUtil;
import com.ruoyi.bst.order.constants.OrderConstants;
import com.ruoyi.bst.order.domain.Order;
import com.ruoyi.bst.order.domain.OrderQuery;
import com.ruoyi.bst.order.domain.OrderVO;
import com.ruoyi.bst.order.domain.bo.OrderChangeBO;
import com.ruoyi.bst.order.domain.bo.OrderCreateBO;
import com.ruoyi.bst.order.domain.bo.OrderDeductBO;
import com.ruoyi.bst.order.domain.bo.OrderEndBO;
import com.ruoyi.bst.order.domain.bo.OrderPayRideFeeBO;
import com.ruoyi.bst.order.domain.dto.OrderCalcFeeDTO;
import com.ruoyi.bst.order.domain.dto.OrderCalcRideFeeDTO;
import com.ruoyi.bst.order.domain.dto.OrderChangeDeviceDTO;
import com.ruoyi.bst.order.domain.dto.OrderCloseDeviceDTO;
import com.ruoyi.bst.order.domain.dto.OrderCreateDTO;
import com.ruoyi.bst.order.domain.dto.OrderDeductDTO;
import com.ruoyi.bst.order.domain.dto.OrderEndDTO;
import com.ruoyi.bst.order.domain.dto.OrderOpenDeviceDTO;
import com.ruoyi.bst.order.domain.dto.OrderPayRideFeeDTO;
import com.ruoyi.bst.order.domain.dto.OrderRefundDTO;
import com.ruoyi.bst.order.domain.dto.OrderRefundDetailDTO;
import com.ruoyi.bst.order.domain.dto.OrderRidePaySuccessDTO;
import com.ruoyi.bst.order.domain.dto.OrderSeatDTO;
import com.ruoyi.bst.order.domain.dto.OrderUpdatePriceDTO;
import com.ruoyi.bst.order.domain.dto.OrderVerifyDTO;
import com.ruoyi.bst.order.domain.enums.OrderPayType;
import com.ruoyi.bst.order.domain.enums.OrderReturnType;
import com.ruoyi.bst.order.domain.enums.OrderStatus;
import com.ruoyi.bst.order.domain.vo.OrderCalcPreRideFeeVO;
import com.ruoyi.bst.order.domain.vo.OrderCalcRideFeeVO;
import com.ruoyi.bst.order.domain.vo.OrderEndVO;
import com.ruoyi.bst.order.domain.vo.OrderFeeVO;
import com.ruoyi.bst.order.domain.vo.OrderInParkingVO;
import com.ruoyi.bst.order.mapper.OrderMapper;
import com.ruoyi.bst.order.service.OrderAssembler;
import com.ruoyi.bst.order.service.OrderConverter;
import com.ruoyi.bst.order.service.OrderService;
import com.ruoyi.bst.order.service.OrderValidator;
import com.ruoyi.bst.order.utils.OrderUtil;
import com.ruoyi.bst.orderDevice.domain.OrderDevice;
import com.ruoyi.bst.orderDevice.domain.OrderDeviceVO;
import com.ruoyi.bst.orderDevice.domain.enums.OrderDeviceReason;
import com.ruoyi.bst.orderDevice.domain.enums.OrderDeviceStatus;
import com.ruoyi.bst.orderDevice.service.OrderDeviceService;
import com.ruoyi.bst.pay.domain.Pay;
import com.ruoyi.bst.pay.domain.dto.PayRefundDTO;
import com.ruoyi.bst.pay.domain.enums.PayBstType;
import com.ruoyi.bst.pay.domain.vo.DoPayVO;
import com.ruoyi.bst.pay.service.PayConverter;
import com.ruoyi.bst.pay.service.PayService;
import com.ruoyi.bst.refund.domain.enums.RefundType;
import com.ruoyi.bst.sms.service.SmsService;
import com.ruoyi.bst.vipUser.domain.VipUserVO;
import com.ruoyi.bst.vipUser.service.VipUserService;
import com.ruoyi.bst.vipUser.utils.VipUserUtil;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.core.redis.RedisLock;
import com.ruoyi.common.core.redis.enums.RedisLockKey;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.LogParamHolder;
import com.ruoyi.common.utils.MathUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.SnowFlakeUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.system.user.service.UserService;

import lombok.extern.slf4j.Slf4j;

/**
 * 订单Service业务层处理
 *
 * @author ruoyi
 * @date 2025-03-24
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderConverter orderConverter;

    @Autowired
    private OrderValidator orderValidator;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private RedisLock redisLock;

    @Autowired
    private ScheduledExecutorService scheduledExecutorService;

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private BonusConverter bonusConverter;

    @Autowired
    private BonusService bonusService;

    @Autowired
    private PayService payService;

    @Autowired
    private PayConverter payConverter;

    @Autowired
    private AreaService areaService;

    @Autowired
    private DeviceIotService deviceIotService;

    @Autowired
    private AreaSubService areaSubService;

    @Autowired
    private OrderDeviceService orderDeviceService;

    @Autowired
    private FaultConverter faultConverter;

    @Autowired
    private FaultService faultService;

    @Autowired
    private LocationLogConverter locationLogConverter;

    @Autowired
    private UserService userService;

    @Autowired
    private SmsService smsService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private DeviceAssembler deviceAssembler;

    @Autowired
    private FeeLogConverter feeLogConverter;

    @Autowired
    private FeeLogService feeLogService;

    @Autowired
    private VipUserService vipUserService;

    @Autowired
    private ChannelService channelService;

    @Autowired
    private OrderAssembler orderAssembler;

    /**
     * 查询订单
     *
     * @param id 订单主键
     * @return 订单
     */
    @Override
    public OrderVO selectOrderById(Long id, boolean scope) {
        if (id == null) {
            return null;
        }
        OrderQuery query = new OrderQuery();
        query.setId(id);
        query.setScope(scope);
        query.addAreaPermission(AreaJoinPermission.ORDER_VIEW.getCode());
        return this.selectOne(query);
    }

    @Override
    public OrderVO selectOne(OrderQuery query) {
        PageHelper.startPage(1, 1);
        List<OrderVO> list = this.selectOrderList(query);
        return CollectionUtils.firstElement(list);
    }

    /**
     * 查询订单列表
     *
     * @param order 订单
     * @return 订单
     */
    @Override
    public List<OrderVO> selectOrderList(OrderQuery order) {
        List<OrderVO> list = orderMapper.selectOrderList(order);
        orderAssembler.assembleIot(list);
        return list;
    }

    /**
     * 新增订单
     *
     * @param order 订单
     * @return 结果
     */
    @Override
    public int insertOrder(Order order) {
        order.setCreateTime(DateUtils.getNowDate());
        order.setNo(String.valueOf(SnowFlakeUtil.newId()));
        return orderMapper.insertOrder(order);
    }

    /**
     * 修改订单
     *
     * @param order 订单
     * @return 结果
     */
    @Override
    public int updateOrder(Order order) {
        return orderMapper.updateOrder(order);
    }

    /**
     * 批量删除订单
     *
     * @param ids 需要删除的订单主键
     * @return 结果
     */
    @Override
    public int deleteOrderByIds(Long[] ids) {
        return orderMapper.deleteOrderByIds(ids);
    }

    /**
     * 删除订单信息
     *
     * @param id 订单主键
     * @return 结果
     */
    @Override
    public int deleteOrderById(Long id) {
        return orderMapper.deleteOrderById(id);
    }

    @Override
    public DoPayVO createOrder(OrderCreateDTO dto) {
        ServiceUtil.assertion(dto == null || dto.getDeviceId() == null, "参数错误");

        // 加锁，防止设备重复下单
        Long lockKey = dto.getDeviceId();
        boolean lock = redisLock.lock(RedisLockKey.ORDER_CREATE, lockKey);
        ServiceUtil.assertion(!lock, "当前车辆使用的人太多了，请稍后再试");
        try {
            // 转为BO对象
            OrderCreateBO bo = orderConverter.toCreateBO(dto);
            // 校验参数
            orderValidator.validate(bo);

            // 若设备当前订单未支付，则将其取消
            DeviceVO device = bo.getDevice();
            if (device.getOrderId() != null && OrderStatus.WAIT_PAY.getCode().equals(device.getOrderStatus())) {
                int cancel = this.cancelOrder(device.getOrderId(), "取消上一个未支付订单");
                ServiceUtil.assertion(cancel != 1, "取消上一个未支付订单失败");
            }

            return transactionTemplate.execute(status -> {

                // 创建订单
                Order order = bo.getOrder();
                int rows = this.insertOrder(order);
                ServiceUtil.assertion(rows != 1, "创建订单失败");

                // 查询订单
                OrderVO vo = this.selectOrderByNo(order.getNo());
                ServiceUtil.assertion(vo == null, "查询创建的订单失败");

                // 创建订单设备
                OrderDevice orderDevice = bo.getOrderDevice();
                orderDevice.setOrderId(vo.getId());
                int orderDeviceRows = orderDeviceService.insertOrderDevice(orderDevice);
                ServiceUtil.assertion(orderDeviceRows != 1, "创建订单设备失败");

                // 设置用户运营区ID
                int updateAreaId = userService.updateAreaId(vo.getUserId(), vo.getAreaId());
                ServiceUtil.assertion(updateAreaId != 1, "更新用户运营区ID失败");

                // 支付
                DoPayVO doPayVO = this.pay(bo);
                ServiceUtil.assertion(doPayVO == null, "支付失败");
                bo.setDoPayVO(doPayVO);

                return doPayVO;
            });
        } finally {
            redisLock.unlock(RedisLockKey.ORDER_CREATE, lockKey);
        }
    }

    @Override
    public OrderVO selectOrderByNo(String no, boolean scope) {
        if (StringUtils.isBlank(no)) {
            return null;
        }
        OrderQuery query = new OrderQuery();
        query.setEqNo(no);
        query.setScope(scope);
        return this.selectOne(query);
    }

    // 加入延时队列，超时取消
    @Override
    public void cancelWhenExpired(Order order) {
        if (order == null || order.getPayExpireTime() == null) {
            return;
        }

        Duration duration = Duration.between(LocalDateTime.now(), order.getPayExpireTime());
        long delay = duration.getSeconds();
        if (delay <= 0) {
            delay = 1;
        }

        scheduledExecutorService.schedule(() -> {
            // 尝试取消订单
            this.cancelOrder(order.getId(), "订单超时取消");
        }, delay, TimeUnit.SECONDS);
    }

    // 取消订单
    @Override
    public int cancelOrder(Long id, String remark) {
        if (id == null) {
            return 0;
        }
        // 查询订单
        OrderVO order = this.selectOrderById(id);
        ServiceUtil.assertion(order == null, "ID为%s的订单不存在", id);
        ServiceUtil.assertion(!OrderStatus.canCancelPay().contains(order.getStatus()), "ID为%s的订单当前状态不允许取消", id);

        // 刷新支付结果
        if (order.getPayNo() != null) {
            payService.refreshPayResult(order.getPayNo());
        }

        // 查询最新订单状态
        order = this.selectOrderById(id);
        ServiceUtil.assertion(order == null, "ID为%s的订单不存在", id);
        ServiceUtil.assertion(!OrderStatus.canCancelPay().contains(order.getStatus()), "ID为%s的订单当前状态不允许取消", id);

        Long deviceId = order.getDeviceId(); // 设备ID
        Long orderDeviceId = order.getOrderDeviceId(); // 订单设备ID

        // 取消订单
        Integer result = transactionTemplate.execute(status -> {
            // 更新订单状态
            Order data = new Order();
            data.setStatus(OrderStatus.CANCELED.getCode());
            data.setCancelRemark(remark);
            OrderQuery query = new OrderQuery();
            query.setId(id);
            query.setStatusList(OrderStatus.canCancelPay());
            int rows = orderMapper.updateByQuery(data, query);
            ServiceUtil.assertion(rows != 1, "ID为%s的订单取消失败，状态已发生变化", id);

            // 清除设备上的订单ID
            int clear = deviceService.clearCurrentOrderDevice(deviceId, orderDeviceId);
            ServiceUtil.assertion(clear != 1, "清除设备订单失败");

            // 取消支付单
            boolean cancelPay = payService.closeByBstId(PayBstType.ORDER.getType(), id);
            ServiceUtil.assertion(!cancelPay, "ID为%s的订单取消支付单失败", id);

            return rows;
        });

        return result == null ? 0 : result;
    }

    private DoPayVO pay(OrderCreateBO bo) {

        // 转为分成列表
        List<Bonus> bonusList = bonusConverter.toBonusList(bo);
        ServiceUtil.assertion(CollectionUtils.isEmpty(bonusList), "转为分成列表失败");

        // 转为支付PO
        Pay pay = payConverter.toPayPO(bo);
        ServiceUtil.assertion(pay == null, "转为支付单失败");

        return transactionTemplate.execute(status -> {
            // 保存分成列表
            int bonusRows = bonusService.batchInsert(bonusList);
            ServiceUtil.assertion(bonusRows != bonusList.size(), "保存分成列表失败");

            // 创建并调起支付
            return payService.createPayBill(pay);
        });
    }

    @Override
    public OrderEndVO endOrder(OrderEndDTO dto) {
        ServiceUtil.assertion(dto == null, "参数错误，dto不允许为空");
        OrderEndVO vo = new OrderEndVO();

        // 转为BO对象
        OrderEndBO bo = orderConverter.toEndBO(dto);

        // 获取设备信息
        DeviceVO device = bo.getDevice();
        // 设置日志参数
        this.setLogParam(device);
        // 异步使用手机定位更新设备定位
        this.handleDeviceLocationAsync(device, dto.getLon(), dto.getLat());

        // 校验参数
        String returnType = dto.getReturnType();
        boolean isAdmin = OrderReturnType.isAdmin(returnType);
        orderValidator.validate(bo, isAdmin);

        // 提取数据
        OrderVO order = bo.getOrder();
        OrderInParkingVO inParkingVO = bo.getInParkingVO();
        AreaVO area = bo.getArea();
        OrderDeviceVO orderDevice = bo.getOrderDevice();

        // 设置订单数据
        order.setEndTime(LocalDateTime.now()); // 结束时间
        order.setDuration(Duration.between(order.getStartTime(), order.getEndTime()).getSeconds());
        order.setDistance(LocationLogUtil.calcDistance(bo.getPositionList()));
        order.setEndReason(dto.getEndReason());
        order.setReturnType(returnType);
        order.setStatus(OrderStatus.RIDE_WAIT_PAY.getCode());

        // 订单费用
        boolean needDispatchFee = dto.getNeedDispatchFee() != null && dto.getNeedDispatchFee();
        this.setOrderFee(order, area, inParkingVO, needDispatchFee);

        Integer result = transactionTemplate.execute(status -> {
            // 更新订单数据
            Order data = orderConverter.toPOByEnd(order);
            OrderQuery query = new OrderQuery();
            query.setId(order.getId());
            query.setStatusList(OrderStatus.canEnd());
            int rows = orderMapper.updateByQuery(data, query);
            ServiceUtil.assertion(rows != 1, "ID为%s的订单更新失败", order.getId());
            vo.setDb(rows);

            // 结束订单设备
            int finish = orderDeviceService.finish(orderDevice, dto.getPicture(), inParkingVO);
            ServiceUtil.assertion(finish != 1, "结束ID为%s的订单设备失败", orderDevice.getId());

            // 设备上锁（必须放最后，因为会操作设备）
            DeviceIotVO lock = deviceIotService.lock(orderDevice.getDeviceId(), isAdmin,
                    "订单结束上锁：" + orderDevice.getOrderNo(), dto.getRequiredIot());
            ServiceUtil.assertion(lock.getDb() != 1, "ID为%s的设备上锁失败", orderDevice.getDeviceId());
            vo.setIot(lock.getIot());

            if (OrderUtil.isCredit(order)) {
                this.creditPay(order.getId());
            }

            return rows;
        });

        return vo;
    }

    /**
     * 挂账支付
     * @param orderId 订单ID
     */
    private void creditPay(Long orderId) {
        OrderVO order = this.selectOrderById(orderId);

        ServiceUtil.assertion(order == null, "订单不存在");
        ServiceUtil.assertion(!OrderUtil.isCredit(order), "当前订单不是挂账订单");

        // 获取费用
        OrderCalcRideFeeVO fee = this.calcRideFee(order, null);

        // 挂账支付
        OrderPayRideFeeDTO dto = new OrderPayRideFeeDTO();
        dto.setOrderId(orderId);
        dto.setChannelId(order.getPayChannelId());
        dto.setAppId(order.getPayAppId());
        dto.setUserId(order.getUserId());
        dto.setCreditUserId(order.getCreditUserId());
        dto.setFee(fee);
        this.payRideFee(dto);
    }

    /**
     * 设置日志参数
     * @param device 设备信息
     */
    private void setLogParam(DeviceVO device) {
        if (device != null) {
            LogParamHolder.set(LogParamHolder.DEVICE_ID, device.getId());
            if (DeviceLocationType.DEVICE.getCode().equals(device.getLocationType())) {
                LogParamHolder.set(LogParamHolder.DEVICE_LON, device.getLongitude());
                LogParamHolder.set(LogParamHolder.DEVICE_LAT, device.getLatitude());
            }
        }
    }

    // 异步使用手机定位更新设备定位
    private void handleDeviceLocationAsync(DeviceVO device, BigDecimal lon, BigDecimal lat) {
        if (device != null && device.getId() != null && StringUtils.isNotBlank(device.getMac()) && DeviceUtil.validLocation(lon, lat)) {
            scheduledExecutorService.execute(() -> {

                // 若卫星信号弱或者离线，则更新设备定位
                if (DeviceUtil.isLowSatelliteSignal(device) || DeviceUtil.isOffline(device)) {
                    Device data = new Device();
                    data.setMac(device.getMac());
                    data.setLongitude(lon);
                    data.setLatitude(lat);
                    data.setLocationType(DeviceLocationType.PHONE.getCode());
                    data.setLastLocationTime(LocalDateTime.now());
                    int rows = deviceIotService.updateIot(data);
                    if (rows != 1) {
                        log.error("通过手机定位修改设备定位失败deviceMac={}", device.getMac());
                    }
                }

                // 直接保存手机定位日志
                DeviceVO vo = new DeviceVO();
                BeanUtils.copyProperties(device, vo);
                vo.setLongitude(lon);
                vo.setLatitude(lat);
                vo.setLocationType(DeviceLocationType.PHONE.getCode());
                vo.setLastLocationTime(LocalDateTime.now());
                LocationLog locationLog = locationLogConverter.toPo(vo);
                if (locationLog == null) {
                    log.error("通过手机定位转换定位日志失败: {}", device.getMac());
                    return;
                }

                // 暂存到Redis缓存
                redisCache.rightPush(CacheConstants.LOCATION_LOG_QUEUE, locationLog);

            });
        }
    }

    // 处理订单完成
    private void handleFinished(Long orderId) {
        // 查询订单数据
        OrderVO order = selectOrderById(orderId);
        ServiceUtil.assertion(order == null, "ID为%s的订单完成失败", orderId);

        // 预分成
        boolean bonus = this.prepayBonus(order);
        ServiceUtil.assertion(!bonus, "ID为%s的订单预分成失败", orderId);

        // 剩余金额退款
        scheduledExecutorService.execute(() -> {
            int refund = this.refundRemainDeposit(order);
            ServiceUtil.assertion(refund != 1, "ID为%s的订单退还剩余金额失败", orderId);
        });
    }

    // 设置订单费用
    private void setOrderFee(OrderVO order, AreaVO area, OrderInParkingVO inParkingVO, boolean needDispatchFee) {
        OrderFeeVO orderFee = OrderUtil.calcOrderFee(order, area, inParkingVO, order.getEndTime(), needDispatchFee);
        order.setManageFee(orderFee.getManageFee());
        order.setDispatchFee(orderFee.getDispatchFee());
        order.setRidingFee(orderFee.getRidingFee());
        order.setTotalFee(orderFee.getTotalFee());
    }

    // 设置订单实收金额
    private void setActualAmount(Order data, OrderVO old, BigDecimal payAmount) {
        // 实收金额
        BigDecimal remain = payAmount;
        data.setActualAmount(payAmount);
        // 骑行费实收
        BigDecimal ridingFee = MathUtils.subtractDecimal(old.getRidingFee(), old.getRidingDiscount());
        data.setActualRidingFee(MathUtils.min(remain, ridingFee));
        remain = MathUtils.subtractDecimal(remain, data.getActualRidingFee());
        // 调度费实收
        data.setActualDispatchFee(MathUtils.min(remain, old.getDispatchFee()));
        remain = MathUtils.subtractDecimal(remain, data.getActualDispatchFee());
        // 管理费实收
        data.setActualManageFee(MathUtils.min(remain, old.getManageFee()));
    }

    @Override
    public int refundRemainDeposit(OrderVO order) {
        if (order == null) {
            return 0;
        }
        ServiceUtil.assertion(order.getAutoRefunded(), "ID为%s的订单已自动退款过，不允许重复退款", order.getId());

        transactionTemplate.execute(status -> {
            // 标记订单已自动退款
            Order data = new Order();
            data.setAutoRefunded(true);
            OrderQuery query = new OrderQuery();
            query.setId(order.getId());
            query.setAutoRefunded(false);
            query.setStatus(OrderStatus.FINISHED.getCode());
            int rows = orderMapper.updateByQuery(data, query);
            ServiceUtil.assertion(rows != 1, "ID为%s的订单状态已发生变化，不允许自动退款", order.getId());

            // 剩余押金退款
            BigDecimal refund = OrderUtil.calcCanAutoRefundAmount(order);
            if (refund != null && refund.compareTo(BigDecimal.ZERO) > 0) {
                // 支付退款
                PayRefundDTO dto = new PayRefundDTO();
                dto.setId(order.getPayId());
                dto.setRefundAmount(refund);
                dto.setRefundReason(this.getRefundReason(null, RefundType.AUTO.getCode(), "系统", order.getNo(), refund));
                dto.setUserId(null);
                dto.setUserName("系统");
                dto.setType(RefundType.AUTO.getCode());
                return payService.refund(dto);
            }

            return rows;
        });

        return 1;
    }

    // 获取退款原因
    private String getRefundReason(String reason, String type, String userName, String orderNo, BigDecimal amount) {
        String refundReason = null;
        if (RefundType.ADMIN.getCode().equals(type)) {
            refundReason = String.format("【管理员退款】%s订单%s退款 %s 元", userName, orderNo, amount);
        } else {
            refundReason = String.format("【自动退款】%s订单%s退款 %s 元", userName, orderNo, amount);
        }
        if (StringUtils.isNotBlank(reason)) {
            refundReason += "：" + reason;
        }
        return refundReason;
    }

    @Override
    public OrderFeeVO calcFee(OrderCalcFeeDTO dto) {
        // 查询订单
        OrderVO order = this.selectOrderById(dto.getOrderId());
        if (order == null) {
            return null;
        }

        // 查询当前设备
        OrderDeviceVO orderDevice = orderDeviceService.selectOrderDeviceById(order.getOrderDeviceId());
        if (orderDevice == null) {
            return null;
        }

        // 设备信息
        DeviceVO device = deviceService.selectDeviceById(order.getDeviceId());
        if (device == null) {
            return null;
        }
        // 设置日志参数
        this.setLogParam(device);
        // 处理设备位置
        this.handleDeviceLocationAsync(device, dto.getLon(), dto.getLat());

        // 查询运营区
        AreaVO area = areaService.selectAreaById(order.getAreaId());
        if (area == null) {
            return null;
        }

        // 查询还车点
        List<AreaSubVO> parkingList = areaSubService.selectParkingAreaByAreaId(area.getId());

        // 查询禁停点
        List<AreaSubVO> noParkingList = areaSubService.selectNoParkingAreaByAreaId(area.getId());

        // 获取是否在停车点内
        OrderInParkingVO inParkingVO = OrderUtil.getInParkingVO(area, parkingList, noParkingList, device, dto.getLon(),
                dto.getLat());

        // 还车校验
        if (dto.getCheckLocation() != null && dto.getCheckLocation()) {
            orderValidator.checkInParking(area, inParkingVO);
        }

        // 计算金额
        return OrderUtil.calcOrderFee(order, area, inParkingVO, LocalDateTime.now(), true);
    }

    @Override
    public int refund(OrderRefundDTO dto) {
        OrderVO order = this.selectOrderById(dto.getOrderId());

        ServiceUtil.assertion(order == null, "参数错误，订单不存在");
        ServiceUtil.assertion(!OrderStatus.canRefund().contains(order.getStatus()), "订单[%s]当前状态不允许退款", order.getNo());
        ServiceUtil.assertion(OrderUtil.isCredit(order), "订单[%s]为挂账订单，不允许退款", order.getNo());

        // 退款加锁，短时间内不允许多次退款
        Long lockKey = order.getId();
        boolean lock = redisLock.lock(RedisLockKey.ORDER_ADMIN_REFUND, lockKey);
        ServiceUtil.assertion(!lock, "订单%s退款过于频繁，请稍后重试", order.getNo());

        try {
            // 校验退款金额
            ServiceUtil.assertion(MathUtils.biggerThan(dto.getRidingRefund(), order.getActualReceivedRidingFee()), "骑行费可退款金额不足，当前可退款金额为%s元", order.getActualReceivedRidingFee());
            ServiceUtil.assertion(MathUtils.biggerThan(dto.getDispatchRefund(), order.getActualReceivedDispatchFee()), "调度费可退款金额不足，当前可退款金额为%s元", order.getActualReceivedDispatchFee());
            ServiceUtil.assertion(MathUtils.biggerThan(dto.getManageRefund(), order.getActualReceivedManageFee()), "管理费可退款金额不足，当前可退款金额为%s元", order.getActualReceivedManageFee());
            ServiceUtil.assertion(MathUtils.biggerThan(dto.getDeductionRefund(), order.getActualReceivedDeductionFee()), "车损费可退款金额不足，当前可退款金额为%s元", order.getActualReceivedDeductionFee());

            // 总退款金额不允许为0
            BigDecimal totalRefund = MathUtils.addDecimal(dto.getRidingRefund(), dto.getDispatchRefund(), dto.getManageRefund(), dto.getDeductionRefund());
            ServiceUtil.assertion(totalRefund.compareTo(BigDecimal.ZERO) <= 0, "退款总额不允许小于或等于0");

            int rows = 0;
            try {
                // 执行退款（押金）
                rows = this.doRefund(order, dto, OrderConstants.REFUND_TYPE_DEPOSIT);

                // 执行退款（支付）
                rows += this.doRefund(order, dto, OrderConstants.REFUND_TYPE_RIDE);
            } catch (Exception e) {
                log.error("退款失败: {}, {}", order.getId(), e.getMessage());
            }

            return rows;
        } finally {
            redisLock.unlock(RedisLockKey.ORDER_ADMIN_REFUND, lockKey);
        }
    }

    private int doRefund(OrderVO order, OrderRefundDTO dto, String refundType) {

        // 计算需要退款的金额
        OrderRefundDetailDTO detail = OrderUtil.calcRefundDetail(order, dto, refundType);
        BigDecimal refundAmount = detail.getTotalRefund();

        // 若需要退款的金额为0，则不进行退款
        if (refundAmount == null || BigDecimal.ZERO.compareTo(refundAmount) == 0) {
            return 1;
        }
        // 若退款金额小于0，则不进行退款，并返回0
        if (BigDecimal.ZERO.compareTo(refundAmount) > 0) {
            return 0;
        }

        // 退款原因
        String type = RefundType.ADMIN.getCode();
        String refundReason = this.getRefundReason(dto.getReason(), type, dto.getUserName(), order.getNo(), refundAmount);

        Integer result = transactionTemplate.execute(status -> {
            // 更新订单退款信息
            Order data = new Order();
            data.setAdminRefundAmount(refundAmount);
            data.setRidingRefund(detail.getRidingRefund());
            data.setDispatchRefund(detail.getDispatchRefund());
            data.setManageRefund(detail.getManageRefund());
            data.setDeductionRefund(detail.getDeductionRefund());
            OrderQuery query = new OrderQuery();
            query.setId(order.getId());
            query.setPayType(order.getPayType());
            int rows = orderMapper.updateRefund(data, query);
            ServiceUtil.assertion(rows != 1, "ID为%s订单当前状态已发生变化，请稍后重试", order.getId());

            // 分成退款
            boolean bonusRefund = bonusService.refundByBst(BonusBstType.ORDER, order.getId(), refundAmount, refundReason);
            ServiceUtil.assertion(!bonusRefund, "ID为%s的订单分成退款失败，请联系管理员处理", order.getId());

            // 支付退款
            PayRefundDTO refundDto = new PayRefundDTO();
            if (OrderConstants.REFUND_TYPE_DEPOSIT.equals(refundType)) {
                refundDto.setId(order.getPayId());
            } else if (OrderConstants.REFUND_TYPE_RIDE.equals(refundType)) {
                refundDto.setId(order.getRidePayId());
            }
            refundDto.setRefundAmount(refundAmount);
            refundDto.setRefundReason(refundReason);
            refundDto.setUserId(dto.getUserId());
            refundDto.setUserName(dto.getUserName());
            refundDto.setType(type);
            int refund = payService.refund(refundDto);
            ServiceUtil.assertion(refund != 1, "ID为%s的支付退款失败，请联系管理员处理", refundDto.getId());

            return refund;
        });

        return result == null ? 0 : result;
    }

    @Override
    public DeviceIotVO openDevice(OrderOpenDeviceDTO dto) {
        ServiceUtil.assertion(dto == null, "参数错误，dto不允许为空");

        OrderVO order = this.selectOrderById(dto.getOrderId());
        ServiceUtil.assertion(order == null, "ID为%s的订单不存在", dto.getOrderId());
        ServiceUtil.assertion(!OrderStatus.inUse().contains(order.getStatus()), "ID为%s的订单当前状态并非使用中，无法操作设备",
                order.getId());

        OrderDeviceVO orderDevice = orderDeviceService.selectOrderDeviceById(order.getOrderDeviceId());
        ServiceUtil.assertion(orderDevice == null, "ID为%s的订单设备不存在", order.getId());
        ServiceUtil.assertion(!OrderDeviceStatus.inUse().contains(orderDevice.getStatus()),
                "ID为%s的订单设备当前状态并非使用中，无法操作设备", order.getId());

        // 查询设备
        DeviceVO device = deviceService.selectDeviceById(orderDevice.getDeviceId());
        ServiceUtil.assertion(device == null, "ID为%s的设备不存在", orderDevice.getDeviceId());
        // 设置日志参数
        this.setLogParam(device);
        // 异步使用手机定位更新设备定位
        this.handleDeviceLocationAsync(device, dto.getLon(), dto.getLat());

        // 发送命令开锁
        return deviceIotService.unlock(device, DeviceUnLockType.USER, "订单开锁：" + order.getNo(),
                dto.getRequiredIot(), 1);
    }

    @Override
    public DeviceIotVO closeDevice(OrderCloseDeviceDTO dto) {
        ServiceUtil.assertion(dto == null, "参数错误，dto不允许为空");

        OrderVO order = this.selectOrderById(dto.getOrderId());
        ServiceUtil.assertion(order == null, "ID为%s的订单不存在", dto.getOrderId());

        OrderDeviceVO orderDevice = orderDeviceService.selectOrderDeviceById(order.getOrderDeviceId());
        ServiceUtil.assertion(orderDevice == null, "ID为%s的订单设备不存在", order.getId());
        ServiceUtil.assertion(!OrderDeviceStatus.inUse().contains(orderDevice.getStatus()),
                "ID为%s的订单设备当前状态并非使用中，无法操作设备", order.getId());

        // 查询设备
        DeviceVO device = deviceService.selectDeviceById(orderDevice.getDeviceId());
        ServiceUtil.assertion(device == null, "ID为%s的设备不存在", orderDevice.getDeviceId());
        // 设置日志参数
        this.setLogParam(device);
        // 异步使用手机定位更新设备定位
        this.handleDeviceLocationAsync(device, dto.getLon(), dto.getLat());

        // 判断是否在禁停区内
        List<AreaSubVO> noParkingList = areaSubService.selectNoParkingAreaByAreaId(order.getAreaId());
        if (CollectionUtils.isNotEmptyElement(noParkingList)) {
            OrderInParkingVO inParkingVO = OrderUtil.getInParkingVO(null, null, noParkingList, device, dto.getLon(),
                    dto.getLat());
            ServiceUtil.assertion(inParkingVO == null, "获取设备位置失败");
            ServiceUtil.assertion(inParkingVO.getInNoParking() != null && inParkingVO.getInNoParking(), "禁止在禁停区内停车");
        }

        // 发送命令锁车
        return deviceIotService.lock(device, false, "订单锁车：" + order.getNo(), dto.getRequiredIot(), 1);
    }

    @Override
    public int updateOrderDeviceId(Long id, Long orderDeviceId) {
        if (id == null || orderDeviceId == null) {
            return 0;
        }
        Order order = new Order();
        order.setId(id);
        order.setOrderDeviceId(orderDeviceId);
        return orderMapper.updateOrder(order);
    }

    @Override
    public int changeDevice(OrderChangeDeviceDTO dto) {
        OrderChangeBO bo = orderConverter.toChangeBO(dto);
        ServiceUtil.assertion(bo == null, "参数错误，bo不允许为空");

        OrderDeviceVO oldOrderDevice = bo.getOldOrderDevice();
        OrderDevice newOrderDevice = bo.getNewOrderDevice();
        OrderVO order = bo.getOrder();
        OrderInParkingVO inParkingVO = bo.getInParkingVO();
        DeviceVO oldDevice = bo.getOldDevice();

        // 设置日志参数
        this.setLogParam(oldDevice);
        // 异步使用手机定位更新设备定位
        this.handleDeviceLocationAsync(oldDevice, dto.getLon(), dto.getLat());

        // 操作数据库
        Integer result = transactionTemplate.execute(status -> {
            // 结束当前订单设备
            int finish = orderDeviceService.finish(oldOrderDevice, dto.getFaultPicture(), inParkingVO);
            ServiceUtil.assertion(finish != 1, "结束当前订单设备失败");

            // 创建故障信息
            if (OrderDeviceReason.DEVICE_FAULT.getCode().equals(dto.getReason())) {
                Fault fault = faultConverter.toPo(dto, oldOrderDevice);
                int insertFault = faultService.insertFault(fault);
                ServiceUtil.assertion(insertFault != 1, "创建故障信息失败");
                newOrderDevice.setFaultId(fault.getId()); // 设置故障ID
            }

            // 创建新订单设备
            int insert = orderDeviceService.insertOrderDevice(newOrderDevice);
            ServiceUtil.assertion(insert != 1, "创建新订单设备失败");

            // 开始新订单设备
            int start = orderDeviceService.start(newOrderDevice.getId());
            ServiceUtil.assertion(start != 1, "开始新订单设备失败");

            // 设备操作（必须放最后，因为会操作设备）
            // 旧设备上锁
            DeviceIotVO lock = deviceIotService.lock(oldOrderDevice.getDeviceId(), false, "订单换车上锁：" + order.getNo(),
                    false);
            ServiceUtil.assertion(lock.getDb() != 1, "ID为%s的旧设备上锁失败", oldOrderDevice.getDeviceId());
            // 新设备解锁
            DeviceIotVO unlock = deviceIotService.unlock(newOrderDevice.getDeviceId(), DeviceUnLockType.USER,
                    "订单换车开锁：" + order.getNo(), false);
            ServiceUtil.assertion(unlock.getDb() != 1, "ID为%s的新设备解锁失败", newOrderDevice.getDeviceId());

            return start;
        });

        return result == null ? 0 : result;
    }

    @Override
    public int verify(OrderVerifyDTO dto) {
        // 查询订单
        OrderVO order = this.selectOrderById(dto.getId());
        ServiceUtil.assertion(order == null, "ID为%s的订单不存在", dto.getId());
        ServiceUtil.assertion(!OrderStatus.canVerify().contains(order.getStatus()), "ID为%s的订单当前状态不允许审核", dto.getId());

        // 更新订单状态
        Integer result = transactionTemplate.execute(status -> {
            // 更新订单状态
            Order data = new Order();
            data.setStatus(OrderStatus.FINISHED.getCode());
            data.setVerifyRemark(dto.getRemark());
            OrderQuery query = new OrderQuery();
            query.setId(dto.getId());
            query.setStatusList(OrderStatus.canVerify());
            int rows = orderMapper.updateByQuery(data, query);
            ServiceUtil.assertion(rows != 1, "ID为%s的订单审核失败", dto.getId());

            // 更新车损费
            if (dto.getDeductionFee() != null && dto.getDeductionFee().compareTo(BigDecimal.ZERO) > 0) {
                BigDecimal max = OrderUtil.calcRemainCanDeductDeposit(order);
                ServiceUtil.assertion(MathUtils.biggerThan(dto.getDeductionFee(), max), "ID为%s的订单车损费不允许超过%s",
                        dto.getId(), max);
                int add = orderMapper.addDeductionFee(order.getId(), dto.getDeductionFee());
                ServiceUtil.assertion(add != 1, "ID为%s的订单增加车损费失败，请刷新后重试", order.getId());
            }

            // 订单结束操作
            this.handleFinished(order.getId());

            return rows;
        });


        return result == null ? 0 : result;
    }

    private boolean prepayBonus(OrderVO order) {
        if (order == null) {
            return false;
        }
        return bonusService.prepayByBst(BonusBstType.ORDER, order.getId(), order.getActualAmount(), order.getEndTime());
    }

    @Override
    public List<Long> selectIdList(OrderQuery query) {
        return orderMapper.selectIdByQuery(query);
    }

    @Override
    public int updateDisatance(Long id, BigDecimal distance) {
        if (id == null || distance == null) {
            return 0;
        }
        Order data = new Order();
        data.setId(id);
        data.setDistance(distance);
        return orderMapper.updateOrder(data);
    }

    @Override
    public boolean seat(OrderSeatDTO dto) {
        OrderVO order = this.selectOrderById(dto.getOrderId());
        ServiceUtil.assertion(order == null, "ID为%s的订单不存在", dto.getOrderId());
        ServiceUtil.assertion(!OrderStatus.inUse().contains(order.getStatus()), "ID为%s的订单当前状态不允许打开坐垫锁", dto.getOrderId());

        // 查询设备
        DeviceVO device = deviceService.selectDeviceById(order.getDeviceId());
        ServiceUtil.assertion(device == null, "ID为%s的设备不存在", order.getDeviceId());
        boolean enableSeat = device.getModelEnableSeat() != null && device.getModelEnableSeat();
        ServiceUtil.assertion(!enableSeat, "ID为%s的设备不允许用户打开坐垫锁", order.getDeviceId());

        // 设置日志参数
        this.setLogParam(device);

        // 异步使用手机定位更新设备定位
        this.handleDeviceLocationAsync(device, dto.getLon(), dto.getLat());

        // 发送命令开锁
        return deviceIotService.unlockSeat(device, "订单打开坐垫锁：" + order.getNo(), dto.getRequiredIot());
    }

    @Override
    public int deduct(OrderDeductDTO dto) {
        // 转为BO
        OrderDeductBO bo = orderConverter.toDeductBo(dto);
        // 校验参数
        orderValidator.validate(bo);

        OrderVO order = bo.getOrder();
        VipUserVO vipUser = bo.getVipUser();
        OrderCalcRideFeeVO fee = bo.getFee();

        // 加锁
        Long lockKey = order.getId();
        boolean lock = redisLock.lock(RedisLockKey.ORDER_PAY_RIDE_FEE, lockKey);
        ServiceUtil.assertion(!lock, "ID为%s的订单正在支付中，请稍后重试", order.getId());
        try {
            // 获取实际抵扣金额
            BigDecimal max = OrderUtil.calcRemainCanDeductDeposit(order);
            BigDecimal deductAmount = MathUtils.min(MathUtils.dv(fee.getPayAmount()), max);

            // 关闭订单的支付ID
            boolean closePay = payService.closeByBstId(PayBstType.ORDER_RIDE.getType(), order.getId());
            ServiceUtil.assertion(!closePay, "ID为%s的订单骑行费支付关闭失败", order.getId());

            // 更新订单数据
            Integer result = transactionTemplate.execute(status -> {
                // 恢复旧优惠券次数，清空订单优惠券信息
                this.recoverVipCount(order);

                // 若有使用优惠券，则扣减优惠券次数
                if (vipUser != null) {
                    int deduct = vipUserService.deductVipCount(vipUser.getId(), 1);
                    ServiceUtil.assertion(deduct != 1, "优惠券可用次数不足");
                }

                // 押金抵扣
                Order data = new Order();
                data.setDepositDeductionAmount(deductAmount);
                data.setId(order.getId());
                this.setVipInfo(data, vipUser, fee);
                int deduct = orderMapper.deductDeposit(data);
                ServiceUtil.assertion(deduct != 1, "ID为%s的订单押金抵扣失败，剩余可抵扣押金不足%s元", order.getId(), deductAmount);

                // 处理抵扣成功
                OrderRidePaySuccessDTO successDto = new OrderRidePaySuccessDTO();
                successDto.setOrderId(order.getId());
                successDto.setPayType(OrderPayType.DEPOSIT_DEDUCTION);
                successDto.setPayAmount(deductAmount);
                successDto.setPayId(null);
                successDto.setPayTime(LocalDateTime.now());
                return this.handleRidePaySuccess(successDto);
            });

            return result == null ? 0 : result;
        } finally {
            redisLock.unlock(RedisLockKey.ORDER_PAY_RIDE_FEE, lockKey);
        }
    }

    /**
     * 处理骑行费支付成功
     */
    @Override
    public int handleRidePaySuccess(OrderRidePaySuccessDTO dto) {
        OrderVO order = selectOrderById(dto.getOrderId());
        ServiceUtil.assertion(order == null, "ID为%s的订单不存在", dto.getOrderId());

        OrderPayType payType = dto.getPayType();

        // 更新订单数据
        Order data = new Order();
        // 支付信息
        data.setPayType(payType.getCode());
        data.setRidePayId(dto.getPayId());
        data.setRidePayTime(dto.getPayTime());
        this.setActualAmount(data, order, dto.getPayAmount());
        if (order.getAreaReturnVerify() != null && order.getAreaReturnVerify()) {
            data.setStatus(OrderStatus.WAIT_VERIFY.getCode());
        } else {
            data.setStatus(OrderStatus.FINISHED.getCode());
        }
        OrderQuery query = new OrderQuery();
        query.setId(order.getId());
        query.setStatusList(OrderStatus.canRidePaySuccess());
        query.setIsNullPayType(true);

        Integer result = transactionTemplate.execute(status -> {
            int rows = orderMapper.updateByQuery(data, query);
            ServiceUtil.assertion(rows != 1, "ID为%s的骑行支付更新失败", order.getId());

            // 当订单状态为待审核时，发送还车审核通知
            if (OrderStatus.WAIT_VERIFY.getCode().equals(data.getStatus())) {
                smsService.sendOrderWaitVerifyMsg(order);
            }

            // 订单结束操作
            if (OrderStatus.FINISHED.getCode().equals(data.getStatus())) {
                this.handleFinished(order.getId());
            }

            return rows;
        });

        return result == null ? 0 : result;
    }

    @Override
    public DoPayVO payRideFee(OrderPayRideFeeDTO dto) {
        ServiceUtil.assertion(dto == null, "参数错误，dto不允许为空");
        ServiceUtil.assertion(dto.getOrderId() == null, "参数错误，订单ID不允许为空");

        // 加锁
        Long lockKey = dto.getOrderId();
        boolean lock = redisLock.lock(RedisLockKey.ORDER_PAY_RIDE_FEE, lockKey);
        ServiceUtil.assertion(!lock, "ID为%s的订单正在支付中，请稍后重试", dto.getOrderId());
        try {
            // 转为BO
            OrderPayRideFeeBO bo = orderConverter.toPayRideFeeBO(dto);

            // 校验数据
            orderValidator.validate(bo);

            OrderVO order = bo.getOrder();
            VipUserVO vipUser = bo.getVipUser();
            OrderCalcRideFeeVO fee = bo.getFee();

            return transactionTemplate.execute(status -> {
                // 恢复旧优惠券次数，清空订单优惠券信息
                this.recoverVipCount(order);

                // 更新订单信息
                Order data = new Order();
                this.setVipInfo(data, vipUser, fee);
                OrderQuery query = new OrderQuery();
                query.setId(order.getId());
                query.setIsNullVipUserId(true);
                int rows = orderMapper.updateByQuery(data, query);
                ServiceUtil.assertion(rows != 1, "ID为%s的订单更新失败", order.getId());

                // 若有使用优惠券，则扣减优惠券次数
                if (vipUser != null) {
                    int deduct = vipUserService.deductVipCount(vipUser.getId(), 1);
                    ServiceUtil.assertion(deduct != 1, "优惠券可用次数不足");
                }

                // 转为支付单
                Pay pay = payConverter.toPayPO(bo);

                // 创建并调起支付
                return payService.createPayBill(pay);

            });
        } finally {
            redisLock.unlock(RedisLockKey.ORDER_PAY_RIDE_FEE, lockKey);
        }

    }

    /**
     * 设置卡券及费用信息
     */
    private void setVipInfo(Order data, VipUserVO vipUser, OrderCalcRideFeeVO fee) {
        if (data == null)  {
            return;
        }
        if (vipUser != null) {
            data.setVipUserId(vipUser.getId());
            data.setVipDiscountValue(vipUser.getDiscount());
            data.setVipType(vipUser.getType());
            data.setVipName(vipUser.getName());
        }
        if (fee != null) {
            data.setRidingDiscount(fee.getRideFeeDiscount());
        }
    }

    /**
     * 恢复VIP优惠次数
     */
    private int recoverVipCount(OrderVO order) {
        ServiceUtil.assertion(order == null, "订单不存在");
        if (order.getVipUserId() == null) {
            return 1;
        }
        ServiceUtil.assertion(!OrderStatus.canRecoverVipCount().contains(order.getStatus()), "ID为%s的订单当前状态不允许恢复VIP优惠次数", order.getId());

        Integer result = transactionTemplate.execute(status -> {
            // 清空订单的VIP信息
            int clear = orderMapper.clearVipInfo(order.getId(), order.getVipUserId());
            ServiceUtil.assertion(clear != 1, "ID为%s的订单清空VIP信息失败", order.getId());
            // 尝试恢复VIP优惠次数
            try {
                vipUserService.recoverVipCount(order.getVipUserId(), 1);
            } catch (Exception e) {
                log.error("ID为{}的订单恢复VIP优惠次数失败", order.getId(), e);
            }
            return clear;
        });

        return result == null ? 0 : result;
    }

    @Override
    public int updatePrice(OrderUpdatePriceDTO dto) {
        // 查询订单
        OrderVO order = this.selectOrderById(dto.getId());
        ServiceUtil.assertion(order == null || order.getId() == null, "ID为%s的订单不存在", dto.getId());
        ServiceUtil.assertion(!OrderStatus.canUpdatePrice().contains(order.getStatus()), "ID为%s的订单当前状态不允许改价", dto.getId());

        // 加锁
        Long lockKey = order.getId();
        boolean lock = redisLock.lock(RedisLockKey.ORDER_PAY_RIDE_FEE, lockKey);
        ServiceUtil.assertion(!lock, "ID为%s的订单正在支付中，请稍后重试", dto.getId());
        try {

            // 关闭支付订单
            boolean closePay = payService.closeByBstId(PayBstType.ORDER_RIDE.getType(), order.getId());
            ServiceUtil.assertion(!closePay, "ID为%s的订单骑行费支付关闭失败", dto.getId());

            Integer result = transactionTemplate.execute(status -> {
                // 修改订单数据
                Order data = new Order();
                data.setRidingFee(dto.getRidingFee());
                data.setDispatchFee(dto.getDispatchFee());
                data.setManageFee(dto.getManageFee());
                data.setTotalFee(OrderUtil.calcTotalFee(data));
                data.setPriceChanged(true);
                OrderQuery query = new OrderQuery();
                query.setId(order.getId());
                query.setStatusList(OrderStatus.canUpdatePrice());
                int rows = orderMapper.updateByQuery(data, query);
                ServiceUtil.assertion(rows != 1, "ID为%s的订单状态已发生变化，请刷新后重试", dto.getId());

                // 新增改价记录
                FeeLog feeLog = feeLogConverter.toPo(dto, order);
                int insert = feeLogService.insertFeeLog(feeLog);
                ServiceUtil.assertion(insert != 1, "ID为%s的订单改价记录新增失败", dto.getId());

                return rows;
            });

            return result == null ? 0 : result;
        } finally {
            redisLock.unlock(RedisLockKey.ORDER_PAY_RIDE_FEE, lockKey);
        }
    }

    /**
     * 计算应付骑行费
     *
     * @param dto
     * @return
     */
    @Override
    public OrderCalcRideFeeVO calcRideFee(OrderCalcRideFeeDTO dto) {
        OrderVO order = this.selectOrderById(dto.getOrderId());
        VipUserVO vipUser = vipUserService.selectVipUserById(dto.getVipUserId());
        return calcRideFee(order, vipUser);
    }

    @Override
    public OrderCalcRideFeeVO calcRideFee(OrderVO order, VipUserVO vipUser) {
        ServiceUtil.assertion(order == null, "订单不存在");

        // 计算应付费用
        OrderCalcRideFeeVO vo = new OrderCalcRideFeeVO();
        vo.setOriginalAmount(order.getRidingFee());
        vo.setRideFeeDiscount(VipUserUtil.calcDiscountAmount(vo.getOriginalAmount(), vipUser)); // 骑行费优惠
        vo.setRideFee(MathUtils.subtractDecimal(vo.getOriginalAmount(), vo.getRideFeeDiscount()));    // 骑行费
        vo.setDispatchFee(order.getDispatchFee()); // 调度费
        vo.setManageFee(order.getManageFee()); // 管理费
        vo.setDeductionFee(order.getDeductionFee()); // 车损费

        return vo;
    }

    @Override
    public OrderCalcPreRideFeeVO calcPreRideFee(Long orderId, LocalDateTime endTime) {
        OrderVO order = this.selectOrderById(orderId);
        return OrderUtil.calcRideFee(order, endTime);
    }
}
