package com.sckw.transport.handler;


import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.sckw.core.common.enums.enums.DictTypeEnum;
import com.sckw.core.common.enums.enums.ErrorCodeEnum;
import com.sckw.core.exception.BusinessPlatfromException;
import com.sckw.core.model.constant.Global;
import com.sckw.core.model.enums.*;
import com.sckw.core.utils.CollectionUtils;
import com.sckw.fleet.api.model.vo.RDriverScoreVo;
import com.sckw.fleet.api.model.vo.RDriverVo;
import com.sckw.fleet.api.model.vo.RTruckVo;
import com.sckw.fleet.api.model.vo.TruckDispatchCoefficientVO;
import com.sckw.order.api.model.OrderDetailVo;
import com.sckw.order.api.model.OrderUnitInfoDetailVO;
import com.sckw.order.api.model.UpdateActualAmountParam;
import com.sckw.product.api.model.KwpGoods;
import com.sckw.transport.model.*;
import com.sckw.transport.model.param.OrderCirculateTakingQueryParam;
import com.sckw.transport.model.param.OrderTakingResp;
import com.sckw.transport.repository.KwtGatekeeperWaybillOrderRepository;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Author: donglang
 * Time: 2025-11-19
 * Des: 接单处理器Handler
 * Version: 1.0
 */

@Slf4j
@Service
public class TakingOrderHandler extends AbstractWaybillOrderHandler<OrderCirculateTakingQueryParam> {


    @Autowired
    private KwtGatekeeperWaybillOrderRepository gatekeeperWaybillOrderRepository;

    // 定义常量
    private static final BigDecimal EIGHTY_PERCENT = new BigDecimal("0.8");
    private static final BigDecimal TWO_TONS = new BigDecimal("2");
    // 定义禁止运单接单的状态集合
    private static final List<Integer> FORBIDDEN_STATUSES = Arrays.asList(
            CarWaybillV1Enum.PENDING_VEHICLE.getCode(),
            CarWaybillV1Enum.REFUSE_TRAFFIC.getCode(),
            CarWaybillV1Enum.EXIT_COMPLETED.getCode(),
            CarWaybillV1Enum.EMPTY_WAIT_LEAVE.getCode(),
            CarWaybillV1Enum.WAIT_LEAVE.getCode(),
            CarWaybillV1Enum.UNLOADING.getCode(),
            CarWaybillV1Enum.WAIT_RELEASE.getCode(),
            CarWaybillV1Enum.REPLENISHING.getCode(),
            CarWaybillV1Enum.REPLENISH_FINISH.getCode(),
            CarWaybillV1Enum.RELEASED_NOT_EXITED.getCode(),
            CarWaybillV1Enum.WAIT_LOADING.getCode(),
            CarWaybillV1Enum.REVIEW_REJECTION.getCode()
    );

    // 定义禁止运单接单的状态集合
    private static final List<Integer> RAW_ORE_FORBIDDEN_STATUSES = Arrays.asList(
            CarWaybillV1Enum.PENDING_VEHICLE.getCode(),
            CarWaybillV1Enum.REFUSE_TRAFFIC.getCode(),
            CarWaybillV1Enum.EXIT_COMPLETED.getCode(),
            CarWaybillV1Enum.EMPTY_WAIT_LEAVE.getCode(),
            CarWaybillV1Enum.WAIT_LEAVE.getCode(),
            CarWaybillV1Enum.UNLOADING.getCode(),
            CarWaybillV1Enum.WAIT_RELEASE.getCode(),
            CarWaybillV1Enum.REPLENISHING.getCode(),
            CarWaybillV1Enum.REPLENISH_FINISH.getCode(),
            CarWaybillV1Enum.RELEASED_NOT_EXITED.getCode(),
            CarWaybillV1Enum.WAIT_LOADING.getCode(),

            CarWaybillV1Enum.UNLOADING_POINT.getCode(),
            CarWaybillV1Enum.UNLOADING_WAIT_LEAVE.getCode(),
            CarWaybillV1Enum.UNLOADING_WAIT_RELEASE.getCode(),

            CarWaybillV1Enum.REVIEW_REJECTION.getCode()
    );


    @Override
    protected KwtWaybillOrder getWaybillOrder(OrderCirculateTakingQueryParam param) {
        // 接单时运单未创建
        return null;
    }


