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.ResultEnum;
import com.clx.order.enums.VehicleUsageEnum;
import com.clx.order.feign.OrderFeign;
import com.clx.order.param.feign.OrderCancelReasonParam;
import com.clx.order.vo.feign.FeignOrderInfoVO;
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.SettlementOrderChildRiskEnum;
import com.clx.performance.enums.settle.SettlementOwnerEnum;
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.extranal.user.OrderService;
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.*;
import com.clx.performance.service.child.OrderChildPostService;
import com.clx.performance.struct.OrderGoodsStruct;
import com.clx.performance.utils.excel.ExcelData;
import com.clx.performance.utils.excel.ExcelField;
import com.clx.performance.utils.excel.ExcelSheet;
import com.clx.performance.utils.excel.ExcelUtil;
import com.clx.performance.vo.app.OrderGoodsAPPVO;
import com.clx.performance.vo.feign.FreightEstimateVO;
import com.clx.performance.vo.feign.OrderExtractWeightVO;
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.performance.vo.pc.carrier.settle.SettlementOrderChildRiskVO;
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.apache.poi.xssf.streaming.SXSSFWorkbook;
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;

    @Autowired
    OrderWeightService orderWeightService;

    @Autowired
    OrderService orderService;



    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();
        BigDecimal residueWeight = this.calcOrderGoodsResidueWeight(orderGoodsVO.getExtractWeight(),
                orderGoodsVO.getAlreadyTransportWeight());
        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(residueWeight);
        //货源地信息
        orderGoodsVO.setSendContact(orderInfoFeign.getSendContact());
        orderGoodsVO.setSendContactPhone(orderInfoFeign.getSendContactPhone());
        orderGoodsVO.setSendWaitSystem(orderInfoFeign.getSendWaitSystem());
        orderGoodsVO.setSendWaitSystemName(orderInfoFeign.getSendWaitSystemName());
        orderGoodsVO.setSendWaitMode(orderInfoFeign.getSendWaitMode());

        //获取订单配置的违约金方案
        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);
        }

        //目的地信息
        orderGoodsVO.setReceiveContact(orderInfoFeign.getReveiveContact());
        orderGoodsVO.setReceiveContactPhone(orderInfoFeign.getReveiveContactPhone());
        orderGoodsVO.setReceiveWaitSystem(orderInfoFeign.getReveiveWaitSystem());
        orderGoodsVO.setReceiveWaitSystemName(orderInfoFeign.getReveiveWaitSystemName());
        orderGoodsVO.setReceiveWaitMode(orderInfoFeign.getReveiveWaitMode());

        return orderGoodsVO;
    }

    @Override
    public IPage<OrderGoodsVO> pageOrderGoodsList(PageOrderGoodsListParam param) {
        long start2 = System.currentTimeMillis();
        IPage<OrderGoodsVO> page = orderGoodsDao.pageOrderGoodsList(param);
        long start3 = System.currentTimeMillis();
        log.info("执行耗时2,{}",start3-start2);
        if(CollectionUtils.isNotEmpty(page.getRecords())){
            List<String> fleetNoList = new ArrayList<>();
            List<String> orderNoList = new ArrayList<>();

            for (OrderGoodsVO record : page.getRecords()) {
                if(Objects.equals(record.getPendingOrderWay(),PendingOrderWayStatusEnum.Status.FLEET_DX.getCode())){
                    fleetNoList.add(record.getOrderGoodsNo());
                }
                orderNoList.add(record.getOrderNo());
            }
            long start5 = System.currentTimeMillis();
            log.info("执行耗时3,{}",start5-start3);
            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())));
            }
            long start6 = System.currentTimeMillis();
            log.info("执行耗时4,{}",start6-start5);
            Optional<Map<String, FeignOrderInfoVO>> orderListOption = orderService.queryListOrderByOrderNoList(orderNoList);

            if(!orderListOption.isPresent()){
                log.warn("通过订单号批量查询订单信息失败，失败原因");
                throw new ServiceSystemException(ResultEnum.DATA_ERROR,"查询货单对应的订单信息失败");
            }
            long start7 = System.currentTimeMillis();
            log.info("执行耗时5,{}",start7-start6);
            List<OrderGoods> orderGoods = orderGoodsDao.listInField(OrderGoods::getOrderNo, orderNoList);
            long start8 = System.currentTimeMillis();
            log.info("执行耗时6,{}",start8-start7);

            Map<String, BigDecimal> orderExtractWeightMap = new HashMap<>();
            for (OrderGoods orderGood : orderGoods) {
                //计算货单真实的提取量
                BigDecimal weight = orderWeightService.calcOrderGoodsRealExtractWeight(orderGood);
                String orderNo = orderGood.getOrderNo();
                orderExtractWeightMap.put(orderNo,Objects.nonNull(orderExtractWeightMap.get(orderNo))?
                        orderExtractWeightMap.get(orderNo).add(weight): weight);
            }
            long start9 = System.currentTimeMillis();
            log.info("执行耗时7,{}",start9-start8);
            Map<String, FeignOrderInfoVO> orderInfoMap = orderListOption.get();
            page.getRecords().forEach(item->{
                FeignOrderInfoVO orderInfo = orderInfoMap.get(item.getOrderNo());
                BigDecimal orderExtractWeight = orderExtractWeightMap.get(item.getOrderNo());
                if(Objects.nonNull(orderInfo) && Objects.nonNull(orderExtractWeight)){
                    if(orderExtractWeight.compareTo(orderInfo.getTransportWeight()) > 0 ){
                        item.setOverOrderWeight(1);
                    }
                }
                item.setResidueTransportWeight(calcOrderGoodsResidueWeight(item.getExtractWeight(),item.getAlreadyTransportWeight()));
            });
            long start11 = System.currentTimeMillis();
            log.info("执行耗时8,{}",start11-start9);
        }
        return page;
    }

    @Override
    public SXSSFWorkbook exportOrderGoods(PageOrderGoodsListParam param) {
        param.setPage(1);
        param.setPageSize(1000000);
        IPage<OrderGoodsVO> orderGoodsPage = pageOrderGoodsList(param);

        List<OrderGoodsVO> list = orderGoodsPage.getRecords();

        // 组装表头
        List<ExcelField> fieldList = new ArrayList<>();
        fieldList.add(new ExcelField(0, "货单编号", "orderGoodsNo", 5000));
        fieldList.add(new ExcelField(1, "订单编号", "orderNo", 5000));
        fieldList.add(new ExcelField(2, "订单来源", "orderSourceMsg", 5000));
        fieldList.add(new ExcelField(3, "发货地址", "sendAddressShorter", 5000));
        fieldList.add(new ExcelField(4, "收货地址", "receiveAddressShorter", 5000));

        fieldList.add(new ExcelField(5, "货物名称", "goodsName", 5000));
        fieldList.add(new ExcelField(6, "提取吨数", "extractWeight", 5000));
        fieldList.add(new ExcelField(7, "已抢单吨数", "alreadyTransportWeight", 5000));
        fieldList.add(new ExcelField(8, "未抢单吨数", "residueTransportWeight", 5000));
        fieldList.add(new ExcelField(9, "已装车吨数", "alreadyLoadWeight", 5000));

        fieldList.add(new ExcelField(10, "创建时间", "createTime", 5000));
        fieldList.add(new ExcelField(11, "货单状态", "orderGoodsStatus", 5000));

        // 组装数据
        List<List<ExcelData>> dataList = new ArrayList<>();
        for (OrderGoodsVO vo : list) {
            List<ExcelData> rowData = new ArrayList<>();
            rowData.add(new ExcelData(vo.getOrderGoodsNo()));
            rowData.add(new ExcelData(vo.getOrderNo()));
            rowData.add(new ExcelData(vo.getOrderSourceMsg(), "-"));
            rowData.add(new ExcelData(vo.getSendAddressShorter()));
            rowData.add(new ExcelData(vo.getReceiveAddressShorter()));

            rowData.add(new ExcelData(vo.getGoodsName()));
            rowData.add(new ExcelData(vo.getExtractWeight()));
            rowData.add(new ExcelData(vo.getAlreadyTransportWeight()));
            rowData.add(new ExcelData(vo.getResidueTransportWeight()));
            rowData.add(new ExcelData(vo.getAlreadyLoadWeight()));

            rowData.add(new ExcelData(vo.getCreateTime()));
            rowData.add(new ExcelData(OrderGoodsStatusEnum.Status.getMsgByCode(vo.getOrderGoodsStatus())));

            dataList.add(rowData);
        }

        ExcelSheet excelSheet = new ExcelSheet("货单明细", "货单明细", fieldList, dataList);

        //创建excel
        return ExcelUtil.create(excelSheet);
    }

    @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);
        //货单没有辆，并且货单用车非自有车
        BigDecimal residueTransportWeight = this.calcOrderGoodsResidueWeight
                (orderGoods.getExtractWeight(),orderGoods.getAlreadyTransportWeight());
        if (residueTransportWeight.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);

        if(CollectionUtils.isNotEmpty(list)){
            list.forEach(item-> item.setResidueTransportWeight(this.calcOrderGoodsResidueWeight(item.getExtractWeight(),
                    item.getAlreadyTransportWeight())));
        }
        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) {
        BigDecimal residueWeight = orderWeightService.getOrderResidueWeight(orderNo);

        switch (optionType) {
            case "1":
                return residueWeight;
            case "2":
                return residueWeight;
            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);
                }
                residueWeight = residueWeight.add(childResidueWeight);
                return residueWeight;
            default:throw new RuntimeException("参数错误");
        }

    }


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

        //考虑到借吨、恢复吨数的货单，逻辑判断实际的提取吨数
        BigDecimal oldResidueTransportWeight = this.calcOrderGoodsResidueWeight
                (oldOrderGoods.getExtractWeight(),oldOrderGoods.getAlreadyTransportWeight());

        OrderExtractWeightVO orderCanExtractWeight = orderWeightService.getOrderCanExtractWeight(param.getOrderNo());

        BigDecimal canExtractWeight = orderCanExtractWeight.getCanExtractWeight();

        BigDecimal changeWeight = orderGoodsParams.getExtractWeight().subtract(oldOrderGoods.getExtractWeight());

        //当计算出的订单可提取量为负数时，说明订单下调吨数，货单超过订单量，所以货单编辑吨数的时候只能进行下调操作
        if(canExtractWeight.compareTo(BigDecimal.ZERO) < 0  && changeWeight.compareTo(BigDecimal.ZERO) > 0){
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前货单总量已超吨，只能做吨数下调操作");

        }
        BigDecimal realExtractWeight = oldResidueTransportWeight.compareTo(BigDecimal.ZERO) <= 0?
                oldOrderGoods.getAlreadyTransportWeight():oldOrderGoods.getExtractWeight();
        oldOrderGoods.setExtractWeight(realExtractWeight);

        BigDecimal orderResidueWeight = orderWeightService.getOrderResidueWeight(param.getOrderNo());

        if (orderResidueWeight.compareTo(changeWeight) < 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(), "");
    }

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

        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());
            }
        }
        orderGoodsTruckBindDao.updateOrderGoodsBindStatus(orderGoods.getOrderGoodsNo(), OrderGoodsTruckBindEnum.Status.CANCEL.getCode());

        orderGoodsDao.updateOrderGoodsSetAlreadyWeightAndStatus(sum, dto.getOrderGoodsStatus(), orderGoods.getId());

    }

    private void cancelOperateTwoTypeStrategy(OrderGoodsCancelDTO dto) {
        String now = DateUtils.formatDateTime(LocalDateTime.now()).get();
        OrderGoods orderGoods = dto.getOrderGoods();
        List<OrderChild> orderChildList = orderChildDao.selectResidueWeightByOrderGoodsNo(orderGoods.getOrderGoodsNo(), OrderChildEnum.Status.DRIVER_CANCEL.getCode());
        List<String> childNoList = dto.getChildNoList();

        BigDecimal childResidueWeight = BigDecimal.ZERO;

        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());
                    orderChildLogService.saveOrderChildLog(orderChild.getChildNo(),
                            OrderChildEnum.Status.PLATFORM_CANCEL.getCode(), OrderChildEnum.Status.PLATFORM_CANCEL.getName(),
                            OrderChildLogEnum.CreateType.PLATFORM.getCode(), 0L, OrderChildLogEnum.CreateType.PLATFORM.getMsg()
                    );
                    childResidueWeight = childResidueWeight.add(orderChild.getWeight());

                }
                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());
            }
        }
        orderGoodsTruckBindDao.updateOrderGoodsBindStatus(orderGoods.getOrderGoodsNo(), OrderGoodsTruckBindEnum.Status.CANCEL.getCode());
        orderGoodsDao.updateOrderGoodsWeightAlreadyAndStatus(orderGoods.getId(),childResidueWeight,OrderGoodsStatusEnum.Status.COMPLETED.getCode());
    }

    private void cancelOperateOneTypeStrategy(OrderGoodsCancelDTO dto) {
        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, "当前货单已产生运单");
        }
        orderGoodsTruckBindDao.updateOrderGoodsBindStatus(orderGoods.getOrderGoodsNo(), OrderGoodsTruckBindEnum.Status.CANCEL.getCode());
        OrderGoods update = new OrderGoods();
        update.setId(orderGoods.getId());
        update.setOrderGoodsStatus(dto.getOrderGoodsStatus());
        orderGoodsDao.updateEntityByKey(update);
    }

    /**
     * 查看当前货单可取消吨数
     * @param goodsCancelParam
     * @return
     */
    @Override
    public BigDecimal orderGoodsCancelResidueWeight(OrderGoodsCancelParam goodsCancelParam) {

        OrderGoods orderGoods = orderGoodsDao.getByOrderGoodsNo(goodsCancelParam.getOrderGoodsNo()).orElseThrow(
                PerformanceResultEnum.DATA_NOT_FIND);

        //订单剩余吨数
        BigDecimal orderResidueWeight = orderWeightService.getOrderResidueWeight(orderGoods.getOrderNo());

        //获取货单剩余吨数
        BigDecimal orderGoodsResidueWeight = this.calcOrderGoodsResidueWeight(orderGoods.getExtractWeight(),orderGoods.getAlreadyTransportWeight());

        //货单剩余量大于订单剩余量，取订单剩余量，否则取货单剩余量
        BigDecimal residueWeight = orderGoodsResidueWeight.compareTo(orderResidueWeight) > 0? orderResidueWeight : orderGoodsResidueWeight;


        // 1：弹窗1  2：取消未接单及未到达货源地的车辆 3：取消未接单及未装车的车辆

        switch (goodsCancelParam.getCancelOperateType()) {
            case 1:
                return residueWeight;
            case 2:
                return residueWeight;
            case 3:
                List<OrderChild> orderChildList = orderChildDao.selectResidueWeight(goodsCancelParam.getOrderNo(), OrderChildEnum.Status.ARRIVE_SEND.getCode());
                BigDecimal childResidueWeight = BigDecimal.ZERO;
                if (CollectionUtils.isNotEmpty(orderChildList)) {
                    childResidueWeight = orderChildList.stream().map(OrderChild::getWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
                }
                residueWeight = residueWeight.add(childResidueWeight);
                return residueWeight;
            default:throw new RuntimeException("参数错误");
        }
    }


    @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);
        orderGoodsVO.setResidueTransportWeight(
                this.calcOrderGoodsResidueWeight(orderGoodsVO.getExtractWeight(),orderGoodsVO.getAlreadyTransportWeight())
        );

        // 车数
        orderGoodsVO.setAlreadyLoadTruckAmount(orderChildDao.countTakeByOrderGoodsNo(orderGoodsVO.getOrderGoodsNo()));
        orderGoodsVO.setAlreadyTransportTruckAmount(orderChildDao.countLoadByOrderGoodsNo(orderGoodsVO.getOrderGoodsNo()));

        String orderNo = orderGoodsVO.getOrderNo();
        FeignOrderVO orderInfoFeign = orderFeign.getOrderInfoFeign(orderNo);

        //查询订单可提取吨数
        OrderExtractWeightVO orderCanExtractWeight = orderWeightService.getOrderCanExtractWeight(orderNo);
        //查询订单剩余吨数
        BigDecimal residueWeight = orderWeightService.getOrderResidueWeight(orderNo);


        result.setOrderNo(orderInfoFeign.getOrderNo());
        result.setTransportWeight(orderCanExtractWeight.getTransportWeight());
        result.setValidFreightPrice(orderInfoFeign.getValidFreightPrice());
        result.setTruckDemand(orderInfoFeign.getTruckDemand());
        result.setResidueWeight(String.valueOf(residueWeight));
        result.setOwnCarryWeight(String.valueOf(orderCanExtractWeight.getOwnCarryWeight()));
        result.setOwnResidueCarryWeight(String.valueOf(orderCanExtractWeight.getOwnCanExtractWeight()));
        result.setPlatformCarryWeight(String.valueOf(orderCanExtractWeight.getPlatformCarryWeight()));
        result.setPlatformResidueCarryWeight(String.valueOf(orderCanExtractWeight.getPlatCanExtractWeight()));

        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 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);
            BigDecimal residueTransportWeight = this.calcOrderGoodsResidueWeight
                    (orderGoods.getExtractWeight(),orderGoods.getAlreadyTransportWeight());
            totalCancelWeight = totalCancelWeight.add(residueTransportWeight);
            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);
    }

    @Override
    public BigDecimal calcOrderGoodsResidueWeight(BigDecimal extractWeight, BigDecimal alreadyWeight) {
        BigDecimal weight1 = Objects.nonNull(extractWeight)?extractWeight:BigDecimal.ZERO;
        BigDecimal weight2 = Objects.nonNull(alreadyWeight)?alreadyWeight:BigDecimal.ZERO;
        return weight1.subtract(weight2);
    }
}
