package com.clx.performance.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.clx.order.enums.InvoicingCompanyEnum;
import com.clx.order.enums.UpdateEnum;
import com.clx.order.enums.VehicleUsageEnum;
import com.clx.order.feign.OrderFeign;
import com.clx.order.param.feign.OrderCancelReasonParam;
import com.clx.order.param.feign.RollbackOrderWeightParam;
import com.clx.order.vo.feign.FeignOrderVO;
import com.clx.order.vo.pc.owner.OwnerQuotationDetailVO;
import com.clx.performance.component.GoodsOrderTruckRecordComponent;
import com.clx.performance.component.OrderCancelComponent;
import com.clx.performance.component.OrderGoodsStatusLazyComponent;
import com.clx.performance.constant.RabbitKeyConstants;
import com.clx.performance.dao.*;
import com.clx.performance.dto.OrderGoodsBindTruckNumDTO;
import com.clx.performance.dto.OrderGoodsCancelDTO;
import com.clx.performance.enums.*;
import com.clx.performance.enums.settle.SettlementWayEnum;
import com.clx.performance.extranal.order.QuotationService;
import com.clx.performance.extranal.user.DriverService;
import com.clx.performance.model.*;
import com.clx.performance.param.app.AppGoodsOrderSearchParam;
import com.clx.performance.param.app.OrderGoodsListPageParam;
import com.clx.performance.param.feign.CancelOrderGoodsParam;
import com.clx.performance.param.feign.DistributionTruckParam;
import com.clx.performance.param.pc.*;
import com.clx.performance.service.IntegralMqService;
import com.clx.performance.service.OrderChildLogService;
import com.clx.performance.service.OrderGoodsLogService;
import com.clx.performance.service.OrderGoodsService;
import com.clx.performance.service.child.OrderChildPostService;
import com.clx.performance.struct.OrderGoodsStruct;
import com.clx.performance.vo.app.OrderGoodsAPPVO;
import com.clx.performance.vo.feign.FreightEstimateVO;
import com.clx.performance.vo.feign.OrderGoodsFeignVO;
import com.clx.performance.vo.mq.OrderTruckBindCancelParam;
import com.clx.performance.vo.pc.DriverFreightPriceVO;
import com.clx.performance.vo.pc.OrderGoodsEditVO;
import com.clx.performance.vo.pc.OrderGoodsPendingVO;
import com.clx.performance.vo.pc.OrderGoodsVO;
import com.clx.user.enums.driver.DriverInfoEnum;
import com.clx.user.feign.UserClxFeign;
import com.msl.common.base.Optional;
import com.msl.common.enums.ResultCodeEnum;
import com.msl.common.exception.ServiceSystemException;
import com.msl.common.result.Result;
import com.msl.common.utils.DateUtils;
import com.msl.user.data.UserSessionData;
import com.msl.user.utils.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * @author kavin
 * Date 2023-09-17
 * Time 16:45
 */
@Service
@Slf4j
public class OrderGoodsServiceImpl implements OrderGoodsService, InitializingBean {

    @Autowired
    private OrderGoodsDao orderGoodsDao;

    @Autowired
    private OrderGoodsStruct orderGoodsStruct;

    @Autowired
    private OrderFeign orderFeign;

    @Autowired
    private OrderGoodsTruckBindDao orderGoodsTruckBindDao;

    @Autowired
    private OrderGoodsDriverTruckDao orderGoodsDriverTruckDao;
    @Autowired
    private OrderGoodsLogService orderGoodsLogService;

    @Autowired
    private UserClxFeign userClxFeign;

    @Autowired
    private OrderChildDao orderChildDao;
    @Autowired
    private GoodsOrderTruckRecordComponent goodsOrderTruckRecordComponent;

    @Autowired
    private OrderGoodsStatusLazyComponent orderGoodsStatusLazyComponent;
    @Autowired
    private DriverService driverService;
    @Autowired
    private OrderCancelComponent orderCancelComponent;
    @Autowired
    private IntegralMqService integralMqService;
    @Autowired
    private OrderChildLogService orderChildLogService;
    @Autowired
    private OrderChildPostService orderChildPostService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private  QuotationService quotationService;

    @Autowired
    private OrderGoodsFleetOpenTruckDao orderGoodsFleetOpenTruckDao;



    private static Map<Integer, Consumer<OrderGoodsCancelDTO>> orderGoodsCancelMap = new HashMap<>();

    @Override
    public OrderGoodsVO getOrderGoodsInfoByOrderGoodsNoForPC(String orderGoodsNo) {

        OrderGoodsVO orderGoodsVO = orderGoodsDao.getOrderGoodsInfoByOrderGoodsNoForPC(orderGoodsNo).map(orderGoodsStruct::convert).get();
        List<String> truckList;

        if(Objects.equals(orderGoodsVO.getPendingOrderWay(),PendingOrderWayStatusEnum.Status.FLEET_DX.getCode())){
            truckList = orderGoodsTruckBindDao.
                    listByField(OrderGoodsTruckBind::getOrderGoodsNo, orderGoodsNo)
                    .stream().map(OrderGoodsTruckBind::getTruckNo).collect(Collectors.toList());
        }else{
            truckList = orderGoodsTruckBindDao.selectListByOrderGoodsNo(orderGoodsNo).stream().map(OrderGoodsTruckBind::getTruckNo).collect(Collectors.toList());
        }

        String orderNo = orderGoodsVO.getOrderNo();
        orderGoodsVO.setTruckList(truckList);
        FeignOrderVO orderInfoFeign = orderFeign.getOrderInfoFeign(orderNo);
        orderGoodsVO.setReveiveAddressAll(orderInfoFeign.getReveiveAddressAll());
        orderGoodsVO.setSendAddressAll(orderInfoFeign.getSendAddressAll());
        orderGoodsVO.setDispatchedOrders(truckList.size());
        return orderGoodsVO;
    }

    @Override
    public OrderGoodsVO getOrderGoodsInfoByOrderGoodsNoForAPP(String orderGoodsNo) {
        OrderGoodsVO orderGoodsVO = orderGoodsDao.getOrderGoodsInfoByOrderGoodsNoForAPP(orderGoodsNo).map(orderGoodsStruct::convert).get();
        String orderNo = orderGoodsVO.getOrderNo();
        FeignOrderVO orderInfoFeign = orderFeign.getOrderInfoFeign(orderNo);
        orderGoodsVO.setReveiveAddressAll(orderInfoFeign.getReveiveAddressAll());
        orderGoodsVO.setSendAddressAll(orderInfoFeign.getSendAddressAll());
        orderGoodsVO.setUnloadBeginTime(orderInfoFeign.getUnloadBeginTime());
        orderGoodsVO.setUnloadEndTime(orderInfoFeign.getUnloadEndTime());
        orderGoodsVO.setLoadBeginTime(orderInfoFeign.getLoadBeginTime());
        orderGoodsVO.setLoadEndTime(orderInfoFeign.getLoadEndTime());
        orderGoodsVO.setResidueTransportWeight(BigDecimal.ZERO.compareTo(orderGoodsVO.getResidueTransportWeight()) > 0 ? BigDecimal.ZERO : orderGoodsVO.getResidueTransportWeight());

        //获取订单配置的违约金方案
        OwnerQuotationDetailVO quotationDetailVO = quotationService.getQuotationByOrderNo(orderNo).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);
        if(Objects.isNull(quotationDetailVO.getLiquidatedDamagesPlanId())){
            throw new ServiceSystemException(PerformanceResultEnum.DATA_NOT_FIND);
        }
        //货源详情页面 是否显示弹窗和显示平台服务费率
        /**  订单结算方式为“卸车净重（减货损）”且平台运费报价为“未税”时 显示平台服务费率和弹窗提示司机平台服务费率**/
        if (Objects.equals(orderGoodsVO.getSettlementWay(),
                SettlementWayEnum.WayType.UNLOAD_LOSS.getCode())
                && Objects.equals(quotationDetailVO.getPlatformFreightQuotationTaxType(),
                InvoicingCompanyEnum.TaxType.TAX_EXCLUDED.getCode())) {
            orderGoodsVO.setGoodsOrderDetailShow(1);
        }