    @Override
    protected void checkState(OrderCirculateTakingQueryParam param, KwtWaybillOrder waybillOrder) {
        // 1.校验车辆是否已被派单
        checkTruckDispatch(param);
        // 2.校验物流订单
        KwtLogisticsOrder logOrder = checkLogOrder(param);
        // 3.校验交易订单
        OrderDetailVo tradeOrder = checkTradeOrder(param, logOrder);
        // 4.校验司机
        RDriverVo driver = checkDriver(param);
        // 5.校验车辆
        RTruckVo truck = checkTruck(param);
        // 6.校验车辆是否已有未完成运单
        checkTruckUnfinished(param, logOrder);

        // 存储到线程上下文
        BusinessContext.set("logOrder", logOrder);
        BusinessContext.set("tradeOrder", tradeOrder);
        BusinessContext.set("driver", driver);
        BusinessContext.set("truck", truck);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doBusiness(OrderCirculateTakingQueryParam param, KwtWaybillOrder waybill) {
        KwtLogisticsOrder logOrder = BusinessContext.get("logOrder");
        OrderDetailVo tradeOrder = BusinessContext.get("tradeOrder");
        RDriverVo driver = BusinessContext.get("driver");
        RTruckVo truck = BusinessContext.get("truck");

        // 计算任务量（含接单校验）
        BigDecimal truckLoadVolume = queryCurTruckLoadVolume(truck, tradeOrder, logOrder);

        //1、生成物流运单
        KwtWaybillOrder waybillOrder = createWaybillOrder(param, driver, truck, logOrder);

        //2、生成物流子运单
        KwtWaybillOrderSubtask waybillOrderSubtask = createWaybillOrderSubtask(param, waybillOrder, truckLoadVolume);

        //3、生成物流运单地址
        List<KwtWaybillOrderAddress> addresses = createWaybillOrderAddress(param, waybillOrder, waybillOrderSubtask);

        //4、生成车辆运单-装卸货信息
        createWaybillOrderTicket(logOrder, waybillOrder, waybillOrderSubtask, addresses);

        //5、更新上游订单：回写物流订单
        updateLogOrder(logOrder, truckLoadVolume);

        //6、更新上游订单：回写贸易订单
//        updateTradeOrder(tradeOrder, truckLoadVolume);

        //7、绑定车辆
        driverBindTruck(waybillOrder);

        //8、生成门卫订单
        createGatekeeperWaybillOrder(logOrder, waybillOrder, truck, truckLoadVolume);

        BusinessContext.set("createdWaybillOrder", waybillOrder);

        log.info("物流订单接单完成，运单ID：{}", waybillOrder.getId());
    }

    /**
     * 创建门卫订单
     *
     * @param waybillOrder
     * @param truckLoadVolume
     */
    private void createGatekeeperWaybillOrder(KwtLogisticsOrder logOrder, KwtWaybillOrder waybillOrder,
                                              RTruckVo truck, BigDecimal truckLoadVolume) {
        log.info("开始创建门卫订单，入参参数：{}", JSON.toJSONString(waybillOrder));
        try {
            // 获取企业id
            Long entId = getEntId(logOrder);

            KwtGatekeeperWaybillOrder gatekeeper = new KwtGatekeeperWaybillOrder();
            gatekeeper.setEntId(entId);
            gatekeeper.setWOrderId(waybillOrder.getId());
            gatekeeper.setWOrderNo(waybillOrder.getWOrderNo());
            gatekeeper.setLOrderId(waybillOrder.getLOrderId());

            //查询字典
            Map<String, Map<String, String>> dictValueAndDictResDtoMap = remoteSystemService.queryDictByType(
                    Arrays.asList(DictTypeEnum.PRODUCT_NAME_TYPE.getType(), DictTypeEnum.GOODS_SPEC.getType()));
            Map<String, String> goodsTypeMap= dictValueAndDictResDtoMap.getOrDefault(DictTypeEnum.PRODUCT_NAME_TYPE.getType(), new HashMap<>());
            Map<String, String> goodsSpecMap= dictValueAndDictResDtoMap.getOrDefault(DictTypeEnum.GOODS_SPEC.getType(), new HashMap<>());

            // 查询商品信息
            KwtLogisticsOrderGoods orderGoods = logisticsOrderGoodsRepository.queryByLogOrderId(waybillOrder.getLOrderId());
            KwpGoods goods = goodsInfoService.getGoodsById(orderGoods.getGoodsId());
            if (goods != null) {
                gatekeeper.setGoodsId(goods.getId());
                gatekeeper.setGoodsName(goods.getName()+"/"+goodsTypeMap.getOrDefault(goods.getGoodsType(),"")+"/"+goodsSpecMap.getOrDefault(goods.getSpec(), ""));
            }

            gatekeeper.setWaybillAcceptTime(waybillOrder.getCreateTime());
            gatekeeper.setType(GatekeeperTypeEnum.LOADING.getCode());
            gatekeeper.setStatus(GatekeeperStatusEnum.PENDING_ENTRY.getCode());
            gatekeeper.setTruckType(truck.getTruckType());
            gatekeeper.setEntrustAmount(truckLoadVolume);
            gatekeeper.setCarAxis(truck.getCarAxis());
            gatekeeper.setLegalLoad(truck.getLegalLoad());
            gatekeeper.setCreateTime(new Date());
            gatekeeper.setCreateUser(waybillOrder.getDriverId());
            gatekeeper.setUpdateUser(waybillOrder.getDriverId());

            log.debug("开始保存门卫订单数据，运单ID:{}", waybillOrder.getId());
            gatekeeperWaybillOrderRepository.save(gatekeeper);
            log.debug("门卫订单数据保存成功");
        } catch (Exception e) {
            log.error("保存门卫订单数据失败！");
        }
    }

    /**
     * 获取企业id
     * @param logOrder
     * @return
     */
    private Long getEntId(KwtLogisticsOrder logOrder) {
        log.info("[创建装货门卫]开始查询企业id，入参参数：{}", JSON.toJSONString(logOrder));
        List<OrderUnitInfoDetailVO> unitInfoDetailVOS = tradeOrderInfoService.queryOrderUnitByTradeOrderId(logOrder.getTOrderId());
        OrderUnitInfoDetailVO unitInfoDetailVO = unitInfoDetailVOS.stream()
                .filter(unit -> Objects.equals(unit.getUnitType(), "2"))
                .findFirst().orElse(new OrderUnitInfoDetailVO());
        Long entId = unitInfoDetailVO.getEntId();
        log.info("[创建装货门卫]查询企业id完成，入参参数：{}", JSON.toJSONString(entId));
        return entId;
    }

    @Override
    protected void calculateAutoDispatchScore(OrderCirculateTakingQueryParam param, KwtWaybillOrder waybillOrder) {

    }


    /**
     * 校验车辆是否已被派单
     * @param param
     */
    private void checkTruckDispatch(OrderCirculateTakingQueryParam param) {
        KwtLogisticsOrderCirculate orderCirculate = logisticsOrderCirculateRepository
                .findOneByLogOrderIdsAndTruckNo(param.getLogOrderId(), param.getTruckNo(), param.getEntId());
        if (orderCirculate == null) {
            throw new BusinessPlatfromException(ErrorCodeEnum.LOGISTICS_ORDER_NOT_DISPATCH_TRUCK, "当前车辆无派车数据，不可继续接单");
        }
    }

    /**
     * 校验物流订单是否是可接单状态
     * @param param
     * @return
     */
    private KwtLogisticsOrder checkLogOrder(OrderCirculateTakingQueryParam param) {
        KwtLogisticsOrder logOrder = logisticsOrderRepository.queryByLogOrderIdAndStatus(param.getLogOrderId(), LogisticsOrderV1Enum.IN_TRANSIT.getCode());
        if (logOrder == null || logOrder.getEndTime().isBefore(LocalDateTime.now())) {
            throw new BusinessPlatfromException(ErrorCodeEnum.LOGISTICS_ORDER_STATUS_ERROR, "物流订单非可接单状态");
        }
        return logOrder;
    }

    /**
     * 校验交易订单状态
     * @param param
     * @param logOrder
     * @return
     */
    private OrderDetailVo checkTradeOrder(OrderCirculateTakingQueryParam param, KwtLogisticsOrder logOrder) {
        // 原矿运输没有贸易订单
        if (Objects.equals(1, logOrder.getOrderType())) {
            return new OrderDetailVo();
        }
        OrderDetailVo orderDetail = tradeOrderInfoService.queryByTradeOrderId(logOrder.getTOrderId());
        if (orderDetail == null || orderDetail.getStatus() == Global.NUMERICAL_ONE) {
            throw new BusinessPlatfromException(ErrorCodeEnum.TRADE_ORDER_STATUS_ERROR, "当前物流订单的交易订单已锁定");
        }
        return orderDetail;
    }

    /**
     * 校验司机状态
     * @param param
     * @return
     */
    private RDriverVo checkDriver(OrderCirculateTakingQueryParam param) {
        RDriverVo driverVo = remoteFleetService.findDriver(param.getDriverId());
        if (driverVo == null || Objects.equals(driverVo.getStatus(), Global.NUMERICAL_ONE)) {
            throw new BusinessPlatfromException(ErrorCodeEnum.DRIVER_STATUS_ERROR, "当前司机已锁定");
        }
        //校验是否是自动派单
        KwtLogisticsOrder logisticsOrder = getLogisticsOrder(param.getLogOrderId());
        if (!DispatchWayEnums.AUTO_DISPATCH.getCode().equals(logisticsOrder.getDispatchWay())) {
            return driverVo;
        }
        //查询订单托运单位
        KwtLogisticsOrderUnit logisticsOrderUnit = logisticsOrderUnitRepository.queryByLOrderIdAndUnitType(param.getLogOrderId(), 1);
        if (logisticsOrderUnit == null || logisticsOrderUnit.getEntId() == null) {
            throw new BusinessPlatfromException(ErrorCodeEnum.LOGISTICS_ORDER_NOT_ENT, "未找到关联的物流订单托运企业（供应商）！");
        }

        //查询司机派车系数
        TruckDispatchCoefficientVO dispatchCoefficient = getAutoTruckDispatchByEntId(logisticsOrderUnit.getEntId());
        Integer driverOrderLimit = dispatchCoefficient.getDriverOrderLimit();
        //查询司机分数
        RDriverScoreVo driverScore = remoteFleetService.findDriverScore(logisticsOrderUnit.getEntId(), param.getEntId(), param.getDriverId());
        if (driverScore == null || driverScore.getScore() == null || driverOrderLimit == 0 || driverScore.getScore().compareTo(BigDecimal.valueOf(driverOrderLimit)) < 0) {
            throw new BusinessPlatfromException(ErrorCodeEnum.DRIVER_STATUS_ERROR, "当前司机分数过低，不能继续接单");
        }
        return driverVo;
    }

    /**
     * 校验车辆状态
     * @param param
     * @return
     */
    private RTruckVo checkTruck(OrderCirculateTakingQueryParam param) {
        RTruckVo truckNo = remoteFleetService.findTruckByTruckNo(param.getTruckNo());
        if (truckNo == null || !Objects.equals(truckNo.getStatus(), 0)) {
            throw new BusinessPlatfromException(ErrorCodeEnum.TRUCK_STATUS_ERROR, "当前车辆非正常状态，不能接单！");
        }
        //核定载重
        if (truckNo.getLegalLoad() == null || BigDecimal.ZERO.compareTo(truckNo.getLegalLoad()) == 0) {
            throw new BusinessPlatfromException(ErrorCodeEnum.RESOURCE_NOT_FOUND, "车辆核定载重不能为空！");
        }

        return truckNo;
    }

    /**
     * 校验车辆是否已有未完成运单(不可继续接单状态：已接单、已入场、已装货、已离场、审核驳回)
     * @param param
     */
    private void checkTruckUnfinished(OrderCirculateTakingQueryParam param, KwtLogisticsOrder logOrder) {
        // 原矿运输
        List<KwtWaybillOrder> wbOrderByTruckNo;
        if (Objects.equals(1, logOrder.getOrderType())) {
            wbOrderByTruckNo = waybillOrderRepository.findWbOrderByTruckNoAndStatus(param.getTruckNo(), RAW_ORE_FORBIDDEN_STATUSES);
        } else {
            // 正常流程
            wbOrderByTruckNo = waybillOrderRepository.findWbOrderByTruckNoAndStatus(param.getTruckNo(), FORBIDDEN_STATUSES);
        }
        if (CollectionUtils.isNotEmpty(wbOrderByTruckNo)) {
            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_NOT_UNFINISHED, "当前车辆有未完成的状态，不可继续接单");
        }
    }


