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.device.domain.DeviceVO;
import com.ruoyi.bst.device.domain.enums.DeviceUnLockType;
import com.ruoyi.bst.device.domain.vo.DeviceIotVO;
import com.ruoyi.bst.device.service.DeviceIotService;
import com.ruoyi.bst.device.service.DeviceService;
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.locationLog.utils.LocationLogUtil;
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.OrderEndBO;
import com.ruoyi.bst.order.domain.dto.OrderCalcFeeDTO;
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.OrderEndDTO;
import com.ruoyi.bst.order.domain.dto.OrderRefundDTO;
import com.ruoyi.bst.order.domain.dto.OrderVerifyDTO;
import com.ruoyi.bst.order.domain.enums.OrderReturnType;
import com.ruoyi.bst.order.domain.enums.OrderStatus;
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.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.OrderDeviceConverter;
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.common.core.redis.RedisLock;
import com.ruoyi.common.core.redis.enums.RedisLockKey;
import com.ruoyi.common.utils.DateUtils;
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.collection.CollectionUtils;
import com.ruoyi.system.user.service.UserService;

/**
 * 订单Service业务层处理
 *
 * @author ruoyi
 * @date 2025-03-24
 */
@Service
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 OrderDeviceConverter orderDeviceConverter;

    @Autowired
    private UserService userService;

    @Autowired
    private SmsService smsService;

    /**
     * 查询订单
     *
     * @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)
    {
        return orderMapper.selectOrderList(order);
    }

    /**
     * 新增订单
     *
     * @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, "参数错误");

        // 加锁，防止设备重复下单
        // TODO 可以考虑加锁60秒，存储车辆、用户ID，60秒内只允许同一个用户下单。
        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);

        // 校验参数
        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);
        // 订单状态
        this.setOrderStatus(order, returnType);
        // 订单费用
        this.setOrderFee(order, area, inParkingVO);

        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);

            // 当订单状态为已完成时，处理订单完成操作
            if (OrderStatus.FINISHED.getCode().equals(order.getStatus())) {
                int refund = this.refundRemainAmount(order.getId());
                ServiceUtil.assertion(refund != 1, "ID为%s的订单退还剩余金额失败", order.getId());

                // 预分成
                boolean bonus = bonusService.prepayByBst(BonusBstType.ORDER, order.getId());
                ServiceUtil.assertion(!bonus, "ID为%s的订单预分成失败", order.getId());
            } else if (OrderStatus.WAIT_VERIFY.getCode().equals(order.getStatus())) {
                // 发送还车审核通知
                smsService.sendOrderWaitVerifyMsg(order);
            }

            // 结束订单设备
            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(), false);
            ServiceUtil.assertion(lock.getDb() != 1, "ID为%s的设备上锁失败", orderDevice.getDeviceId());
            vo.setIot(lock.getIot());

            return rows;
        });

        return vo;
    }

    // 设置订单状态
    private void setOrderStatus(OrderVO order, String returnType) {
        // 根据是否需要审核，设置订单状态
        if (order.getAreaReturnVerify() != null && order.getAreaReturnVerify() && OrderReturnType.needVerify().contains(returnType)) {
            // 更新订单状态为待审核
            order.setStatus(OrderStatus.WAIT_VERIFY.getCode());
        } else {
            // 更新订单状态为已完成
            order.setStatus(OrderStatus.FINISHED.getCode());
        }
    }

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

    // 退还剩余金额
    private int refundRemainAmount(Long orderId) {
        // 查询订单
        OrderVO order = this.selectOrderById(orderId);
        if (order == null) {
            return 0;
        }

        // 订单剩余金额退款
        BigDecimal refund = MathUtils.subtractDecimal(order.getPayAmount(), order.getTotalFee());
        if (refund != null && refund.compareTo(BigDecimal.ZERO) > 0) {
            return this.refund(order, refund, null, null, "系统", RefundType.AUTO.getCode());
        }

        return 1;
    }

    /**
     * 退款
     * @param order 订单
     * @param amount 退款金额
     * @param reason 退款原因
     * @param userId 操作人ID
     * @param userName 操作人名称
     * @return 结果
     */
    private int refund(OrderVO order, BigDecimal amount, String reason, Long userId, String userName, String type) {
        ServiceUtil.assertion(order == null, "参数错误，order不允许为空");
        ServiceUtil.assertion(!OrderStatus.canRefund().contains(order.getStatus()), "ID为%s的订单当前状态不允许退款", order.getId());
        ServiceUtil.assertion(amount == null || amount.compareTo(BigDecimal.ZERO) <= 0, "参数错误，退款金额不允许为空且必须大于0");

        BigDecimal canRefundAmount = OrderUtil.calcCanRefundAmount(order);
        ServiceUtil.assertion(canRefundAmount.compareTo(amount) < 0, "ID为%s的订单可退款金额不足，当前可退款金额为%s元", order.getId(), canRefundAmount);

        
        // 退款原因
        String refundReason = null;
        if (RefundType.ADMIN.getCode().equals(type)) {
            refundReason = String.format("【管理员退款】%s订单%s退款 %s 元", userName, order.getNo(), amount);
        } else {
            refundReason = String.format("【自动退款】%s订单%s退款 %s 元", userName, order.getNo(), amount);
        }
        if (StringUtils.isNotBlank(reason)) {
            refundReason += "：" + reason;
        }
        String finalRefundReason = refundReason;
        
        Integer result = transactionTemplate.execute(status -> {
        
            // 分成退款
            boolean bonusRefund = bonusService.refundByBst(BonusBstType.ORDER, order.getId(), amount, order.getPayAmount(), finalRefundReason);
            ServiceUtil.assertion(!bonusRefund, "ID为%s的订单分成退款失败", order.getId());

            // 支付退款
            PayRefundDTO dto = new PayRefundDTO();
            dto.setId(order.getPayId());
            dto.setRefundAmount(amount);
            dto.setRefundReason(finalRefundReason);
            dto.setUserId(userId);
            dto.setUserName(userName);
            dto.setType(type);
            return payService.refund(dto);
        });

        return result == null ? 0 : 1;

    }

    @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());
        deviceIotService.refresh(device, null);
        if (device == null) {
            return null;
        }

        // 查询运营区
        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());
    }

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

        return this.refund(order, dto.getAmount(), dto.getReason(), dto.getUserId(), dto.getUserName(), dto.getType());
    }

    @Override
    public DeviceIotVO openDevice(OrderVO order, boolean requiredIot) {
        ServiceUtil.assertion(order == null, "参数错误，order不允许为空");
        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());

        return deviceIotService.unlock(orderDevice.getDeviceId(), DeviceUnLockType.USER, "订单开锁：" + order.getNo(), requiredIot);
    }

    @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());
        deviceIotService.refresh(device, null);

        // 判断是否在禁停区内
        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());
    }

    @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();

        // 操作数据库
        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());

        // 更新订单状态
        boolean pass = dto.getPass() != null && dto.getPass();
        Integer result = transactionTemplate.execute(status -> {
            // 更新订单状态
            Order data = new Order();
            data.setStatus(pass ? OrderStatus.FINISHED.getCode() : OrderStatus.REJECTED.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 = MathUtils.subtractDecimal(order.getDepositFee(), order.getTotalFee());
                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());
            }

            // 若审核通过，则退还剩余金额
            if (pass && rows > 0) {
                int refund = this.refundRemainAmount(order.getId());
                ServiceUtil.assertion(refund != 1, "ID为%s的订单退还剩余金额失败", order.getId());
            }

            // 预分成
            boolean bonus = bonusService.prepayByBst(BonusBstType.ORDER, order.getId());
            ServiceUtil.assertion(!bonus, "ID为%s的订单预分成失败", order.getId());

            return rows;
        });

        return result == null ? 0 : result;
    }

    @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);
    }

}
