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.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.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.OrderChildDao;
import com.clx.performance.dao.OrderGoodsDao;
import com.clx.performance.dao.OrderGoodsDriverTruckDao;
import com.clx.performance.dao.OrderGoodsTruckBindDao;
import com.clx.performance.dto.OrderGoodsCancelDTO;
import com.clx.performance.enums.*;
import com.clx.performance.extranal.user.DriverService;
import com.clx.performance.model.OrderChild;
import com.clx.performance.model.OrderGoods;
import com.clx.performance.model.OrderGoodsDriverTruck;
import com.clx.performance.model.OrderGoodsTruckBind;
import com.clx.performance.param.app.AppGoodsOrderSearchParam;
import com.clx.performance.param.app.OrderGoodsListPageParam;
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.OrderGoodsEditVO;
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;

    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 = 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());
        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.setResidueTransportWeight(BigDecimal.ZERO.compareTo(orderGoodsVO.getResidueTransportWeight()) > 0 ? BigDecimal.ZERO : orderGoodsVO.getResidueTransportWeight());
        return orderGoodsVO;
    }

    @Override
    public IPage<OrderGoodsVO> pageOrderGoodsList(PageOrderGoodsListParam param) {
        return orderGoodsDao.pageOrderGoodsList(param);
    }

    @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) {
        if (StringUtils.equals(orderGoodsListParam.getOrderGoodsType(), "1")) {
            return orderGoodsDao.openOrderPageGoodsList(orderGoodsListParam);
        } else {
            Optional<List<OrderGoodsDriverTruck>> truckList = orderGoodsDriverTruckDao.
                    selectListByDriverUserNo(orderGoodsListParam.getDriverUserNo());

            List<String> truckNoList = new ArrayList<>();

            //查询当前用户是否是车主
            Long driverUserNo = orderGoodsListParam.getDriverUserNo();
            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 new Page<>();
                }
                truckNoList.addAll(ownTruckByUserNo.getData());//当前用户自己的车
                truckNoList.addAll(truckList.get().stream().map(OrderGoodsDriverTruck::getTruckNo).collect(Collectors.toList()));//当前用户被绑定为司机的车
            }
            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);
        }
    }

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

        switch (optionType) {
            case "1":
                return new BigDecimal(residueWeight);
            case "2":
                orderGoodsList  = orderGoodsDao.getOrderGoodsListByOrderNoAndStatus(orderNo);
                if (CollectionUtil.isNotEmpty(orderGoodsList)) {
                    orderGoodsResidueWeight = orderGoodsList.stream().map(OrderGoods::getResidueTransportWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
                }
                return orderGoodsResidueWeight.add(new BigDecimal(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);

                }
                orderGoodsList = orderGoodsDao.getOrderGoodsListByOrderNoAndStatus(orderNo);
                if (CollectionUtil.isNotEmpty(orderGoodsList)) {
                    orderGoodsResidueWeight = orderGoodsList.stream().map(OrderGoods::getResidueTransportWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
                }
                return new BigDecimal(residueWeight).add(orderGoodsResidueWeight).add(childResidueWeight);

            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 afterPropertiesSet() throws Exception {
        orderGoodsCancelMap.put(1, this::cancelOperateOneTypeStrategy);
        orderGoodsCancelMap.put(2, this::cancelOperateTwoTypeStrategy);
        orderGoodsCancelMap.put(3, this::cancelOperateThreeTypeStrategy);

    }
}