        return orderGoodsVO;
    }

    @Override
    public IPage<OrderGoodsVO> pageOrderGoodsList(PageOrderGoodsListParam param) {

        IPage<OrderGoodsVO> page = orderGoodsDao.pageOrderGoodsList(param);
        if(CollectionUtils.isNotEmpty(page.getRecords())){
            List<String> fleetNoList = page.getRecords().stream()
                    .filter(item->Objects.equals(item.getPendingOrderWay(),PendingOrderWayStatusEnum.Status.FLEET_DX.getCode()))
                    .map(OrderGoodsVO :: getOrderGoodsNo).collect(Collectors.toList());
            
            if(CollectionUtils.isNotEmpty(fleetNoList)){
                List<OrderGoodsBindTruckNumDTO> bindTruckNumList = orderGoodsTruckBindDao.queryOrderGoodsTruckNum(fleetNoList);
                Map<String, Integer> map = bindTruckNumList.stream().collect(
                        Collectors.toMap(OrderGoodsBindTruckNumDTO::getOrderGoodsNo,OrderGoodsBindTruckNumDTO :: getTruckNum));
                page.getRecords().forEach(item->item.setDispatchedOrders(map.get(item.getOrderGoodsNo())));
            }
        }
        return page;
    }

    @Override
    public void updateOrderGoodsReduceWeightAndStatusAmountLoad(OrderGoods orderGoods, BigDecimal orderChildWeight, Integer orderGoodsStatus) {
        if (orderGoods.getOrderGoodsStatus().equals(OrderGoodsStatusEnum.Status.CANCEL.getCode())
            || orderGoods.getOrderGoodsStatus().equals(OrderGoodsStatusEnum.Status.COMPLETED.getCode())
            || orderGoods.getOrderGoodsStatus().equals(OrderGoodsStatusEnum.Status.SUCCESS.getCode())
        ) {
            if (orderChildWeight.compareTo(BigDecimal.ZERO) < 0) {
                orderChildWeight = orderChildWeight.negate();
            }
            //当前订单已经取消或完结
            orderCancelComponent.backFillTonnage(orderGoods, orderChildWeight);
        } else {

            orderGoodsDao.updateOrderGoodsReduceWeightAndStatus(orderGoods.getId(), orderChildWeight, orderGoodsStatus);

       }

    }

    @Override
    public void updateOrderGoodsReduceWeightAndStatus(OrderGoods orderGoods, OrderChild orderChild, Integer orderGoodsStatus) {
        orderGoodsDao.updateOrderGoodsReduceWeightAndStatus(orderGoods.getId(), orderChild.getWeight(), orderGoodsStatus);
        //货单没有辆，并且货单用车非自有车
        if (orderGoods.getResidueTransportWeight().compareTo(orderChild.getWeight()) <= 0
                && !Objects.equals(orderGoods.getVehicleUsage(),VehicleUsageEnum.Status.OWN.getCode())) {
            //释放其他车辆
            goodsOrderTruckRecordComponent.releaseDriverAndTruckBind(orderGoods.getOrderGoodsNo(), orderChild.getTruckNo());
        }

    }

    @Override
    public IPage<OrderGoodsAPPVO> indexOrderGoodsList(OrderGoodsListPageParam orderGoodsListParam) {
        Long driverUserNo = orderGoodsListParam.getDriverUserNo();
        List<String> truckNoList = getOwnerOrDriverTruckNoList(driverUserNo);
        if (StringUtils.equals(orderGoodsListParam.getOrderGoodsType(), "1")) {
            //查询当前登录人能看到哪些车队公开单
            List<String> fleetOpenOrderGoodsNoList = getFleetOpenOrderGoodsNoList(truckNoList);
            log.info("当前登录用户编号:{} ,查询到车队公开单集合:{}",driverUserNo,fleetOpenOrderGoodsNoList);
            return orderGoodsDao.openOrderPageGoodsList(orderGoodsListParam,fleetOpenOrderGoodsNoList);
        } else {
            if (CollectionUtils.isEmpty(truckNoList)) {
                log.warn("用户编号:{},查询车主车辆和作为司机的车辆全未查询到数据", driverUserNo);
                return new Page<>();
            }
            //自有车辆的货单接单之后还可以再次看到
            List<String> orderGoodsNoList = orderGoodsTruckBindDao.selectListByTruckNo(
                    truckNoList);
            if (CollectionUtils.isEmpty(orderGoodsNoList)) {
                log.warn("用户编号:{},无专属单", driverUserNo);
                return new Page<>();
            }
            return orderGoodsDao.exclusiveOrderPageGoodsList(orderGoodsListParam, orderGoodsNoList);
        }
    }
    /*
     * @Author kavin
     * @Description 查询当前登录作为车主或者司机名下的所有车辆
     * @Param [driverUserNo]
     * @return
     **/
    private List<String> getOwnerOrDriverTruckNoList(Long driverUserNo) {
        List<String> truckNoList = new ArrayList<>();
        Optional<List<OrderGoodsDriverTruck>> truckList = orderGoodsDriverTruckDao.
                selectListByDriverUserNo(driverUserNo);
        //查询当前用户是否是车主
        Result<List<String>> ownTruckByUserNo = userClxFeign.getOwnTruckByUserNo(driverUserNo);
        log.info("通过用户编号:{} 查询本人车辆，查询结果:{}", driverUserNo, JSON.toJSONString(ownTruckByUserNo));
        if (Objects.equals(ownTruckByUserNo.getCode(), ResultCodeEnum.SUCCESS.getCode())) {
            if ((!truckList.isPresent() || CollectionUtils.isEmpty(truckList.get()))
                    && ownTruckByUserNo.getData().isEmpty()) {
                log.warn("用户编号:{},当前用户未绑定车辆", driverUserNo);
                return truckNoList;
            }
            truckNoList.addAll(ownTruckByUserNo.getData());//当前用户自己的车
            truckNoList.addAll(truckList.get().stream().map(OrderGoodsDriverTruck::getTruckNo).collect(Collectors.toList()));//当前用户被绑定为司机的车
        }
        return truckNoList;
    }

    /*
     * @Author kavin
     * @Description 获取当前登录者存在的车队公开单
     * @Param [loginUserTruckNoList]
     * @return
     **/
    private List<String> getFleetOpenOrderGoodsNoList(List<String> loginUserTruckNoList){
        if(CollectionUtils.isEmpty(loginUserTruckNoList)){
            return null;
        }
        //查询正在进行的车队公开单的车辆列表
        List<String> orderGoodsNoList = new ArrayList<>();
        List<OrderGoodsFleetOpenTruck> fleetOpenTruckList= orderGoodsDao.queryProcessFleetOpenTruckList();
        a:for (OrderGoodsFleetOpenTruck orderGoodsFleetOpenTruck : fleetOpenTruckList) {
            //可以看到车队公开单的车来那个列表
            List<String> truckNoList = JSON.parseArray(orderGoodsFleetOpenTruck.getTruckListJson(), String.class);
            for (String truckNo : loginUserTruckNoList) {
                if(truckNoList.contains(truckNo)){
                    orderGoodsNoList.add(orderGoodsFleetOpenTruck.getOrderGoodsNo());
                    continue a;
                }
            }
        }
        return orderGoodsNoList;
    }

    @Override
    public List<OrderGoodsFeignVO> getOrderGoodsListByOrderNo(String orderNo) {
        List<OrderGoods> list = orderGoodsDao.getOrderGoodsListByOrderNo(orderNo);
        return orderGoodsStruct.convertList(list);
    }

    @Override
    public List<OrderGoods> getOrderGoodsList(String orderNo, LocalDateTime lastArriveSendTime) {
        return orderGoodsDao.getOrderGoodsListByOrderNoAndLastArriveSendTime(orderNo, lastArriveSendTime);
    }

    @Override
    public String orderCancelStyle(String orderNo) {
        FeignOrderVO orderInfoFeign = orderFeign.getOrderInfoFeign(orderNo);
        Integer orderStatus = orderInfoFeign.getOrderStatus();

        switch (orderStatus) {
            case 0:
                //不算违约 弹窗1
                return "writeRemark";
            case 1:
                //不算违约 弹窗1
                return "writeRemark";
            case 2:
                //算违约，但是不会有吨数，弹窗2
                return "remarkHasAmount";
            case 3:
                //算违约，但是不会有吨数，弹窗2
                return "remarkHasAmount";
            case 4:
                //已取消状态，不会涉及弹窗
            case 5:
                //暂停的订单不会在列表中展示
            case 6:
                //拒绝承运，不会在列表中展示
            case 7:
                //挂单中 ，算违约，需要判断弹窗2还是3
                //约可取消吨数
                return "writeRemark";
            case 8: //运输中 ，算违约， 弹窗3
                return "selectType";
            case 9:  //已完成，不能取消
            case 10: //已失效,不会出现在订单列表
            case 11: //已挂单  算违约  弹窗 2
                return "remarkHasAmount";
            case 12: //已完结
            default:
                throw new RuntimeException();
        }
    }

    @Override
    public BigDecimal orderCancelResidueWeight(String orderNo, String optionType) {
        FeignOrderVO orderInfoFeign = orderFeign.getOrderInfoFeign(orderNo);
        List<OrderGoods> orderGoodsList = null;
        BigDecimal orderGoodsResidueWeight = BigDecimal.ZERO;
        String residueWeight = orderInfoFeign.getResidueWeight();
        BigDecimal ans = new BigDecimal(residueWeight);
        switch (optionType) {
            case "1":
                return ans;
            case "2":
                orderGoodsList  = orderGoodsDao.getOrderGoodsListByOrderNoAndStatus(orderNo);
                if (CollectionUtil.isNotEmpty(orderGoodsList)) {
                    orderGoodsResidueWeight = orderGoodsList.stream().map(OrderGoods::getResidueTransportWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
                }
                ans = orderGoodsResidueWeight.add(new BigDecimal(residueWeight));
                if (ans.compareTo(new BigDecimal("35")) <= 0) {
                    return BigDecimal.ZERO;
                } else {
                    return ans.subtract(new BigDecimal("35"));
                }
            case "3":
                List<OrderChild> orderChildList = orderChildDao.selectResidueWeight(orderNo, OrderChildEnum.Status.ARRIVE_SEND.getCode());
                BigDecimal childResidueWeight = BigDecimal.ZERO;
                if (CollectionUtils.isNotEmpty(orderChildList)) {
                    childResidueWeight = orderChildList.stream().map(OrderChild::getWeight).reduce(BigDecimal.ZERO, BigDecimal::add);

                }
                orderGoodsList = orderGoodsDao.getOrderGoodsListByOrderNoAndStatus(orderNo);
                if (CollectionUtil.isNotEmpty(orderGoodsList)) {
                    orderGoodsResidueWeight = orderGoodsList.stream().map(OrderGoods::getResidueTransportWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
                }
                ans = ans.add(orderGoodsResidueWeight).add(childResidueWeight);
                if (ans.compareTo(new BigDecimal("35")) <= 0) {
                    return BigDecimal.ZERO;
                } else {
                    return ans.subtract(new BigDecimal("35"));
                }
            default:throw new RuntimeException("参数错误");
        }

    }


    /**
     * 编辑货单提交
     *
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateEditOrderGoods(UpdateEditOrderGoodsParam param) {
        UserSessionData loginUserInfo = null;
        loginUserInfo  = TokenUtil.getLoginUserInfo();
        OrderGoodsEditParams orderGoodsParams = param.getOrderGoodsParams();
        OrderGoods oldOrderGoods = orderGoodsDao.getByOrderGoodsNo(orderGoodsParams.getOrderGoodsNo()).get();
        FeignOrderVO orderInfoFeign = orderFeign.getOrderInfoFeign(param.getOrderNo());
        if (orderGoodsParams.getExtractWeight().compareTo(oldOrderGoods.getAlreadyTransportWeight()) < 0) {
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前货单提取吨数不能小于货单已拉运吨数");
        }

        //考虑到借吨、恢复吨数的货单，逻辑判断实际的提取吨数
        BigDecimal realExtractWeight = oldOrderGoods.getResidueTransportWeight().compareTo(BigDecimal.ZERO) == 0?
                oldOrderGoods.getAlreadyTransportWeight():oldOrderGoods.getAlreadyTransportWeight().add(oldOrderGoods.getResidueTransportWeight());
        oldOrderGoods.setExtractWeight(realExtractWeight);
        //本次提取增加或者减少的吨数  =  本次提取的吨数 - 货单原实际提取吨数
        BigDecimal answer = orderGoodsParams.getExtractWeight().subtract(realExtractWeight);
        int flag = answer.compareTo(BigDecimal.ZERO);
        //归还吨数
        RollbackOrderWeightParam rollbackOrderWeightParam = new RollbackOrderWeightParam();
        rollbackOrderWeightParam.setOrderNo(param.getOrderNo());
        log.info("flag:{}",flag);
        if (flag > 0) {
            orderGoodsParams.setResidueTransportWeight(oldOrderGoods.getResidueTransportWeight().add(answer));
            //限制剩余吨数
            limitOrderGoodsResidueWeight(orderGoodsParams.getResidueTransportWeight());
            rollbackOrderWeightParam.setUpdateType(UpdateEnum.SUB.getCode());
            if (oldOrderGoods.getTruckDemand().equals(TruckDemandEnum.TruckType.PLATFORM_CAR.getCode())) {
                rollbackOrderWeightParam.setResidueWeight(answer);
                rollbackOrderWeightParam.setOwnResidueCarryWeight(BigDecimal.ZERO);
                rollbackOrderWeightParam.setPlatformResidueCarryWeight(answer);
            }else if (oldOrderGoods.getTruckDemand().equals(TruckDemandEnum.TruckType.PLATFORM_ANY_CAR.getCode())) {
                if (orderGoodsParams.getVehicleUsage().equals(VehicleUsageEnum.Status.OWN.getCode())) {
                    rollbackOrderWeightParam.setResidueWeight(answer);
                    rollbackOrderWeightParam.setOwnResidueCarryWeight(answer);
                    rollbackOrderWeightParam.setPlatformResidueCarryWeight(BigDecimal.ZERO);
                } else {
                    rollbackOrderWeightParam.setResidueWeight(answer);
                    rollbackOrderWeightParam.setOwnResidueCarryWeight(BigDecimal.ZERO);
                    rollbackOrderWeightParam.setPlatformResidueCarryWeight(answer);
                }

            }
            log.info("回填吨数：{}", JSONUtil.parse(rollbackOrderWeightParam));
            orderFeign.rollbackOrderWeight(rollbackOrderWeightParam);
        }else if (flag < 0 ){
            orderGoodsParams.setResidueTransportWeight(orderGoodsParams.getExtractWeight().subtract(oldOrderGoods.getAlreadyTransportWeight()));
            //限制剩余吨数
            limitOrderGoodsResidueWeight(orderGoodsParams.getResidueTransportWeight());
            rollbackOrderWeightParam.setUpdateType(UpdateEnum.ADD.getCode());
            if (oldOrderGoods.getTruckDemand().equals(TruckDemandEnum.TruckType.PLATFORM_CAR.getCode())) {
                rollbackOrderWeightParam.setResidueWeight(answer.negate());
                rollbackOrderWeightParam.setOwnResidueCarryWeight(BigDecimal.ZERO);
                rollbackOrderWeightParam.setPlatformResidueCarryWeight(answer.negate());
            }else if (oldOrderGoods.getTruckDemand().equals(TruckDemandEnum.TruckType.PLATFORM_ANY_CAR.getCode())) {
                rollbackOrderWeightParam.setResidueWeight(answer.negate());
                if (VehicleUsageEnum.Status.OWN.getCode().equals(oldOrderGoods.getVehicleUsage())) {
                    rollbackOrderWeightParam.setOwnResidueCarryWeight(answer.negate());
                    rollbackOrderWeightParam.setPlatformResidueCarryWeight(BigDecimal.ZERO);
                } else {
                    rollbackOrderWeightParam.setOwnResidueCarryWeight(BigDecimal.ZERO);
                    rollbackOrderWeightParam.setPlatformResidueCarryWeight(answer.negate());
                }
            }
            log.info("回填吨数：{}", JSONUtil.parse(rollbackOrderWeightParam));
            orderFeign.rollbackOrderWeight(rollbackOrderWeightParam);
        } else {
            //当编辑吨数等于0 的时候，不进行拦截
            orderGoodsParams.setResidueTransportWeight(oldOrderGoods.getResidueTransportWeight());
        }


        if (new BigDecimal(orderInfoFeign.getResidueWeight()).compareTo(orderGoodsParams.getExtractWeight().subtract(oldOrderGoods.getExtractWeight())) < 0) {
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前货单提取吨数已超订单可提取吨数");
        }

        String orderGoodsNo = orderGoodsParams.getOrderGoodsNo();
        List<OrderChild> orderChildList = orderChildDao.selectListByOrderGoodsNo(orderGoodsNo);
        boolean pendingOrderWayFlag = CollectionUtils.isNotEmpty(orderChildList);

        if (pendingOrderWayFlag) {
            Integer pendingOrderWay = oldOrderGoods.getPendingOrderWay();
            if (!pendingOrderWay.equals(orderGoodsParams.getPendingOrderWay())) {
                throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前货单不允许更改挂单方式");
            }
        }

        if (oldOrderGoods.getAlreadyTransportWeight().compareTo(orderGoodsParams.getExtractWeight()) > 0) {
            //修改后的货单提取吨数小于已拉运的吨数
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前货单提取吨数不应小于已经拉运的吨数");
        }

        if (orderChildList.size() > orderGoodsParams.getNeedTruckNum()) {
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "需要车辆数不能小于当前已经接单的运单数量");
        }

        List<OrderGoodsTruckBind> truckBindList = orderGoodsTruckBindDao.selectListByOrderGoodsNo(orderGoodsNo);
        List<OrderGoodsTruckBind> getChildList = null;
        if (CollectionUtils.isNotEmpty(truckBindList)) {
            List<OrderGoodsTruckBind> deleteList = truckBindList.stream().filter(i ->
                    !i.getStatus().equals(OrderGoodsTruckBindEnum.Status.GET.getCode()) &&
            !i.getStatus().equals(OrderGoodsTruckBindEnum.Status.SUCCESS.getCode())
            ).collect(Collectors.toList());
            //已接单的记录和完成的
            getChildList = truckBindList.stream().filter(i -> i.getStatus().equals(OrderGoodsTruckBindEnum.Status.GET.getCode())
                    || i.getStatus().equals(OrderGoodsTruckBindEnum.Status.SUCCESS.getCode())
                    )
                    .collect(Collectors.toList());

            if (CollectionUtils.isNotEmpty(deleteList)) {
                orderGoodsTruckBindDao.deleteByIds(deleteList.stream().map(OrderGoodsTruckBind::getId).collect(Collectors.toList()));
            }
            for (OrderGoodsTruckBind bind : deleteList) {
                goodsOrderTruckRecordComponent.deleteTruckRecord(orderGoodsNo, bind.getTruckNo());
            }

        }

        if (!oldOrderGoods.getPendingOrderWay().equals(orderGoodsParams.getPendingOrderWay())) {
            orderGoodsTruckBindDao.deleteByOrderGoods(orderGoodsNo);
            goodsOrderTruckRecordComponent.deleteTruckRecord(orderGoodsNo);
        }

        LocalDateTime now = LocalDateTime.now();
        List<String> truckList = orderGoodsParams.getTruckList();
        if (CollectionUtil.isNotEmpty(truckList)) {
            if (CollectionUtil.isNotEmpty(getChildList)) {
                for (OrderGoodsTruckBind bind : getChildList) {
                    if (OrderGoodsTruckBindEnum.Status.SUCCESS.getCode().equals(bind.getStatus()) && !truckList.contains(bind.getTruckNo())) {
                        throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前取消的车辆已经接单,车牌号为：" + bind.getTruckNo());
                    } else {
                        //已存在的记录不需要重新创建绑定记录
                        truckList.remove(bind.getTruckNo());
                    }
                }
            }
            if (CollectionUtils.isNotEmpty(truckList)) {
                orderGoodsTruckBindDao.saveBatchEntity(param.getOrderNo(), orderGoodsNo, truckList, now);
                goodsOrderTruckRecordComponent.saveTruckRecord(orderGoodsNo, truckList);
            }

        }

        orderGoodsStatusLazyComponent.deleteRedisRecordForLastOrderTime(orderGoodsNo);
        orderGoodsStatusLazyComponent.deleteRedisRecordForLastArriveSendTime(orderGoodsNo);

        orderGoodsStatusLazyComponent.expireProduceByLastOrderTime(DateUtils.parseDateTime(orderGoodsParams.getLastOrderTime(), "yyyy-MM-dd HH:mm:ss").get(), orderGoodsNo);
        orderGoodsStatusLazyComponent.expireProduceByLastArriveSendTime(DateUtils.parseDateTime(orderGoodsParams.getLastArriveSendTime(), "yyyy-MM-dd HH:mm:ss").get(), orderGoodsNo);

        orderGoodsParams.setUserNo(loginUserInfo.getUserNo());
        orderGoodsParams.setUserName(loginUserInfo.getUserName());
        orderGoodsDao.updateOrderGoods(orderGoodsParams);

        //日志提交

        orderGoodsLogService.saveLog(orderGoodsNo, loginUserInfo.getUserNo(), loginUserInfo.getUserName(), OrderGoodsLogsEnum.Type.EDIT.getName(), "");
    }

    /**
     * 限制货单更新剩余吨数不能小于35吨
     **/
    private void limitOrderGoodsResidueWeight(BigDecimal residueTransportWeight){
        if(residueTransportWeight.compareTo(BigDecimal.ZERO) != 0 &&  residueTransportWeight.compareTo(new BigDecimal("35")) < 0){
            throw new ServiceSystemException(PerformanceResultEnum.DATA_NOT_FIND,"当前货单剩余吨数不足35吨，无法挂单");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateOrderGoodsPrice(UpdateOrderGoodsPriceParam param) {
        OrderGoods orderGoods = orderGoodsDao.getEntityByKey(param.getId()).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);
        BigDecimal oldPendingOrderFreight = orderGoods.getPendingOrderFreight().divide(new BigDecimal("100"));
        orderGoodsDao.updatePendingOrderFreightById(param.getId(), param.getPendingOrderFreight());
        BigDecimal newPendingOrderFreight = param.getPendingOrderFreight().divide(new BigDecimal("100"));
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        //记录货单调价日志
        orderGoodsLogService.saveLog(orderGoods.getOrderGoodsNo(), loginUserInfo.getUserNo(), loginUserInfo.getUserName(),
                OrderGoodsLogsEnum.Type.ADJUST_PRICE.getName(), String.format("调价前%s元,调价后%s元", oldPendingOrderFreight, newPendingOrderFreight));
    }

    @Override
    public Boolean updateOrderGoodsStopFlag(String orderNo, Integer stopFlag) {
        return orderGoodsDao.updateStopFlagByOrderNo(orderNo, stopFlag);
    }

    @Override
    public String orderGoodsCancelStyle(String orderGoodsNo) {
        List<OrderChild> orderChildren = orderChildDao.selectListByOrderGoodsNo(orderGoodsNo);
        if (CollectionUtils.isNotEmpty(orderChildren)) {
            return "selectTruck";
        } else {
            return "onlyRemark";
        }
    }

    /**
     * 货单取消
     *
     * @param goodsCancelParam
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void orderGoodsCancel(OrderGoodsCancelParam goodsCancelParam) {
        String orderGoodsNo = goodsCancelParam.getOrderGoodsNo();
        OrderGoods orderGoods = orderGoodsDao.getByOrderGoodsNo(orderGoodsNo).orElseThrow(PerformanceResultEnum.HTTP_ERROR, "数据错误");
        List<String> childNoList = new LinkedList<>();
        Integer orderGoodsStatus = OrderGoodsStatusEnum.Status.CANCEL.getCode();

        //封装取消策略参数
        OrderGoodsCancelDTO build = OrderGoodsCancelDTO.builder().orderGoodsCancelParam(goodsCancelParam)
                .orderGoodsStatus(orderGoodsStatus).orderGoods(orderGoods)
                .childNoList(childNoList).build();
        //根据不同取消策略调用不同方法
        orderGoodsCancelMap.get(goodsCancelParam.getCancelOperateType()).accept(build);

        OrderCancelReasonParam orderCancelReasonParam = new OrderCancelReasonParam();
        orderCancelReasonParam.setOrderNo(goodsCancelParam.getOrderNo());
        orderCancelReasonParam.setOrderGoodsNo(goodsCancelParam.getOrderGoodsNo());
        orderCancelReasonParam.setReason(goodsCancelParam.getCancelReason());
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        orderCancelReasonParam.setCreateNo(loginUserInfo.getUserNo());
        orderCancelReasonParam.setCreateName(loginUserInfo.getUserName());

        //删除绑定记录
        goodsOrderTruckRecordComponent.deleteTruckRecord(orderGoods.getOrderGoodsNo());
        //记录取消意见
        orderFeign.orderCancelReason(orderCancelReasonParam);

        if (CollectionUtil.isNotEmpty(childNoList)) {
            for (String childNo : childNoList) {
                // 货单取消
                orderChildPostService.orderGoodsCancel(childNo);
            }
        }

        OrderTruckBindCancelParam bindCancelParam = new OrderTruckBindCancelParam();
        bindCancelParam.setOrderGoodsNo(orderGoodsNo);
        Message message = MessageBuilder.withBody(JSONUtil.parse(bindCancelParam).toString().getBytes()).build();
        message.getMessageProperties().setHeader("x-delay", 2000);
        //执行解绑自有车辆处理逻辑，将绑定记录正常改为取消
        rabbitTemplate.send(
                RabbitKeyConstants.ORDER_TRUCK_BIND_LAZY_EXCHANGE, RabbitKeyConstants.ORDER_TRUCK_BIND_LAZY_ROUTE_KEY, message
        );
        orderGoodsLogService.saveLog(orderGoodsNo, loginUserInfo.getUserNo(), loginUserInfo.getUserName(), OrderGoodsLogsEnum.Type.CANCEL.getName(), "");

    }

    private void cancelOperateThreeTypeStrategy(OrderGoodsCancelDTO dto) {
        String now = DateUtils.formatDateTime(LocalDateTime.now()).get();
        BigDecimal sum = BigDecimal.ZERO;
        OrderGoods orderGoods = dto.getOrderGoods();
        List<String> childNoList = dto.getChildNoList();
        RollbackOrderWeightParam param = new RollbackOrderWeightParam();

        List<OrderChild> orderChildList = orderChildDao.selectResidueWeightByOrderGoodsNo(orderGoods.getOrderGoodsNo(),
                OrderChildEnum.Status.DRIVER_CANCEL.getCode(), dto.getOrderGoodsCancelParam().getTruckList());

        if (CollectionUtils.isNotEmpty(orderChildList)) {
            List<OrderChild> filterOrderChildList = orderChildList.stream().
                    filter(item -> item.getStatus() < OrderChildEnum.Status.LOAD.getCode()).collect(Collectors.toList());

            for (OrderChild orderChild : filterOrderChildList) {
                driverService.updateOrderStatus(orderChild.getDriverUserNo(),
                        DriverInfoEnum.DriverStatus.NO.getCode(), orderChild.getTruckId(), 1);
                childNoList.add(orderChild.getChildNo());
                sum = sum.add(orderChild.getWeight());
                orderChildLogService.saveOrderChildLog(orderChild.getChildNo(),
                        OrderChildEnum.Status.OWNER_CANCEL.getCode(), OrderChildEnum.Status.OWNER_CANCEL.getName(),
                        OrderChildLogEnum.CreateType.OWNER.getCode(), 0L, OrderChildLogEnum.CreateType.OWNER.getMsg()
                );
            }
            orderChildDao.batchUpdateOrderChildStatus(
                    OrderChildEnum.Status.PLATFORM_CANCEL.getCode(),"系统取消",
                    now, now, childNoList);
            orderChildList.removeAll(filterOrderChildList);
            if (CollectionUtil.isNotEmpty(orderChildList)) {
                dto.setOrderGoodsStatus(OrderGoodsStatusEnum.Status.COMPLETED.getCode());
            }
        }

        BigDecimal residueWeight = orderGoods.getResidueTransportWeight().add(sum);
        param.setResidueWeight(residueWeight);
        param.setOrderNo(orderGoods.getOrderNo());
        if (!orderGoods.getTruckDemand().equals(TruckDemandEnum.TruckType.PLATFORM_ANY_CAR.getCode())) {
            param.setOwnResidueCarryWeight(BigDecimal.ZERO);
            param.setPlatformResidueCarryWeight(BigDecimal.ZERO);
        } else {
            if (orderGoods.getVehicleUsage().equals(VehicleUsageEnum.Status.PLATFORM.getCode())) {
                param.setOwnResidueCarryWeight(BigDecimal.ZERO);
                param.setPlatformResidueCarryWeight(residueWeight);
            } else if (orderGoods.getVehicleUsage().equals(VehicleUsageEnum.Status.OWN.getCode())) {
                param.setOwnResidueCarryWeight(residueWeight);
                param.setPlatformResidueCarryWeight(BigDecimal.ZERO);
            }
        }
        orderGoodsTruckBindDao.updateOrderGoodsBindStatus(orderGoods.getOrderGoodsNo(), OrderGoodsTruckBindEnum.Status.CANCEL.getCode());

        log.info("取消货单,参数：{}", JSONUtil.parse(param));
        if (orderFeign.rollbackOrderWeight(param).succeed()) {
            orderGoodsDao.updateOrderGoodsSetResidueWeightAndAlreadyWeightAndStatus(orderGoods.getResidueTransportWeight(),
                    sum, dto.getOrderGoodsStatus(), orderGoods.getId());
        }
    }

    private void cancelOperateTwoTypeStrategy(OrderGoodsCancelDTO dto) {
        BigDecimal sum = BigDecimal.ZERO;
        String now = DateUtils.formatDateTime(LocalDateTime.now()).get();
        OrderGoods orderGoods = dto.getOrderGoods();
        RollbackOrderWeightParam param = new RollbackOrderWeightParam();
        List<OrderChild> orderChildList = orderChildDao.selectResidueWeightByOrderGoodsNo(orderGoods.getOrderGoodsNo(), OrderChildEnum.Status.DRIVER_CANCEL.getCode());
        List<String> childNoList = dto.getChildNoList();
        if (CollectionUtils.isNotEmpty(orderChildList)) {
            List<OrderChild> filterOrderChildList = orderChildList.stream().filter(item -> item.getStatus() < OrderChildEnum.Status.ARRIVE_SEND.getCode()).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(filterOrderChildList)) {
                for (OrderChild orderChild : filterOrderChildList) {
                    driverService.updateOrderStatus(orderChild.getDriverUserNo(), DriverInfoEnum.DriverStatus.NO.getCode(), orderChild.getTruckId(), 1);
                    childNoList.add(orderChild.getChildNo());
                    sum = sum.add(orderChild.getWeight());
                    orderChildLogService.saveOrderChildLog(orderChild.getChildNo(),
                            OrderChildEnum.Status.PLATFORM_CANCEL.getCode(), OrderChildEnum.Status.PLATFORM_CANCEL.getName(),
                            OrderChildLogEnum.CreateType.PLATFORM.getCode(), 0L, OrderChildLogEnum.CreateType.PLATFORM.getMsg()
                    );
                }
                orderChildDao.batchUpdateOrderChildStatus(
                        OrderChildEnum.Status.PLATFORM_CANCEL.getCode(), OrderChildEnum.Status.PLATFORM_CANCEL.getName(),
                        now, now, childNoList);
            }
            orderChildList.removeAll(filterOrderChildList);
            if (CollectionUtil.isNotEmpty(orderChildList)) {
                dto.setOrderGoodsStatus(OrderGoodsStatusEnum.Status.COMPLETED.getCode());
            }
        }

        BigDecimal residueWeight = orderGoods.getResidueTransportWeight().add(sum);
        param.setResidueWeight(residueWeight);
        param.setOrderNo(orderGoods.getOrderNo());
        if (!orderGoods.getTruckDemand().equals(TruckDemandEnum.TruckType.PLATFORM_ANY_CAR.getCode())) {
            param.setOwnResidueCarryWeight(BigDecimal.ZERO);
            param.setPlatformResidueCarryWeight(BigDecimal.ZERO);
        } else {
            if (orderGoods.getVehicleUsage().equals(VehicleUsageEnum.Status.PLATFORM.getCode())) {
                param.setOwnResidueCarryWeight(BigDecimal.ZERO);
                param.setPlatformResidueCarryWeight(residueWeight);
            } else if (orderGoods.getVehicleUsage().equals(VehicleUsageEnum.Status.OWN.getCode())) {
                param.setOwnResidueCarryWeight(residueWeight);
                param.setPlatformResidueCarryWeight(BigDecimal.ZERO);
            }
        }

        orderGoodsTruckBindDao.updateOrderGoodsBindStatus(orderGoods.getOrderGoodsNo(), OrderGoodsTruckBindEnum.Status.CANCEL.getCode());

        log.info("取消货单,参数：{}", JSONUtil.parse(param));
        if (orderFeign.rollbackOrderWeight(param).succeed()) {
            OrderGoods update = new OrderGoods();
            update.setId(orderGoods.getId());
            update.setResidueTransportWeight(BigDecimal.ZERO);
            update.setOrderGoodsStatus(OrderGoodsStatusEnum.Status.COMPLETED.getCode());
            orderGoodsDao.updateEntityByKey(update);
        }
    }

    private void cancelOperateOneTypeStrategy(OrderGoodsCancelDTO dto) {
        RollbackOrderWeightParam param = new RollbackOrderWeightParam();
        OrderGoods orderGoods = dto.getOrderGoods();
        List<OrderChild> orderChildList = orderChildDao.selectResidueWeightByOrderGoodsNo(orderGoods.getOrderGoodsNo(), OrderChildEnum.Status.DRIVER_CANCEL.getCode());
        if (CollectionUtils.isNotEmpty(orderChildList)) {
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前货单已产生运单");
        }
        BigDecimal residueWeight = dto.getOrderGoods().getResidueTransportWeight();
        param.setResidueWeight(residueWeight);
        param.setOrderNo(orderGoods.getOrderNo());
        if (!orderGoods.getTruckDemand().equals(TruckDemandEnum.TruckType.PLATFORM_ANY_CAR.getCode())) {
            param.setOwnResidueCarryWeight(BigDecimal.ZERO);
            param.setPlatformResidueCarryWeight(BigDecimal.ZERO);
        } else {
            if (orderGoods.getVehicleUsage().equals(VehicleUsageEnum.Status.PLATFORM.getCode())) {
                param.setOwnResidueCarryWeight(BigDecimal.ZERO);
                param.setPlatformResidueCarryWeight(residueWeight);
            } else if (orderGoods.getVehicleUsage().equals(VehicleUsageEnum.Status.OWN.getCode())) {
                param.setOwnResidueCarryWeight(residueWeight);
                param.setPlatformResidueCarryWeight(BigDecimal.ZERO);
            }
        }
        orderGoodsTruckBindDao.updateOrderGoodsBindStatus(orderGoods.getOrderGoodsNo(), OrderGoodsTruckBindEnum.Status.CANCEL.getCode());

        log.info("取消货单,参数：{}", JSONUtil.parse(param));
        if (orderFeign.rollbackOrderWeight(param).succeed()) {
            OrderGoods update = new OrderGoods();
            update.setId(orderGoods.getId());
            update.setResidueTransportWeight(BigDecimal.ZERO);
            update.setOrderGoodsStatus(dto.getOrderGoodsStatus());
            orderGoodsDao.updateEntityByKey(update);
        }
    }

    /**
     * 查看当前货单可取消吨数
     * @param goodsCancelParam
     * @return
     */
    @Override
    public BigDecimal orderGoodsCancelResidueWeight(OrderGoodsCancelParam goodsCancelParam) {
        String orderGoodsNo = goodsCancelParam.getOrderGoodsNo();
        OrderGoods orderGoods = orderGoodsDao.getByOrderGoodsNo(orderGoodsNo).orElseThrow(PerformanceResultEnum.HTTP_ERROR, "未查询到货单");
        List<OrderChild> orderChildList = null;
        BigDecimal residueWeight = null;
        BigDecimal sum = BigDecimal.ZERO;
        Integer cancelOperateType = goodsCancelParam.getCancelOperateType();
        // 1：弹窗1  2：取消未接单及未到达货源地的车辆 3：取消未接单及未装车的车辆
        switch (cancelOperateType) {
            case 1:
                return orderGoods.getResidueTransportWeight();
            case 2:
                orderChildList = orderChildDao.selectResidueWeightByOrderGoodsNo(orderGoods.getOrderGoodsNo(), OrderChildEnum.Status.ARRIVE_SEND.getCode());
                if (CollectionUtils.isNotEmpty(orderChildList)) {
                    sum = orderChildList.stream().map(OrderChild::getWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
                }
                residueWeight = orderGoods.getResidueTransportWeight().add(sum);

                return residueWeight;
            case 3:
                orderChildList = orderChildDao.selectResidueWeightByOrderGoodsNo(orderGoods.getOrderGoodsNo(), OrderChildEnum.Status.LOAD.getCode(), goodsCancelParam.getTruckList());
                if (CollectionUtils.isNotEmpty(orderChildList)) {
                    sum = orderChildList.stream().map(OrderChild::getWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
                }
                residueWeight = orderGoods.getResidueTransportWeight().add(sum);

                return residueWeight;
            default:
                throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "参数类型有误");

        }


    }


    @Override
    public List<String> getOrderChildTruckList(String orderGoodsNo) {
        List<OrderChild> orderChildList = orderChildDao.selectResidueWeightByOrderGoodsNo(orderGoodsNo, OrderChildEnum.Status.LOAD.getCode());
        if (CollectionUtil.isNotEmpty(orderChildList)) {
            return orderChildList.stream().map(OrderChild::getTruckNo).collect(Collectors.toList());
        }
        return null;
    }

    @Override
    public OrderGoodsEditVO findOrderGoodsById(Integer id) {
        OrderGoodsEditVO result = new OrderGoodsEditVO();
        OrderGoodsVO orderGoodsVO = orderGoodsDao.findOrderGoodsById(id);
        if(BigDecimal.ZERO.compareTo(orderGoodsVO.getResidueTransportWeight()) == 0 ){
            //如果借吨或者恢复吨数，会导致提取吨数不准确，所以这里取准确提取吨数
            orderGoodsVO.setExtractWeight(orderGoodsVO.getAlreadyTransportWeight());
        }else{
            orderGoodsVO.setExtractWeight(orderGoodsVO.getAlreadyTransportWeight().add(orderGoodsVO.getResidueTransportWeight()));
        }
        String orderNo = orderGoodsVO.getOrderNo();
        FeignOrderVO orderInfoFeign = orderFeign.getOrderInfoFeign(orderNo);
        result.setOrderNo(orderInfoFeign.getOrderNo());
        result.setTransportWeight(orderInfoFeign.getTransportWeight());
        result.setValidFreightPrice(orderInfoFeign.getValidFreightPrice());
        result.setTruckDemand(orderInfoFeign.getTruckDemand());
        result.setResidueWeight(orderInfoFeign.getResidueWeight());
        result.setOwnCarryWeight(orderInfoFeign.getOwnCarryWeight());
        result.setOwnResidueCarryWeight(orderInfoFeign.getOwnResidueCarryWeight());
        result.setPlatformCarryWeight(orderInfoFeign.getPlatformCarryWeight());
        result.setPlatformResidueCarryWeight(orderInfoFeign.getPlatformResidueCarryWeight());

        result.setDownFloatWeight(orderInfoFeign.getDownFloatWeight());
        result.setUpFloatWeight(orderInfoFeign.getUpFloatWeight());
        result.setStopFlag(orderInfoFeign.getStopFlag());
        result.setSettlementAccountPeriod(orderInfoFeign.getSettlementAccountPeriod());
        result.setTransportEndTime(orderInfoFeign.getTransportEndTime());
        List<OrderChild> orderChildList = orderChildDao.selectListByOrderGoodsNo(orderGoodsVO.getOrderGoodsNo());
        if (CollectionUtils.isNotEmpty(orderChildList)) {
            result.setEditAllFlag(false);
        } else {
            result.setEditAllFlag(true);
        }
        List<OrderGoodsTruckBind> truckBindList = orderGoodsTruckBindDao.selectListByOrderGoodsNo(orderGoodsVO.getOrderGoodsNo());
        if (CollectionUtils.isNotEmpty(truckBindList)) {
            List<String> collect = truckBindList.stream().map(OrderGoodsTruckBind::getTruckNo).collect(Collectors.toList());
            orderGoodsVO.setTruckList(collect.stream().distinct().collect(Collectors.toList()));
        }
        result.setOrderGoodsVO(orderGoodsVO);

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateSystemAddressId(Integer ownerAddressId, Integer systemAddressId) {

        orderGoodsDao.updateSendSystemAddress(ownerAddressId, systemAddressId);
        orderGoodsDao.updateReceiveSystemAddress(ownerAddressId, systemAddressId);

        orderChildDao.updateSendSystemAddress(ownerAddressId, systemAddressId);
        orderChildDao.updateReceiveSystemAddress(ownerAddressId, systemAddressId);

        return true;
    }

    @Override
    public FreightEstimateVO listFreightEstimate(OrderChildReportParam param) {
        List<Double> lossNet = orderChildDao.getLossNet(param);
        List<Double> freightPrice = orderGoodsDao.getFreightPrice(param.getSendAddressId(), param.getReceiveAddressId(),param.getOrderNo());
        FreightEstimateVO freightEstimateVO= new FreightEstimateVO();
        freightEstimateVO.setLossNet(lossNet);
        freightEstimateVO.setFreightPriceList(freightPrice);
        return freightEstimateVO;
    }

    @Override
    public IPage<OrderGoodsAPPVO> indexOrderGoodsListSearch(AppGoodsOrderSearchParam param) {
        return orderGoodsDao.indexOrderGoodsListSearch(param);
    }

    @Override
    public void borrowWeight(OrderGoods orderGoods,String orderChildNo, BigDecimal subOrderGoodsResidue, BigDecimal addAlready,BigDecimal borrowOrderWeight,
            Integer orderGoodsStatus) {
        log.info("运单号:{} 进行订单借量,货单剩余吨数需扣减:{} 吨,货单已拉运吨数需增加:{} 吨,订单借用吨数:{} 吨",orderChildNo,
                subOrderGoodsResidue,addAlready,borrowOrderWeight);
        //更新订单吨数
        orderCancelComponent.backFillOrderWeight(orderGoods,borrowOrderWeight, UpdateEnum.SUB.getCode());
        //更新货单吨数
        orderGoodsDao.updateOrderGoodsWeightResidueAndAlreadyAndStatus(orderGoods.getId(),addAlready,subOrderGoodsResidue,orderGoodsStatus);
        orderGoodsLogService.saveLog(orderGoods.getOrderGoodsNo(), 0L, "系统", OrderGoodsLogsEnum.Type.SYSTEM_INCREASE.getName(),
                String.format("系统自动提量：%s吨", borrowOrderWeight));

    }

    @Override
    public void batchUpdateResidueWeight(List<OrderGoods> list) {
        if(CollectionUtils.isEmpty(list)){
            return;
        }
        List<Integer> collect = list.stream().map(OrderGoods::getId).collect(Collectors.toList());
        orderGoodsDao.batchUpdateResidueWeight(collect,BigDecimal.ZERO);
    }

    @Override
    public void updateFrightPrice(String orderNo, BigDecimal pendingOrderFreight) {
        List<OrderGoods> list = orderGoodsDao.getOrderGoodsListByOrderNo(orderNo);
        if (list.isEmpty()) {return;}
        log.info("更新货单运费, orderNo:{}, pendingOrderFreight:{}", orderNo, pendingOrderFreight);
        orderGoodsDao.updatePendingOrderFreightByIdList(pendingOrderFreight, list.stream().map(item->item.getId()).collect(Collectors.toList()));
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        orderGoodsCancelMap.put(1, this::cancelOperateOneTypeStrategy);
        orderGoodsCancelMap.put(2, this::cancelOperateTwoTypeStrategy);
        orderGoodsCancelMap.put(3, this::cancelOperateThreeTypeStrategy);

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveBindTruck(DistributionTruckParam param) {
        //查询货单信息，并且必须是车队运营系统派发车辆的货单
        OrderGoods orderGoods = orderGoodsDao.getByOrderGoodsNo(param.getOrderGoodsNo()).orElseThrow(
                PerformanceResultEnum.DATA_NOT_FIND, "货单不存在");
        if(!Objects.equals(orderGoods.getPendingOrderWay(),OrderGoodsPendingOrderWayStatusEnum.Status.FLEET_EXCLUSIVE.getCode())
         && !Objects.equals(orderGoods.getPendingOrderWay(),OrderGoodsPendingOrderWayStatusEnum.Status.FLEET_OPEN.getCode())){
            throw new ServiceSystemException(PerformanceResultEnum.DATA_NOT_FIND, "货单不是车队派发货单");
        }

        if(Objects.equals(orderGoods.getPendingOrderWay(),OrderGoodsPendingOrderWayStatusEnum.Status.FLEET_EXCLUSIVE.getCode())){
            orderGoodsTruckBindDao.saveBatchEntity(param.getOrderNo(), param.getOrderGoodsNo(),
                    param.getTruckNoList(), LocalDateTime.now());
            goodsOrderTruckRecordComponent.saveTruckRecord(param.getOrderGoodsNo(),param.getTruckNoList());
        }else{
            //车队公开单保存 货单和车辆的关系
            Optional<OrderGoodsFleetOpenTruck> optional = orderGoodsFleetOpenTruckDao.getOneByField(
                    OrderGoodsFleetOpenTruck::getOrderGoodsNo, param.getOrderGoodsNo());

            if(optional.isPresent()){
                OrderGoodsFleetOpenTruck orderGoodsFleetOpenTruck = optional.get();
                List<String> oldTruckNoList = JSON.parseArray(orderGoodsFleetOpenTruck.getTruckListJson(), String.class);
                //前后两次选择的车辆去重
                oldTruckNoList.addAll(param.getTruckNoList());
                Set<String> merge = new HashSet<>(oldTruckNoList);
                oldTruckNoList.clear();
                oldTruckNoList.addAll(merge);
                orderGoodsFleetOpenTruck.setTruckListJson(JSON.toJSONString(oldTruckNoList));
                orderGoodsFleetOpenTruckDao.updateEntityByKey(orderGoodsFleetOpenTruck);
            }else{
                OrderGoodsFleetOpenTruck save = new OrderGoodsFleetOpenTruck();
                save.setOrderNo(param.getOrderNo());
                save.setOrderGoodsNo(param.getOrderGoodsNo());
                save.setTruckListJson(JSON.toJSONString(param.getTruckNoList()));
                orderGoodsFleetOpenTruckDao.saveEntity(save);
            }
        }


    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BigDecimal cancelOrderGoods(CancelOrderGoodsParam param) {
        log.info("取消货单：{}",param);

        List<OrderGoods> orderGoodsList = orderGoodsDao.getOrderGoodsListByOrderNo(param.getOrderNo());

        // 过滤可取消
        List<OrderGoods> orderGoodsUpdateList =
                orderGoodsList.stream().filter(item ->
                        Objects.equals(item.getOrderGoodsStatus(), OrderGoodsStatusEnum.Status.CREATED.getCode())
                        || Objects.equals(item.getOrderGoodsStatus(), OrderGoodsStatusEnum.Status.PAYING.getCode())
                        || Objects.equals(item.getOrderGoodsStatus(), OrderGoodsStatusEnum.Status.GO_TO_SEND.getCode())
                ).collect(Collectors.toList());
        if (orderGoodsUpdateList.isEmpty()) {return BigDecimal.ZERO;}

        //取消货单
        orderGoodsDao.batchCancel(orderGoodsUpdateList.stream().map(item->item.getId()).collect(Collectors.toList()));

        //批量保存货单日志
        log.info("orderGoodsListByOrderNo：{}",orderGoodsUpdateList);
        List<OrderGoodsLog> orderGoodsLogs = new ArrayList<>();
        OrderGoodsLog orderGoodsLog = null;
        BigDecimal totalCancelWeight = BigDecimal.ZERO;
        List<String> cancelTruckBindOrderGoodsNoList = new ArrayList<>();

        for(OrderGoods orderGoods:orderGoodsUpdateList){
            orderGoodsLog = new OrderGoodsLog();
            orderGoodsLog.setOrderGoodsNo(orderGoods.getOrderGoodsNo());
            orderGoodsLog.setCreateName("系统");
            orderGoodsLog.setType(OrderGoodsLogsEnum.Type.CANCEL.getName());
            orderGoodsLog.setCreateBy(0L);
            orderGoodsLog.setRemark("货主发起减吨请求，当前已挂单量超过总拉运量，自动取消");
            orderGoodsLogs.add(orderGoodsLog);
            totalCancelWeight = totalCancelWeight.add(Objects.nonNull(orderGoods.getResidueTransportWeight())?
                    orderGoods.getResidueTransportWeight() : BigDecimal.ZERO);
            if(Objects.equals(orderGoods.getPendingOrderWay(),PendingOrderWayStatusEnum.Status.DX.getCode())
                    || Objects.equals(orderGoods.getPendingOrderWay(),PendingOrderWayStatusEnum.Status.FLEET_DX.getCode())){
                cancelTruckBindOrderGoodsNoList.add(orderGoods.getOrderGoodsNo());
            }
        }
        //取消货单下未接单的车辆绑定关系
        if(CollectionUtils.isNotEmpty(cancelTruckBindOrderGoodsNoList)){

            cancelTruckBindOrderGoodsNoList.forEach(item->goodsOrderTruckRecordComponent.deleteTruckRecord(item));
/*            //查询定向货单下未接单的车辆
            List<OrderGoodsTruckBind> notOrderBindTruckList = orderGoodsTruckBindDao.
                    queryNotOrderTruck(cancelTruckBindOrderGoodsNoList);
            //删除缓存中未接单的车辆绑定
            if(CollectionUtils.isNotEmpty(notOrderBindTruckList)){
                for (OrderGoodsTruckBind bind : notOrderBindTruckList) {
                    goodsOrderTruckRecordComponent.deleteTruckRecord(bind.getOrderGoodsNo(), bind.getTruckNo());
                }
            }*/

            orderGoodsTruckBindDao.updateOrderGoodsBindStatus(cancelTruckBindOrderGoodsNoList,
                    OrderGoodsTruckBindEnum.Status.CANCEL.getCode());
        }
        orderGoodsLogService.saveBatchLog(orderGoodsLogs);
        return totalCancelWeight;

    }

    @Override
    public List<DriverFreightPriceVO> getDriverFreightPriceList(String orderNo) {
        List<OrderGoods> orderGoods = orderGoodsDao.listAfterCreatedByOrderNo(orderNo);
        return orderGoodsStruct.convertDriverFreightList(orderGoods);
    }

    @Override
    public List<OrderGoodsPendingVO> getOrderGoodsPendingList(String orderNo) {
        List<OrderGoods> orderGoods = orderGoodsDao.listAfterCreatedByOrderNo(orderNo);
        //升序排序
        List<OrderGoods> sort = orderGoods.stream().sorted(Comparator.comparing(OrderGoods::getPendingOrderTime))
                .collect(Collectors.toList());
        return orderGoodsStruct.convertOrderGoodsPendingList(sort);
    }
}