    /**
     * 计算当前车辆任务量：
     * 若有皮重：任务量 = 核定载重 - 皮重
     * 若无皮重：任务量 = 核定载重 × 80%
     * <p>
     * 1.当订单余量>=车辆的（法定载重-首次皮重）且<（法定载重-首次皮重 + 2）时，接取的任务量为车辆的（法定载重-首次皮重）；
     * 2.订单余量<车辆的（法定载重-首次皮重）时，该车辆无法接单；
     * 3.当订单余量>= (法定载重-首次皮重 + 2)时，接取的任务量为 (法定载重-首次皮重 + 2)
     *
     * @param truckNo
     */
    private BigDecimal queryCurTruckLoadVolume(RTruckVo truckNo, OrderDetailVo tradeOrder, KwtLogisticsOrder logOrder) {
        log.info("开始计算当前车辆任务量！");
        //核定载重
        BigDecimal actualWeight = truckNo.getLegalLoad();
        //首次皮重
        BigDecimal tareWeight = truckNo.getTareWeight();
        //任务量
        BigDecimal loadVolume;
        if (tareWeight != null) {
            // 有皮重：任务量 = 核定载重 - 皮重
            loadVolume = actualWeight.subtract(tareWeight);
            log.info("车辆有皮重，皮重：{}， 任务量:{}", tareWeight, loadVolume);

        } else {
            // 无皮重：任务量 = 核定载重 × 80%
            loadVolume = actualWeight.multiply(EIGHTY_PERCENT);
            log.info("车辆无皮重，按80%核定载重计算，车辆任务量：{}", loadVolume);
        }

        //订单余量:区分正常流程和原矿运输
        BigDecimal remainingAmount = getRawOreSupAmount(logOrder);

        // 最终接取的任务量
        BigDecimal taskAmount;
        BigDecimal loadVolumePlus2 = loadVolume.add(TWO_TONS);
        if (remainingAmount.compareTo(loadVolume) < 0) {
            // 规则2：订单余量 < 任务量 → 无法接单
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, String.format("订单余量不足，无法接单, 订单余量:%s, 车辆任务量:%s", remainingAmount, loadVolume));
        } else if (remainingAmount.compareTo(loadVolumePlus2) >= 0) {
            // 规则3：订单余量 >= 任务量+2 → 接取任务量+2
            taskAmount = loadVolumePlus2;
            log.info("订单余量充足，按(任务量+2吨)接单,最终任务量: {}", taskAmount);
        } else {
            // 规则1：订单余量 >= 任务量 且 < 任务量+2 → 接取任务量
            taskAmount = loadVolume;
            log.info("订单余量适中，按基础任务量接单，最终任务量: {}", taskAmount);
        }
        log.info("计算当前车辆任务量结束，最终任务量：{}", taskAmount);
        return taskAmount;
    }

    @NotNull
    private BigDecimal getRemainingAmount(OrderDetailVo tradeOrder) {
        //订单分配总量
        BigDecimal entrustAmount = tradeOrder.getAmount();
        if (entrustAmount == null ||  entrustAmount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "订单分配总量必须大于0！");
        }
        //物流订单
        List<KwtLogisticsOrder> logisticsOrders = logisticsOrderRepository.queryByTradeOrderId(tradeOrder.getId());
        if (CollectionUtils.isEmpty(logisticsOrders)) {
            throw new BusinessPlatfromException(ErrorCodeEnum.LOGISTICS_ORDER_NOT_FOUND, "物流订单数据不存在！");
        }

        BigDecimal[] totals = logisticsOrders.stream()
                .reduce(
                        new BigDecimal[]{BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO}, // [totalLoad, totalEntrust, totalUnload]
                        (acc, order) -> {
                            // 累计已接单量
                            acc[0] = acc[0].add(Optional.ofNullable(order.getEntrustAmount()).orElse(BigDecimal.ZERO));
                            // 累计装货量
                            acc[1] = acc[1].add(Optional.ofNullable(order.getTotalLoadAmount()).orElse(BigDecimal.ZERO));
                            // 累计卸货量
                            acc[2] = acc[2].add(Optional.ofNullable(order.getTotalUnloadAmount()).orElse(BigDecimal.ZERO));
                            return acc;
                        },
                        (a, b) -> new BigDecimal[]{a[0].add(b[0]), a[1].add(b[1]), a[2].add(b[2])}
                );
        // 累计装货量/卸货量
        BigDecimal totalLoadAmount = tradeOrder.getChargeType() == 1 ? totals[1] : totals[2];

        // 已接单量
        BigDecimal totalEntrustAmount = totals[0];

        //订单余量 = 订单总量-所有物流订单(已接单量+累计装货量/累计卸货量)
        BigDecimal remainingAmount = entrustAmount.subtract(totalEntrustAmount)
                .subtract(totalLoadAmount)
                .setScale(6, RoundingMode.HALF_UP);
        log.info("订单余量 = 订单总量:{} - 累计装/卸货量:{} - 已接单量:{}", entrustAmount, totalLoadAmount, totalEntrustAmount);

        // 校验余量是否为负
        if (remainingAmount.compareTo(BigDecimal.ZERO) < 0) {
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR,
                    "订单已分配总量（已接单量+累计装货/卸货量）超过订单总量！");
        }
        return remainingAmount;
    }


    /**
     * 计算贸易订单余量
     * 逻辑：贸易订单总量 - (所有关联物流订单下，非取消/完成状态的子运单委托量 + 对应计费模式的磅单量)
     *
     * @return 订单余量，保留两位小数
     */
    private BigDecimal getRawOreSupAmount(KwtLogisticsOrder order) {
        log.debug("开始计算物流订单余量，param: {}", JSON.toJSONString(order));

        // 1. 获取贸易订单总货物量
        BigDecimal tradeAmount = order.getAmount();
        log.debug("物流订单[{}]总货物量: {}", order.getId(), tradeAmount);

        Long logOrderId = order.getId();
        // 获取当前物流订单下的所有子运单
        List<KwtWaybillOrderSubtask> waybillOrderSubtasks = waybillOrderSubtaskRepository.queryByLogId(logOrderId);

        if (CollectionUtils.isEmpty(waybillOrderSubtasks)) {
            BigDecimal tradeTotalAmount = tradeAmount.compareTo(BigDecimal.ZERO) <= 0 ? BigDecimal.ZERO : tradeAmount;
            BigDecimal bigDecimal = tradeTotalAmount.setScale(2, RoundingMode.HALF_UP);
            log.debug("物流订单[{}]无子运单，跳过, 最终余量: {}",logOrderId, bigDecimal);
            return bigDecimal;
        }

        // 定义需要剔除的状态：已取消、已完成、空载（这些状态下的运单不再占用当前可接单的余量，或者其量已结算）
        // 注意：具体业务逻辑中，通常“进行中”的运单会占用余量。这里根据原代码逻辑，剔除CANCELLED和COMPLETED。
        //      空载待离场，实际装货量接近0,所以也要剔除
        List<Integer> excludeStatusList = Arrays.asList(CarWaybillV1Enum.CANCELLED.getCode(), CarWaybillV1Enum.COMPLETED.getCode()
                , CarWaybillV1Enum.EMPTY_WAIT_LEAVE.getCode());

        // 4. 计算子运单委托量合计（仅统计未取消/未完成/空载的有效子运单）
        BigDecimal entrustAmount = waybillOrderSubtasks.stream()
                .filter(Objects::nonNull)
                .filter(subtask -> !excludeStatusList.contains(subtask.getStatus()))
                .map(KwtWaybillOrderSubtask::getEntrustAmount)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        log.debug("物流订单[{}]子运单委托量合计: {}", logOrderId, entrustAmount);

        // 5. 计算运单已完成的合计量
        BigDecimal totalLoadAmount = order.getTotalLoadAmount();
        totalLoadAmount = totalLoadAmount == null || totalLoadAmount.compareTo(BigDecimal.ZERO) <= 0 ? BigDecimal.ZERO : totalLoadAmount;
        log.debug("物流订单[{}]有完成的运单实际装货量合计: {}", logOrderId, totalLoadAmount);

        // 累加到总占用量
        BigDecimal usedAmount = entrustAmount.add(totalLoadAmount);

        log.debug("物流订单[{}]总占用量: {}", logOrderId, usedAmount);

        // 6. 计算余量：贸易订单总量 - 已占用量
        // 如果计算结果小于等于0，则余量为0，避免负数
        BigDecimal surplus = tradeAmount.subtract(usedAmount);
        BigDecimal finalSurplus = surplus.compareTo(BigDecimal.ZERO) <= 0 ? BigDecimal.ZERO : surplus;

        // 保留两位小数，四舍五入
        BigDecimal result = finalSurplus.setScale(2, RoundingMode.HALF_UP);
        log.debug("物流订单[{}]最终余量: {}", logOrderId, result);

        return result;
    }

    /**
     * 创建物流运单
     *
     * @param param
     */
    private KwtWaybillOrder createWaybillOrder(OrderCirculateTakingQueryParam param, RDriverVo driver, RTruckVo truckNo, KwtLogisticsOrder logOrder) {
        log.info("生成物流运单，入参参数：{}", JSON.toJSONString(param));
        KwtWaybillOrder waybillOrder = new KwtWaybillOrder();
        waybillOrder.setEntId(param.getEntId());
        waybillOrder.setLOrderId(param.getLogOrderId());
        waybillOrder.setWOrderNo("W" + System.currentTimeMillis());
        waybillOrder.setType(1);
        waybillOrder.setTruckId(truckNo.getId());
        waybillOrder.setTruckNo(param.getTruckNo());
        waybillOrder.setDriverId(param.getDriverId());
        waybillOrder.setDriverName(driver.getName());
        waybillOrder.setDriverPhone(driver.getPhone());
        waybillOrder.setDriverIdcard(driver.getIdcard());
        waybillOrder.setStatus(CarWaybillV1Enum.PENDING_VEHICLE.getCode());
        waybillOrder.setTaskStartTime(new Date());
        waybillOrder.setCreateTime(new Date());
        waybillOrder.setCreateBy(param.getDriverId());
        waybillOrder.setUpdateBy(param.getDriverId());
        waybillOrder.setDispatchWay(logOrder.getDispatchWay());
        waybillOrderRepository.save(waybillOrder);
        log.info("创建物流运单成功，运单ID：{}", waybillOrder.getId());

        return waybillOrder;

    }

    /**
     * 创建物流子运单
     *
     * @param param
     */
    private KwtWaybillOrderSubtask createWaybillOrderSubtask(OrderCirculateTakingQueryParam param, KwtWaybillOrder waybillOrder,
                                                             BigDecimal truckLoadVolume) {
        log.info("创建物流子运单，入参参数：{}", JSON.toJSONString(param));
        KwtWaybillOrderSubtask subtask = new KwtWaybillOrderSubtask();

        subtask.setEntId(param.getEntId());
        subtask.setLOrderId(param.getLogOrderId());
        subtask.setWOrderId(waybillOrder.getId());
        subtask.setWOrderNo(waybillOrder.getWOrderNo());
        subtask.setUnit("吨"); //TODO DONGLANG

        subtask.setEntrustAmount(truckLoadVolume);
        subtask.setStatus(CarWaybillV1Enum.PENDING_VEHICLE.getCode());
        subtask.setCreateBy(param.getDriverId());
        subtask.setUpdateBy(param.getDriverId());
        waybillOrderSubtaskRepository.save(subtask);
        log.info("创建物流子运单成功，子运单ID：{}", subtask.getId());

        return subtask;

    }

    /**
     * 创建物流运单地址
     *
     * @param param
     */
    private List<KwtWaybillOrderAddress> createWaybillOrderAddress(OrderCirculateTakingQueryParam param, KwtWaybillOrder waybillOrder,
                                                                   KwtWaybillOrderSubtask waybillOrderSubtask) {
        log.info("创建物流运单地址，入参参数，logOrderId：{}", param.getLogOrderId());
        //地址
        Map<String, KwtLogisticsOrderAddress> logOrderIdAndAddressMap = getKwtLogisticsOrderAddressMap(Lists.newArrayList(param.getLogOrderId()));
        List<KwtWaybillOrderAddress> createdAddresses = new ArrayList<>();

        //装货地址
        KwtLogisticsOrderAddress shipmentSource = logOrderIdAndAddressMap.getOrDefault(
                param.getLogOrderId() + "-" + AddressTypeEnum.SHIPMENT.getCode(), new KwtLogisticsOrderAddress());
        KwtWaybillOrderAddress shipmentAddress = createAddress(waybillOrder, waybillOrderSubtask, shipmentSource, AddressTypeEnum.SHIPMENT);
        createdAddresses.add(shipmentAddress);
        log.info("创建物流运单装货地址成功，运单地址ID：{}", shipmentAddress.getId());

        //卸货地址
        KwtLogisticsOrderAddress takeSource = logOrderIdAndAddressMap.getOrDefault(
                param.getLogOrderId() + "-" + AddressTypeEnum.TAKE.getCode(), new KwtLogisticsOrderAddress());
        KwtWaybillOrderAddress takeAddress = createAddress(waybillOrder, waybillOrderSubtask, takeSource, AddressTypeEnum.TAKE);
        createdAddresses.add(takeAddress);
        log.info("创建物流运单卸货地址成功，运单地址ID：{}", takeAddress.getId());

        log.info("创建物流运单地址成功，创建{}个运单地址", createdAddresses.size());
        return createdAddresses;
    }

    /**
     * 保存运单物流地址
     * @param waybillOrder
     * @param subtask
     * @param orderAddress
     */
    private KwtWaybillOrderAddress createAddress(KwtWaybillOrder waybillOrder, KwtWaybillOrderSubtask subtask,
                                                 KwtLogisticsOrderAddress orderAddress, AddressTypeEnum typeEnum) {
        KwtWaybillOrderAddress address = new KwtWaybillOrderAddress();
        address.setWOrderId(waybillOrder.getId());
        address.setWSubtaskId(subtask.getId());
        address.setLAddressId(orderAddress.getId());
        address.setAddressType(typeEnum.getCode());
        address.setName(orderAddress.getName());
        address.setType(orderAddress.getType());
        address.setContacts(orderAddress.getContacts());
        address.setPhone(orderAddress.getPhone());
        address.setCityCode(orderAddress.getCityCode());
        address.setCityName(orderAddress.getCityName());
        address.setDetailAddress(orderAddress.getDetailAddress());
        address.setLat(orderAddress.getLat());
        address.setLng(orderAddress.getLng());
        address.setFence(orderAddress.getFence());
        address.setEntryType(orderAddress.getEntryType());
        address.setPlanTime(waybillOrder.getTaskStartTime());
        address.setSort(Global.NUMERICAL_ONE);
        address.setEntrustAmount(subtask.getEntrustAmount());
        address.setCreateBy(waybillOrder.getDriverId());
        address.setUpdateBy(waybillOrder.getDriverId());
        waybillOrderAddressRepository.save(address);
        return address;
    }

    /**
     * 生成车辆运单-装卸货信息
     *
     * @param logOrder
     * @param waybillOrder
     */
    private void createWaybillOrderTicket(KwtLogisticsOrder logOrder, KwtWaybillOrder waybillOrder, KwtWaybillOrderSubtask waybillOrderSubtask,
                                          List<KwtWaybillOrderAddress> waybillOrderAddresses) {
        log.info("创建车辆运单-装卸货信息，运单id：{}", waybillOrder.getId());

        //装货地址
        KwtWaybillOrderAddress shipmentAddress = getWaybillOrderAddress(waybillOrderAddresses, AddressTypeEnum.SHIPMENT);
        createTicket(waybillOrder, waybillOrderSubtask, shipmentAddress, logOrder);
        log.info("创建车辆运单-装卸货信息成功！");

        //卸货地址
        KwtWaybillOrderAddress takeAddress = getWaybillOrderAddress(waybillOrderAddresses, AddressTypeEnum.TAKE);
        createTicket(waybillOrder, waybillOrderSubtask, takeAddress, logOrder);
        log.info("创建车辆运单-装卸货信息成功！");

    }

    /**
     * 运单地址(装货、卸货地址)
     *
     * @param waybillOrderAddresses
     * @param typeEnum
     * @return
     */
    private KwtWaybillOrderAddress getWaybillOrderAddress(List<KwtWaybillOrderAddress> waybillOrderAddresses, AddressTypeEnum typeEnum) {
        return waybillOrderAddresses.stream()
                .filter(address -> address != null && address.getAddressType() != null && typeEnum.getCode() == address.getAddressType())
                .findFirst()
                .orElseThrow(() -> new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_ADDRESS_NOT_FOUND, "未找到装货地址数据！"));
    }

    /**
     * 保存车辆运单-装卸货信息
     *
     * @param waybillOrder
     * @param waybillOrderSubtask
     * @param shipmentAddress
     */
    private void createTicket(KwtWaybillOrder waybillOrder, KwtWaybillOrderSubtask waybillOrderSubtask,
                              KwtWaybillOrderAddress shipmentAddress, KwtLogisticsOrder logOrder) {
        KwtWaybillOrderTicket ticket = new KwtWaybillOrderTicket();
        ticket.setWOrderId(waybillOrder.getId());
        ticket.setWSubtaskId(waybillOrderSubtask.getId());
        ticket.setWAddressId(shipmentAddress.getId());
        ticket.setType(shipmentAddress.getAddressType());
        ticket.setUnit(logOrder.getUnit());
        ticket.setAmount(BigDecimal.ZERO);
        ticket.setCreateBy(waybillOrder.getDriverId());
        waybillOrderTicketRepository.save(ticket);
    }

    /**
     * 回写贸易订单数据
     * @param tradeOrder
     */
    private void updateTradeOrder(OrderDetailVo tradeOrder, BigDecimal truckLoadVolume) {
        log.info("更新上游贸易订单运输量数据，tradeOrderId：{}", tradeOrder.getId());
        // 计算当前车辆运输量
        BigDecimal totalLoadVolume = Optional.ofNullable(tradeOrder.getActualAmount())
                .map(entrust -> entrust.add(truckLoadVolume))
                .orElse(truckLoadVolume);

        UpdateActualAmountParam tradeParam = new UpdateActualAmountParam();
        tradeParam.setTOrderId(tradeOrder.getId());
        tradeParam.setActualLoadAmount(totalLoadVolume);
        tradeOrderInfoService.updateOrderActualAmount(tradeParam);
        log.info("更新上游贸易订单运输量成功, 贸易订单ID：{}", tradeOrder.getId());
    }


    /**
     * 回写物流订单数据
     * @param logOrder
     */
    private void updateLogOrder(KwtLogisticsOrder logOrder, BigDecimal truckLoadVolume) {
        log.info("更新上游物流订单运输量数据，logOrderId：{}", logOrder);
        // 计算当前车辆总运输量
        if (logOrder.getEntrustAmount() == null || BigDecimal.ZERO.compareTo(logOrder.getEntrustAmount()) == 0) {
            logOrder.setEntrustAmount(truckLoadVolume);
        } else {
            logOrder.setEntrustAmount(logOrder.getEntrustAmount().add(truckLoadVolume));
        }
        logisticsOrderRepository.updateById(logOrder);
        log.info("更新上游物流订单运输量成功, 物流订单ID：{}", logOrder.getId());
    }

    /**
     * 装卸货地址
     * @param logOrderIdList
     * @return
     */
    private Map<String, KwtLogisticsOrderAddress> getKwtLogisticsOrderAddressMap(List<Long> logOrderIdList) {
        List<KwtLogisticsOrderAddress> logOrderAddressList = logisticsOrderAddressRepository.queryByLogOrderIds(logOrderIdList);
        if (CollectionUtils.isEmpty(logOrderAddressList)) {
            log.info("物流订单无装卸货地址信息，logOrderIdList:{}", JSON.toJSONString(logOrderIdList));
            throw new BusinessPlatfromException(ErrorCodeEnum.LOGISTICS_ORDER_NOT_ADDRESS, "物流订单无装卸货地址信息");
        }
        return logOrderAddressList.stream().collect(Collectors
                .toMap(address -> address.getLOrderId() + "-" + address.getAddressType(),
                        Function.identity(), (x, y) -> x));
    }

    @Override
    protected String getProcessName() {
        return "接单";
    }

    @Override
    protected void getStatus(KwtWaybillOrder waybillOrder) {

    }

    @Override
    protected String getRemark(OrderCirculateTakingQueryParam param, KwtWaybillOrder waybillOrder) {
        KwtWaybillOrder actualOrder = BusinessContext.get("createdWaybillOrder");
        KwtWaybillOrderSubtask subtask = getWaybillSubtask(actualOrder.getId());
        String entrustAmount = Objects.isNull(subtask.getEntrustAmount()) ? "0.00" : subtask.getEntrustAmount().setScale(2, RoundingMode.HALF_UP).toPlainString();
        return  "司机[" + actualOrder.getDriverName() + "]接单成功，预计任务量[" + entrustAmount + "吨]";
    }

    // 接单需要单独创建接单轨迹数据
    protected OrderTakingResp afterProcess(OrderCirculateTakingQueryParam param, KwtWaybillOrder waybillOrder) {
        KwtWaybillOrder actualOrder = BusinessContext.get("createdWaybillOrder");
        createNodeTrace(param, actualOrder);
        //接单需要返回运单id
        OrderTakingResp orderTakingResp = new OrderTakingResp();
        orderTakingResp.setWaybillOrderId(actualOrder.getId());
        return orderTakingResp;

    }

    // 7. 绑定车辆
    private void driverBindTruck(KwtWaybillOrder waybillOrder) {
        try {
            remoteFleetService.driverBindTruck(waybillOrder.getDriverId(), waybillOrder.getTruckId(), waybillOrder.getEntId());
        } catch (Exception e) {
            log.error("接单绑定车辆失败，此车辆已与此司机绑定!", e);
        }
    }


}
