package com.sckw.transport.service;

import cn.hutool.core.util.ArrayUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.sckw.contract.api.RemoteContractService;
import com.sckw.contract.api.model.dto.res.ContractCommonInfoResDto;
import com.sckw.core.common.enums.NumberConstant;
import com.sckw.core.common.enums.StringConstant;
import com.sckw.core.common.enums.enums.DictTypeEnum;
import com.sckw.core.model.enums.CarWaybillEnum;
import com.sckw.core.model.enums.LogisticsOrderEnum;
import com.sckw.core.model.page.PageResult;
import com.sckw.core.utils.CollectionUtils;
import com.sckw.core.utils.IdWorker;
import com.sckw.core.utils.StringUtils;
import com.sckw.core.web.constant.HttpStatus;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.core.web.response.HttpResult;
import com.sckw.excel.utils.ValidUtil;
import com.sckw.fleet.api.RemoteFleetService;
import com.sckw.mongo.enums.BusinessTypeEnum;
import com.sckw.mongo.model.SckwLogisticsOrder;
import com.sckw.order.api.dubbo.TradeOrderInfoService;
import com.sckw.order.api.model.AddressInfoDetail;
import com.sckw.order.api.model.OrderDetailRes;
import com.sckw.order.api.model.UpdateOrderAmountParam;
import com.sckw.product.api.dubbo.GoodsInfoService;
import com.sckw.product.api.model.KwpGoods;
import com.sckw.stream.model.SckwBusSum;
import com.sckw.system.api.RemoteSystemService;
import com.sckw.transport.dao.*;
import com.sckw.transport.model.*;
import com.sckw.transport.model.dto.LogisticsOrderDTO;
import com.sckw.transport.model.dto.OrderCarDTO;
import com.sckw.transport.model.dto.OrderFinishDTO;
import com.sckw.transport.model.param.LogisticsConsignmentParam;
import com.sckw.transport.model.vo.OrderFinishVO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.*;

/**
 * @author lfdc
 * @description 物流托运/分包托运Service
 * @date 2023-06-28 11:06:07
 */
@Slf4j
@Service
public class LogisticsConsignmentService {

    @Resource
    private StreamBridge streamBridge;

    @DubboReference(version = "2.0.0", group = "design", check = false)
    RemoteSystemService remoteSystemService;

    @DubboReference(version = "2.0.0", group = "design", check = false)
    GoodsInfoService goodsInfoService;

    @DubboReference(version = "2.0.0", group = "design", check = false, timeout = 6000)
    TradeOrderInfoService tradeOrderInfoService;

    @DubboReference(version = "2.0.0", group = "design", check = false, timeout = 6000)
    RemoteFleetService remoteFleetService;

    @DubboReference(version = "2.0.0", group = "design", check = false, timeout = 6000)
    RemoteContractService remoteContractService;

    @Autowired
    public KwtLogisticsOrderGoodsMapper kwtLogisticsOrderGoodsMapper;

    @Autowired
    public KwtLogisticsOrderContractMapper kwtLogisticsOrderContractMapper;

    @Autowired
    public KwtLogisticsOrderMapper kwtLogisticsOrderMapper;

    @Autowired
    public KwtLogisticsOrderAddressMapper kwtLogisticsOrderAddressMapper;

    @Autowired
    public KwtLogisticsOrderTrackMapper kwtLogisticsOrderTrackMapper;

    @Autowired
    public KwtLogisticsOrderUnitMapper kwtLogisticsOrderUnitMapper;

    @Autowired
    public KwtWaybillOrderMapper waybillOrderMapper;

    /**
     * 采购订单-物流托运生成托运订单
     *
     * @param bo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public HttpResult purchaseLogisticsConsignment(LogisticsConsignmentParam bo) {
        HttpResult httpResult = ValidUtil.serviceValid(bo);
        if (HttpStatus.SUCCESS_CODE != httpResult.getCode()) {
            return HttpResult.error(httpResult.getMsg());
        }
        checkParamData(bo);
        logisticsConsignmentInsert(bo);
        return HttpResult.ok();
    }

    private void checkParamData(LogisticsConsignmentParam bo) {
        if (!ObjectUtils.isEmpty(bo.getLoss())) {
            if (NumberConstant.ZERO > bo.getLoss()) {
                throw new RuntimeException("合理损耗填写时,必须大于0");
            }
        }
        if (!ObjectUtils.isEmpty(bo.getGoodsPrice())) {
            if (NumberConstant.ZERO > bo.getGoodsPrice()) {
                throw new RuntimeException("扣亏货值填写时,必须大于0");
            }
        }
    }

    /**
     * 销售订单-物流托运生成托运订单
     * @param bo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public HttpResult sellLogisticsConsignment(LogisticsConsignmentParam bo) {
        HttpResult httpResult = ValidUtil.serviceValid(bo);
        if (HttpStatus.SUCCESS_CODE != httpResult.getCode()) {
            return HttpResult.error(httpResult.getMsg());
        }
        checkParamData(bo);
        logisticsConsignmentInsert(bo);
        return HttpResult.ok();
    }

    void logisticsConsignmentInsert(LogisticsConsignmentParam bo) {
        OrderDetailRes tradeOrder = tradeOrderInfoService.getOrderDetailById(Long.parseLong(bo.getTOrderId()));
        if (tradeOrder == null) {
            log.error("订单id查找失败:{}", bo.getTOrderId());
            throw new RuntimeException("单据错误,数据不存在");
        }
        KwtLogisticsOrder order = new KwtLogisticsOrder();
        if (!bo.getIsFullDose()) {
            Long amount = bo.getAmount();
            Long carryingCapacity = bo.getCarryingCapacity();
            if (carryingCapacity > amount) {
                log.error("可分配量分配错误:{}", bo.getTOrderId());
                throw new RuntimeException("可分配量分配错误");
            }
            if (ArrayUtil.isEmpty(bo.getCarryingCapacity())) {
                throw new RuntimeException("不是全量分配时,分配量不能为空!");
            }
            order.setAmount(new BigDecimal(bo.getCarryingCapacity()));
        } else {
            order.setAmount(new BigDecimal(NumberConstant.ZERO));
            order.setSubcontractAmount(new BigDecimal(NumberConstant.ZERO));
        }
        String lOrderNo = com.sckw.transport.utils.StringUtils.getLOrderNo();
        Long orderId = new IdWorker(NumberConstant.ONE).nextId();
        /**判断生成物流订单应生成哪一种单据状态*/
        List<Long> contractList = new ArrayList<>();
        contractList.add(Long.parseLong(bo.getContractId()));
        Map<Long, ContractCommonInfoResDto> longContractCommonInfoResDtoMap = remoteContractService.queryContractBaseInfo(contractList);
        if (CollectionUtils.isEmpty(longContractCommonInfoResDtoMap)) {
            throw new RuntimeException("并未有对应合同,应先签约合同");
        }
        if (longContractCommonInfoResDtoMap.get(Long.parseLong(bo.getContractId())) == null) {
            throw new RuntimeException("并未有对应合同,应先签约合同");
        }
        ContractCommonInfoResDto infoResDto = longContractCommonInfoResDtoMap.get(Long.parseLong(bo.getContractId()));
        /**状态判断
         * 是否是已签约合同
         * */
        // 0 已签约 1待签约
        Integer status = infoResDto.getStatus();
        Integer orderStatus = LogisticsOrderEnum.PENDING_ORDER.getCode();
        if (NumberConstant.ONE == status) {
            orderStatus = LogisticsOrderEnum.TO_BE_PLANNED.getCode();
        } else if (NumberConstant.ZERO == status) {
            orderStatus = LogisticsOrderEnum.PENDING_ORDER.getCode();
        } else {
            log.info("采购/销售生成物流托运 贸易订单id:{}," +
                            "贸易订单编号:{},合同id:{},合同信息:{}",
                    bo.getTOrderId(), bo.getTOrderNo(),
                    bo.getContractId(), JSONObject.toJSONString(infoResDto));
            throw new RuntimeException("生成物流托运合同异常");
        }
        insertLogisticsGoods(bo, lOrderNo, orderId);
        insertLogisticsOrder(bo, lOrderNo, order, tradeOrder, orderId, orderStatus);
        insertLogisticsOrderContract(bo, orderId);
        insertLogisticsOrderUnit(bo, orderId);
        insertLogisticsOrderAddress(bo, orderId);
        insertLogisticsOrderTrack(bo, orderId, orderStatus);
        sendMongoDB(lOrderNo, orderId, bo, tradeOrder, orderStatus);
    }

    /**
     * 组装数据发送至mongoDb
     *
     * @param lOrderNo    物流订单编号
     * @param orderId     物流订单id
     * @param bo          页面请求数据
     * @param tradeOrder  贸易单据
     * @param orderStatus 物流订单状态
     */
    private void sendMongoDB(String lOrderNo, Long orderId, LogisticsConsignmentParam bo, OrderDetailRes tradeOrder, Integer orderStatus) {
        SckwLogisticsOrder logisticsOrder = new SckwLogisticsOrder();
        logisticsOrder.setStatus(String.valueOf(orderStatus));
        logisticsOrder.setLOrderId(orderId);
        logisticsOrder.setLOrderNo(lOrderNo);
        logisticsOrder.setLOrderPid(null);
        logisticsOrder.setTOrderId(tradeOrder.getId());
        logisticsOrder.setTOrderNo("D" + com.sckw.transport.utils.StringUtils.getWaybillNoUtil());
        logisticsOrder.setSettlementCycle(bo.getSettlementCycle());
        logisticsOrder.setPrice(new BigDecimal(bo.getPrice()));
        logisticsOrder.setPriceType(remoteSystemService.queryDictByTypeAndValue(DictTypeEnum.PRICE_TYPE.getType(), bo.getPriceType()) == null ?
                null : Long.parseLong(remoteSystemService.queryDictByTypeAndValue(DictTypeEnum.PRICE_TYPE.getType(), bo.getPriceType()).getValue()));

        if (!bo.getIsFullDose()) {
            if (ArrayUtil.isEmpty(bo.getCarryingCapacity())) {
                throw new RuntimeException("不是全量分配时,分配量不能为空!");
            }
            logisticsOrder.setAmount(new BigDecimal(bo.getCarryingCapacity()));
            logisticsOrder.setUnit(bo.getCarryingCapacityUnit());
            logisticsOrder.setCarryingCapacity(bo.getCarryingCapacity());
        } else {
            logisticsOrder.setAmount(new BigDecimal(NumberConstant.ZERO));
            logisticsOrder.setSubcontractAmount(new BigDecimal(NumberConstant.ZERO));
            logisticsOrder.setCarryingCapacity(0L);
        }
        logisticsOrder.setLoss(bo.getLoss() == null ? null : new BigDecimal(bo.getLoss()));
        logisticsOrder.setLossUnit(bo.getLossUnit());
        logisticsOrder.setGoodsPrice(bo.getGoodsPrice() == null ? null : new BigDecimal(bo.getGoodsPrice()));
        BigDecimal decimal = new BigDecimal(NumberConstant.ZERO);
        logisticsOrder.setSubcontractAmount(decimal);
        logisticsOrder.setEntrustAmount(decimal);
        logisticsOrder.setUnloadAmount(decimal);
        logisticsOrder.setLoadAmount(decimal);
        logisticsOrder.setIgnoreAmount(decimal);
        logisticsOrder.setDeficitPrice(decimal);
        logisticsOrder.setPayment(Long.parseLong(bo.getPayment()));
        logisticsOrder.setTaxRate(bo.getTaxRate() == null ? null : new BigDecimal(bo.getTaxRate()));
        logisticsOrder.setRemark(bo.getRemark());
        logisticsOrder.setEntId(LoginUserHolder.getEntId());
        logisticsOrder.setFirmName(remoteSystemService.queryEntCacheById(LoginUserHolder.getEntId()).getFirmName());
        logisticsOrder.setGoodsId(Integer.parseInt(bo.getGoodsId()));
        KwpGoods goods = goodsInfoService.getGoodsById(Long.parseLong(bo.getGoodsId()));
        logisticsOrder.setGoodsType(goods == null ? null : goods.getGoodsType());
        logisticsOrder.setGoodsSpec(goods == null ? null : goods.getSpec());
        logisticsOrder.setContractId(Integer.parseInt(bo.getContractId()));
        logisticsOrder.setContractNo(bo.getContractNo());
        logisticsOrder.setContractName(bo.getContractName());
        logisticsOrder.setContractSigningWay(bo.getPayment());
        logisticsOrder.setCheckEntId(Long.parseLong(bo.getCheckCompanyId()));
        logisticsOrder.setCheckFirmName(bo.getCheckCompany());
        logisticsOrder.setCheckContacts(bo.getCheckContacts());
        logisticsOrder.setCheckPhone(bo.getCheckContactPhone());
        logisticsOrder.setCarrierEntId(Long.parseLong(bo.getConsignCompanyId()));
        logisticsOrder.setCarrierFirmName(bo.getConsignCompany());
        logisticsOrder.setCarrierContacts(bo.getConsignContacts());
        List<AddressInfoDetail> addressInfo = tradeOrder.getAddressInfo();
        for (AddressInfoDetail detail : addressInfo) {
            if (String.valueOf(NumberConstant.ONE).equals(detail.getAddressType())) {
                logisticsOrder.setLoadType(Long.parseLong(detail.getType()));
                logisticsOrder.setLoadCityCode(detail.getCityCode());
                logisticsOrder.setLoadCityName(detail.getCityName());
                logisticsOrder.setLoadDetailAddress(detail.getDetailAddress());
                logisticsOrder.setLoadLat(detail.getLat());
                logisticsOrder.setLoadPhone(detail.getPhone());
                logisticsOrder.setLoadLng(detail.getLng());
                logisticsOrder.setLoadContacts(detail.getContacts());
            }
            if (String.valueOf(NumberConstant.TWO).equals(detail.getAddressType())) {
                logisticsOrder.setUnloadType(Long.parseLong(detail.getType()));
                logisticsOrder.setUnloadPhone(detail.getPhone());
                logisticsOrder.setUnloadCityCode(detail.getCityCode());
                logisticsOrder.setUnloadCityName(detail.getCityName());
                logisticsOrder.setUnloadDetailAddress(detail.getDetailAddress());
                logisticsOrder.setUnloadLat(detail.getLat());
                logisticsOrder.setUnloadLng(detail.getLng());
                logisticsOrder.setUnloadContacts(detail.getContacts());
            }
        }
        //TODO 生成时并无时间
//        logisticsOrder.setLoadTime();
//        logisticsOrder.setunLoadTime();
        logisticsOrder.setCreateBy(LoginUserHolder.getUserId());
        logisticsOrder.setCreateByName(LoginUserHolder.getUserName());
        logisticsOrder.setCreateTime(new Date());
        logisticsOrder.setUpdateBy(LoginUserHolder.getUserId());
        logisticsOrder.setUpdateByName(LoginUserHolder.getUserName());
        logisticsOrder.setUpdateTime(new Date());
        logisticsOrder.setGoodsPriceUnit(bo.getGoodsPriceUnit());
        logisticsOrder.setContractName(bo.getContractName());
        logisticsOrder.setBillingMode(bo.getBillingMode());
        //rabbitMq业务汇总数据发送/消费对象
        SckwBusSum busSum = new SckwBusSum();
        //业务汇总类型
        busSum.setBusSumType(BusinessTypeEnum.LOGISTICS_ORDER_TYPE.getName());
        //操作对象（1新增/2修改）
        busSum.setMethod(1);
        //业务汇总数据对象
        busSum.setObject(logisticsOrder);
        streamBridge.send("sckw-busSum", JSON.toJSONString(busSum));
    }

    /**
     * 物流订单-企业信息
     *
     * @param bo
     * @param orderId
     */
    private void insertLogisticsOrderUnit(LogisticsConsignmentParam bo, Long orderId) {
        KwtLogisticsOrderUnit checkUnit = new KwtLogisticsOrderUnit()
                .setLOrderId(orderId)
                .setId(new IdWorker(NumberConstant.ONE).nextId())
                .setUnitType(NumberConstant.ONE)
                .setFirmName(bo.getCheckCompany())
                .setRemark(bo.getRemark())
                .setEntId(Long.parseLong(bo.getCheckCompanyId()))
                .setContacts(bo.getCheckContacts())
                .setPhone(bo.getCheckContactPhone())
                .setCreateBy(LoginUserHolder.getUserId())
                .setCreateTime(new Date())
                .setUpdateBy(LoginUserHolder.getUserId())
                .setUpdateTime(new Date());
        kwtLogisticsOrderUnitMapper.insert(checkUnit);

        KwtLogisticsOrderUnit consignUnit = new KwtLogisticsOrderUnit()
                .setLOrderId(orderId)
                .setId(new IdWorker(NumberConstant.ONE).nextId())
                .setUnitType(NumberConstant.TWO)
                .setFirmName(bo.getConsignCompany())
                .setRemark(bo.getRemark())
                .setEntId(Long.parseLong(bo.getConsignCompanyId()))
                .setContacts(bo.getConsignContacts())
                .setPhone(bo.getConsignContactPhone())
                .setCreateBy(LoginUserHolder.getUserId())
                .setCreateTime(new Date())
                .setUpdateBy(LoginUserHolder.getUserId())
                .setUpdateTime(new Date());
        kwtLogisticsOrderUnitMapper.insert(consignUnit);
    }

    /**
     * 物流订单-状态
     *
     * @param bo
     * @param orderId
     */
    private void insertLogisticsOrderTrack(LogisticsConsignmentParam bo, Long orderId, Integer orderStatus) {
        KwtLogisticsOrderTrack entity = new KwtLogisticsOrderTrack();
        entity.setId(new IdWorker(NumberConstant.ONE).nextId());
        entity.setLOrderId(orderId);
        entity.setStatus(LogisticsOrderEnum.PENDING_ORDER.getCode());
        entity.setCreateTime(new Date());
        entity.setUpdateTime(new Date());
        entity.setCreateBy(LoginUserHolder.getUserId());
        entity.setUpdateBy(LoginUserHolder.getUserId());
        entity.setRemark(bo.getRemark());
        kwtLogisticsOrderTrackMapper.insert(entity);
    }

    /**
     * 物流订单-商品信息
     *
     * @param bo       页面请求数据
     * @param lOrderNo 物流订单编号
     * @param orderId  物流订单表编号
     */
    private void insertLogisticsGoods(LogisticsConsignmentParam bo, String lOrderNo, Long orderId) {
        KwtLogisticsOrderGoods kwtLogisticsOrderGoods = new KwtLogisticsOrderGoods();
        kwtLogisticsOrderGoods.setId(new IdWorker(NumberConstant.ONE).nextId());
        kwtLogisticsOrderGoods.setGoodsId(Long.parseLong(bo.getGoodsId()));
        kwtLogisticsOrderGoods.setGoodsName(bo.getGoodsName());
        kwtLogisticsOrderGoods.setSkuId(StringUtils.isBlank(bo.getSkuId()) ? null : Long.parseLong(bo.getSkuId()));
        kwtLogisticsOrderGoods.setLOrderId(orderId);
        kwtLogisticsOrderGoods.setLOrderNo(lOrderNo);
        kwtLogisticsOrderGoods.setUpdateBy(LoginUserHolder.getUserId());
        kwtLogisticsOrderGoods.setUpdateTime(new Date());
        kwtLogisticsOrderGoods.setCreateBy(LoginUserHolder.getUserId());
        kwtLogisticsOrderGoods.setCreateTime(new Date());
        kwtLogisticsOrderGoodsMapper.insert(kwtLogisticsOrderGoods);
    }

    /**
     * 物流订单-主体
     *
     * @param bo          页面请求参数
     * @param lOrderNo    物流订单编号
     * @param order       物流订单数据
     * @param tradeOrder  贸易订单数据
     * @param orderId     物流订单id
     * @param orderStatus 物流订单状态
     */
    private void insertLogisticsOrder(LogisticsConsignmentParam bo, String lOrderNo, KwtLogisticsOrder order, OrderDetailRes tradeOrder, Long orderId, Integer orderStatus) {
        order.setId(orderId);
        order.setEntId(LoginUserHolder.getEntId());
        order.setTOrderId(Long.parseLong(bo.getTOrderId()));
        order.setTOrderNo(bo.getTOrderNo());
        order.setLOrderNo(lOrderNo);
        order.setPid(null);
        order.setPids(orderId + StringConstant.COMMA);
        order.setSettlementCycle(bo.getSettlementCycle());
        order.setPrice(new BigDecimal(bo.getPrice()));
        order.setPriceType(remoteSystemService.queryDictByTypeAndValue(DictTypeEnum.PRICE_TYPE.getType(), bo.getPriceType()) == null ?
                null : Long.parseLong(remoteSystemService.queryDictByTypeAndValue(DictTypeEnum.PRICE_TYPE.getType(), bo.getPriceType()).getValue()));
        order.setAmount(tradeOrder.getAmount());
        order.setBillingMode(bo.getBillingMode());
        order.setUnit(bo.getCarryingCapacityUnit());
        order.setLoss(new BigDecimal(bo.getLoss()));
        order.setLossUnit(bo.getLossUnit());
        order.setLossUnit(remoteSystemService.queryDictByTypeAndValue(DictTypeEnum.UNIT_TYPE.getType(), bo.getLossUnit()) == null ?
                null : remoteSystemService.queryDictByTypeAndValue(DictTypeEnum.UNIT_TYPE.getType(), bo.getLossUnit()).getValue());
        order.setGoodsPrice(new BigDecimal(bo.getGoodsPrice()));
        order.setGoodsPriceUnit(remoteSystemService.queryDictByTypeAndValue(DictTypeEnum.PRICE_TYPE.getType(), bo.getGoodsPriceUnit()) == null ?
                null : remoteSystemService.queryDictByTypeAndValue(DictTypeEnum.PRICE_TYPE.getType(), bo.getGoodsPriceUnit()).getValue());
        order.setGoodsPriceUnit(bo.getGoodsPriceUnit());
        order.setStartTime(bo.getShipmentsDateTime());
        order.setEndTime(bo.getReceiveGoodsDateTime());
        order.setRemark(bo.getRemark());
        order.setPayment(Long.parseLong(tradeOrder.getTrading()));
        order.setTaxRate(new BigDecimal(bo.getTaxRate()));
        order.setCreateBy(LoginUserHolder.getUserId());
        order.setCreateTime(new Date());
        order.setUpdateBy(LoginUserHolder.getUserId());
        order.setUpdateTime(new Date());
        order.setStatus(orderStatus);
        BigDecimal decimal = new BigDecimal(NumberConstant.ZERO);
        /**补充默认值*/
        order.setEntrustAmount(decimal);
        order.setSubcontractAmount(decimal);
        order.setLoadAmount(decimal);
        order.setUnloadAmount(decimal);
        order.setIgnoreAmount(decimal);
        order.setDeficitPrice(decimal);
        order.setDeficitAmount(decimal);
        kwtLogisticsOrderMapper.insert(order);
    }

    /**
     * 物流订单-合同
     *
     * @param bo
     */
    private void insertLogisticsOrderContract(LogisticsConsignmentParam bo, Long orderId) {
        KwtLogisticsOrderContract kwtLogisticsOrderContract = new KwtLogisticsOrderContract();
        kwtLogisticsOrderContract.setId(new IdWorker(NumberConstant.ONE).nextId());
        kwtLogisticsOrderContract.setLOrderId(orderId);
        kwtLogisticsOrderContract.setContractId(Long.parseLong(bo.getContractId()));
        kwtLogisticsOrderContract.setRemark(bo.getRemark());
        kwtLogisticsOrderContract.setCreateBy(LoginUserHolder.getUserId());
        kwtLogisticsOrderContract.setUpdateBy(LoginUserHolder.getUserId());
        kwtLogisticsOrderContract.setCreateTime(new Date());
        kwtLogisticsOrderContract.setUpdateTime(new Date());
        kwtLogisticsOrderContractMapper.insert(kwtLogisticsOrderContract);
    }

    /**
     * 物流订单-装卸货地址
     *
     * @param bo
     * @param orderId
     */
    private void insertLogisticsOrderAddress(LogisticsConsignmentParam bo, Long orderId) {
        KwtLogisticsOrderAddress loadOrderAddress = new KwtLogisticsOrderAddress();
        KwtLogisticsOrderAddress unloadOrderAddress = new KwtLogisticsOrderAddress();
        //todo 装卸货地址 通过dubbo查询
        OrderDetailRes orderDetailRes = tradeOrderInfoService.getOrderDetailById(Long.parseLong(bo.getTOrderId()));
        if (ObjectUtils.isEmpty(orderDetailRes)) {
            log.info("dubbp 查询数据 error :orderId:{}", bo.getTOrderId());
            throw new RuntimeException("dubbp 查询销售订单数据查找失败!");
        }
        List<AddressInfoDetail> addressInfo = orderDetailRes.getAddressInfo();
        if (CollectionUtils.isNotEmpty(addressInfo)) {
            for (AddressInfoDetail detail : addressInfo) {
                if (String.valueOf(NumberConstant.ONE).equals(detail.getAddressType())) {
                    loadOrderAddress.setId(new IdWorker(NumberConstant.ONE).nextId());
                    loadOrderAddress.setAddressType(NumberConstant.ONE);
                    loadOrderAddress.setDetailAddress(detail.getDetailAddress());
                    loadOrderAddress.setContacts(detail.getContacts());
                    loadOrderAddress.setLOrderId(orderId);
                    loadOrderAddress.setLat(detail.getLat());
                    loadOrderAddress.setFence(detail.getFence());
                    loadOrderAddress.setCityName(detail.getCityName());
                    loadOrderAddress.setEntryType(NumberConstant.FOUR);
                    loadOrderAddress.setCreateTime(new Date());
                    loadOrderAddress.setPhone(detail.getPhone());
                    loadOrderAddress.setCreateBy(LoginUserHolder.getUserId());
                    loadOrderAddress.setUpdateBy(LoginUserHolder.getUserId());
                    loadOrderAddress.setUpdateTime(new Date());
                }
                if (String.valueOf(NumberConstant.TWO).equals(detail.getAddressType())) {
                    unloadOrderAddress.setId(new IdWorker(NumberConstant.ONE).nextId());
                    unloadOrderAddress.setAddressType(NumberConstant.TWO);
                    unloadOrderAddress.setId(new IdWorker(NumberConstant.ONE).nextId());
                    unloadOrderAddress.setContacts(detail.getContacts());
                    unloadOrderAddress.setLOrderId(orderId);
                    unloadOrderAddress.setLat(detail.getLat());
                    unloadOrderAddress.setFence(detail.getFence());
                    unloadOrderAddress.setCityName(detail.getCityName());
                    unloadOrderAddress.setEntryType(NumberConstant.FOUR);
                    unloadOrderAddress.setPhone(detail.getPhone());
                    unloadOrderAddress.setDetailAddress(detail.getDetailAddress());
                    unloadOrderAddress.setCreateTime(new Date());
                    unloadOrderAddress.setCreateBy(LoginUserHolder.getUserId());
                    unloadOrderAddress.setUpdateBy(LoginUserHolder.getUserId());
                    unloadOrderAddress.setUpdateTime(new Date());
                }
            }
        }

        kwtLogisticsOrderAddressMapper.insert(loadOrderAddress);
        kwtLogisticsOrderAddressMapper.insert(unloadOrderAddress);
    }

    /**
     * @param id
     * @param page
     * @param pageSize
     * @return
     */
    public HttpResult purchaseLogisticsOrder(String id, Integer page, Integer pageSize) {
        Long count = getLogisticsOrderCount(id);
        Integer newPage = page - 1;
        List<LogisticsOrderDTO> list = getLogisticsOrderData(id, newPage, pageSize);
        PageResult build = PageResult.build(page, pageSize, count, list);
        return HttpResult.ok(build);
    }

    private Long getLogisticsOrderCount(String id) {
        return kwtLogisticsOrderMapper.selectOrderCount(id);
    }

    /**
     * 销售订单-采购订单-获取托运订单数据
     *
     * @param id       销售订单id
     * @param page
     * @param pageSize
     * @return
     */
    public HttpResult logisticsOrder(String id, Integer page, Integer pageSize) {
        HttpResult httpResult = new HttpResult();
        OrderDetailRes orderDetailRes = tradeOrderInfoService.getOrderDetailById(Long.parseLong(id));
        /**根据下单方式（代客下单/自主下单）决定托运数据是否展示*/
        boolean flag = false;
        if (String.valueOf(NumberConstant.ONE).equals(orderDetailRes.getSource())) {
            flag = true;
        } else if (String.valueOf(NumberConstant.TWO).equals(orderDetailRes.getSource())) {
            flag = true;
        } else {
            throw new RuntimeException("获取贸易订单下单方式异常!");
        }
        BigDecimal resAmount = orderDetailRes.getAmount();
        if (flag) {
            /**数据展示*/
            //总数
            Long count = getLogisticsOrderCount(id);
            Integer newPage = page - 1;
            List<LogisticsOrderDTO> list = getLogisticsOrderData(id, newPage, pageSize);
            PageResult build = PageResult.build(page, pageSize, count, list);
            /**数据统计*/
            //计划量
            BigDecimal amount = new BigDecimal(NumberConstant.ZERO);
            for (LogisticsOrderDTO logisticsOrderDTO : list) {
                amount = amount.add(logisticsOrderDTO.getAmount() == null ? new BigDecimal(NumberConstant.ZERO) : logisticsOrderDTO.getAmount());
            }
            //剩余调度量
            BigDecimal residue = resAmount.subtract(amount);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("count", count);
            jsonObject.put("residue", residue);
            jsonObject.put("amount", amount);
            Map<String, Object> map = new HashMap<>(NumberConstant.SIXTEEN);
            map.put("dataList", build);
            map.put("TableBottom", jsonObject);
            httpResult.setData(map);
        }
        return httpResult;
    }

    /**
     * @param id
     * @param page
     * @param pageSize
     * @return
     */
    private List<LogisticsOrderDTO> getLogisticsOrderData(String id, Integer page, Integer pageSize) {
        List<LogisticsOrderDTO> list = kwtLogisticsOrderMapper.selectOrderList(id, page, pageSize);
        return list;
    }

    /**
     * 采购订单获取车辆信息
     *
     * @param id
     * @param page
     * @param pageSize
     * @return
     */
    public HttpResult purchaseLogisticsCar(String id, Integer page, Integer pageSize) {
        Long count = getLogisticsCarDataCount(id);
        Integer newPage = page - 1;
        List<OrderCarDTO> list = getLogisticsCarData(id, newPage, pageSize);
        PageResult build = PageResult.build(page, pageSize, count, list);
        return HttpResult.ok(build);
    }

    /**
     * 销售订单获取车辆信息
     *
     * @param id
     * @param page
     * @param pageSize
     * @return
     */
    public HttpResult sellLogisticsCar(String id, Integer page, Integer pageSize) {
        Long count = getLogisticsCarDataCount(id);
        Integer newPage = page - 1;
        List<OrderCarDTO> list = getLogisticsCarData(id, newPage, pageSize);
        PageResult build = PageResult.build(page, pageSize, count, list);
        return HttpResult.ok(build);
    }

    private Long getLogisticsCarDataCount(String id) {
        return waybillOrderMapper.selectWaybillOrderCarCount(id);
    }

    private List<OrderCarDTO> getLogisticsCarData(String id, Integer page, Integer pageSize) {
        List<OrderCarDTO> list = waybillOrderMapper.selectWaybillOrderCarList(id, page, pageSize);
        return list;
    }

    /**
     * 采购订单/销售订单-托运订单列表-撤销托运
     *
     * @param ids  物流订单id
     * @param type 单据操作类型
     * @return
     */
    public HttpResult cancelConsign(List<String> ids, String type) {
        if (CollectionUtils.isEmpty(ids) || ids.size() < NumberConstant.ONE) {
            throw new RuntimeException("单据id不能为空");
        }
        List<JSONObject> list = new ArrayList<>();
        //1采购 2销售
        if (String.valueOf(NumberConstant.ONE).equals(type)) {
            cancelConsignByOrder(ids, list);
        } else if (String.valueOf(NumberConstant.TWO).equals(type)) {
            cancelConsignBySellOrder(ids, list);
        } else {
            throw new RuntimeException("类型错误!");
        }
        return HttpResult.ok(list);
    }

    /**
     * 销售订单撤销托运
     *
     * @param ids
     */
    private void cancelConsignBySellOrder(List<String> ids, List<JSONObject> list) {
        ids.forEach(s -> {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("id", s);
            /**当前单据作废
             * 托运数量回归溯
             */
            KwtLogisticsOrder kwtLogisticsOrder = kwtLogisticsOrderMapper.selectOne(new LambdaUpdateWrapper<KwtLogisticsOrder>()
                    .eq(KwtLogisticsOrder::getId, s));
            if (kwtLogisticsOrder == null || (!String.valueOf(LogisticsOrderEnum.PENDING_ORDER.getCode()).equals(kwtLogisticsOrder.getStatus()))) {
                log.info("物流订单单据id:{}", s);
                jsonObject.put("message", "单据状态异常或单据不存在");
                jsonObject.put("status", HttpStatus.GLOBAL_EXCEPTION_CODE);
            } else {
                OrderDetailRes orderDetailRes = tradeOrderInfoService.getOrderDetailById(Long.parseLong(s));
                UpdateOrderAmountParam param = new UpdateOrderAmountParam();
                param.setTOrderId(Long.parseLong(s));
                param.setActualAmount(orderDetailRes.getActualAmount().add(kwtLogisticsOrder.getLoadAmount()));
                param.setEntrustAmount(orderDetailRes.getEntrustAmount().add(kwtLogisticsOrder.getEntrustAmount().subtract(kwtLogisticsOrder.getLoadAmount())));
                tradeOrderInfoService.updateOrderAmount(param);
                kwtLogisticsOrder.setDelFlag(1);
                kwtLogisticsOrder.setUpdateTime(new Date());
                kwtLogisticsOrder.setUpdateBy(LoginUserHolder.getUserId());
                kwtLogisticsOrderMapper.update(null, new LambdaUpdateWrapper<KwtLogisticsOrder>()
                        .eq(KwtLogisticsOrder::getId, kwtLogisticsOrder.getId())
                        .set(KwtLogisticsOrder::getDelFlag, NumberConstant.ONE)
                        .set(KwtLogisticsOrder::getUpdateBy, LoginUserHolder.getUserId())
                        .set(KwtLogisticsOrder::getUpdateTime, new Date()));
                jsonObject.put("status", HttpStatus.SUCCESS_CODE);
            }
            list.add(jsonObject);
        });
    }

    /**
     * 采购订单撤销托运
     *
     * @param ids
     */
    private void cancelConsignByOrder(List<String> ids, List<JSONObject> list) {
        ids.forEach(s -> {
            /**当前单据作废
             * 托运数量回归溯源
             */
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("id", s);
            /**当前单据作废
             * 托运数量回归溯
             */
            KwtLogisticsOrder kwtLogisticsOrder = kwtLogisticsOrderMapper.selectOne(new LambdaUpdateWrapper<KwtLogisticsOrder>()
                    .eq(KwtLogisticsOrder::getId, s));
            if (kwtLogisticsOrder == null || (!LogisticsOrderEnum.PENDING_ORDER.getStatus().equals(String.valueOf(kwtLogisticsOrder.getStatus())))) {
                log.info("物流订单单据id:{}", s);
                jsonObject.put("message", "单据状态异常或单据不存在");
                jsonObject.put("status", HttpStatus.GLOBAL_EXCEPTION_CODE);
            } else {
                OrderDetailRes orderDetailRes = tradeOrderInfoService.getOrderDetailById(Long.parseLong(s));
                UpdateOrderAmountParam param = new UpdateOrderAmountParam();
                param.setTOrderId(Long.parseLong(s));
                param.setActualAmount(orderDetailRes.getActualAmount().add(kwtLogisticsOrder.getLoadAmount()));
                param.setEntrustAmount(orderDetailRes.getEntrustAmount().add(kwtLogisticsOrder.getEntrustAmount().subtract(kwtLogisticsOrder.getLoadAmount())));
                tradeOrderInfoService.updateOrderAmount(param);
                kwtLogisticsOrder.setDelFlag(1);
                kwtLogisticsOrder.setUpdateTime(new Date());
                kwtLogisticsOrder.setUpdateBy(LoginUserHolder.getUserId());
                kwtLogisticsOrderMapper.update(null, new LambdaUpdateWrapper<KwtLogisticsOrder>()
                        .eq(KwtLogisticsOrder::getId, kwtLogisticsOrder.getId())
                        .set(KwtLogisticsOrder::getDelFlag, NumberConstant.ONE)
                        .set(KwtLogisticsOrder::getUpdateBy, LoginUserHolder.getUserId())
                        .set(KwtLogisticsOrder::getUpdateTime, new Date()));
                jsonObject.put("status", HttpStatus.SUCCESS_CODE);
            }
            list.add(jsonObject);
        });
    }

    /**
     * 采购订单/销售订单-完结订单
     *
     * @param orderFinishDTO 数据dto
     * @param type           类型
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public HttpResult orderFinish(OrderFinishDTO orderFinishDTO, String type) {
        HttpResult httpResult = ValidUtil.serviceValid(orderFinishDTO);
        if (!String.valueOf(httpResult.getCode()).equals(String.valueOf(HttpStatus.SUCCESS_CODE))) {
            return HttpResult.error(httpResult.getMsg());
        }
        //1采购 2销售
        if (String.valueOf(NumberConstant.ONE).equals(type)) {
            purchaseOrderFinish(orderFinishDTO);
        } else if (String.valueOf(NumberConstant.TWO).equals(type)) {
            sellOrderFinish(orderFinishDTO);
        } else {
            throw new RuntimeException("完结订单-单据类型异常!");
        }
        return HttpResult.ok("完结订单-成功");
    }

    /**
     * 销售订单-完结订单
     *
     * @param orderFinishDTO
     */
    private void sellOrderFinish(OrderFinishDTO orderFinishDTO) {
        purchaseOrderFinish(orderFinishDTO);
    }

    /**
     * 采购订单-完结订单
     *
     * @param orderFinishDTO
     */
    private void purchaseOrderFinish(OrderFinishDTO orderFinishDTO) {
        /** 订单完结 物流运单状态为【待派车】、【运输中】可操作*/
        /**完结拦截 必须车辆运单无正在运输中的单据才能完结 状态有 待接单之后已核弹之前的状态 都不能完结*/
        /**完结订单-对应物流订单下子订单都要进行完结*/
        /**完结订单 不做页面填写数量与数据库数量进行计算验证-直接获取页面填写数据进行保存处理*/
        //物流订单id
        String id = orderFinishDTO.getId();
        KwtLogisticsOrder logisticsOrder = kwtLogisticsOrderMapper.selectOne(new LambdaQueryWrapper<KwtLogisticsOrder>()
                .eq(KwtLogisticsOrder::getId, id));
        if (logisticsOrder == null) {
            throw new RuntimeException("采购订单-完结订单-物流单据不存在!");
        }
        /**订单状态验证*/
        if (!LogisticsOrderEnum.WAIT_DELIVERY.getStatus().equals(String.valueOf(logisticsOrder.getStatus()))
                && !LogisticsOrderEnum.IN_TRANSIT.getStatus().equals(String.valueOf(logisticsOrder.getStatus()))) {
            throw new RuntimeException("当前运单并不属于【待派车】,【运输中】状态");
        }
        /**完结拦截*/
        List<Integer> statusList = new ArrayList<>();
        statusList.add(CarWaybillEnum.PENDING_VEHICLE.getCode());
        statusList.add(CarWaybillEnum.EXIT_COMPLETED.getCode());
        statusList.add(CarWaybillEnum.WAIT_LOADING.getCode());
        statusList.add(CarWaybillEnum.COMPLETION_LOADING.getCode());
        statusList.add(CarWaybillEnum.WAIT_UNLOADING.getCode());
        statusList.add(CarWaybillEnum.COMPLETION_UNLOADING.getCode());
        int count = waybillOrderMapper.selectDataByLorderId(id, statusList);
        if (count > NumberConstant.ZERO) {
            throw new RuntimeException("检测您现在有运单正在执行中,该订单目前不可完结,请先将运单执行完毕");
        }
        /**完结订单-对应物流订单下子订单都要进行完结*/
        List<KwtLogisticsOrder> kwtLogisticsOrders = kwtLogisticsOrderMapper.selectList(new LambdaQueryWrapper<KwtLogisticsOrder>()
                .in(KwtLogisticsOrder::getPids, Long.parseLong(orderFinishDTO.getId())));
        if (CollectionUtils.isNotEmpty(kwtLogisticsOrders)) {
            for (KwtLogisticsOrder kwtLogisticsOrder : kwtLogisticsOrders) {
                String[] split = kwtLogisticsOrder.getPids().split(StringConstant.COMMA);
                if (split.length > NumberConstant.ONE) {
                    for (String s : split) {
                        if (String.valueOf(kwtLogisticsOrder.getId()).equals(s)) {
                            //本身订单
                            //只存在当前订单无分包订单
                            /**单据完结修改状态以及数据*/
                            updateDataByItself(logisticsOrder, orderFinishDTO);
                        } else {
                            //修改分包后的订单-代表存在分包订单
                            /**单据完结修改状态以及数据*/
                            updateDataBySubset(orderFinishDTO, s);
                        }
                    }
                } else {
                    //只存在当前订单无分包订单
                    /**单据完结修改状态以及数据*/
                    updateDataByItself(logisticsOrder, orderFinishDTO);
                }
            }
        }
    }

    private void updateDataBySubset(OrderFinishDTO orderFinishDTO, String orderId) {
        KwtLogisticsOrder kwtLogisticsOrder = kwtLogisticsOrderMapper.selectOne(new LambdaQueryWrapper<KwtLogisticsOrder>()
                .eq(KwtLogisticsOrder::getId, Long.parseLong(orderId)));
        if (kwtLogisticsOrder != null) {
            kwtLogisticsOrder.setStatus(LogisticsOrderEnum.HAVE_FINISHED.getCode());
            kwtLogisticsOrder.setUpdateBy(LoginUserHolder.getUserId());
            kwtLogisticsOrder.setUpdateTime(new Date());
            kwtLogisticsOrder.setRemark(orderFinishDTO.getRemark());
            kwtLogisticsOrderMapper.updateById(kwtLogisticsOrder);
            KwtLogisticsOrderTrack track = new KwtLogisticsOrderTrack();
            track.setId(new IdWorker(NumberConstant.ONE).nextId());
            track.setLOrderId(kwtLogisticsOrder.getId());
            track.setStatus(LogisticsOrderEnum.HAVE_FINISHED.getCode());
            track.setCreateTime(new Date());
            track.setRemark(orderFinishDTO.getRemark());
            track.setCreateBy(LoginUserHolder.getUserId());
            track.setUpdateBy(LoginUserHolder.getUserId());
            track.setUpdateTime(new Date());
            kwtLogisticsOrderTrackMapper.insert(track);
            /**单据完结修改Mongodb*/
            SckwLogisticsOrder updateParam = new SckwLogisticsOrder();
            updateParam.setLOrderId(kwtLogisticsOrder.getId())
                    .setStatus(LogisticsOrderEnum.HAVE_FINISHED.getStatus())
                    .setUpdateBy(LoginUserHolder.getUserId())
                    .setUpdateByName(LoginUserHolder.getUserName())
                    .setUpdateTime(new Date())
            ;
            SckwBusSum busSum = new SckwBusSum();
            busSum.setBusSumType(BusinessTypeEnum.LOGISTICS_ORDER_TYPE.getName());
            busSum.setMethod(2);
            busSum.setObject(updateParam);
            streamBridge.send("sckw-busSum", com.alibaba.fastjson2.JSON.toJSONString(busSum));
        }
    }

    /**
     * 完结订单-修改本身数据
     */
    private void updateDataByItself(KwtLogisticsOrder logisticsOrder, OrderFinishDTO orderFinishDTO) {
        logisticsOrder.setStatus(LogisticsOrderEnum.HAVE_FINISHED.getCode());
        logisticsOrder.setLoadAmount(orderFinishDTO.getLoadAmount());
        logisticsOrder.setUnloadAmount(orderFinishDTO.getUnloadAmount());
        logisticsOrder.setUpdateBy(LoginUserHolder.getUserId());
        logisticsOrder.setUpdateTime(new Date());
        logisticsOrder.setRemark(orderFinishDTO.getRemark());
        kwtLogisticsOrderMapper.updateById(logisticsOrder);
        KwtLogisticsOrderTrack track = new KwtLogisticsOrderTrack();
        track.setId(new IdWorker(NumberConstant.ONE).nextId());
        track.setLOrderId(logisticsOrder.getId());
        track.setStatus(LogisticsOrderEnum.HAVE_FINISHED.getCode());
        track.setCreateTime(new Date());
        track.setRemark(orderFinishDTO.getRemark());
        track.setCreateBy(LoginUserHolder.getUserId());
        track.setUpdateBy(LoginUserHolder.getUserId());
        track.setUpdateTime(new Date());
        kwtLogisticsOrderTrackMapper.insert(track);
        /**单据完结修改Mongodb*/
        SckwLogisticsOrder updateParam = new SckwLogisticsOrder();
        updateParam.setLOrderId(Long.parseLong(orderFinishDTO.getId()))
                .setStatus(LogisticsOrderEnum.HAVE_FINISHED.getStatus())
                .setUpdateBy(LoginUserHolder.getUserId())
                .setUpdateByName(LoginUserHolder.getUserName())
                .setUpdateTime(new Date())
                .setLoadAmount(orderFinishDTO.getLoadAmount())
                .setUnloadAmount(orderFinishDTO.getUnloadAmount())
        ;
        SckwBusSum busSum = new SckwBusSum();
        busSum.setBusSumType(BusinessTypeEnum.LOGISTICS_ORDER_TYPE.getName());
        busSum.setMethod(2);
        busSum.setObject(updateParam);
        streamBridge.send("sckw-busSum", com.alibaba.fastjson2.JSON.toJSONString(busSum));
    }

    /**
     * 采购订单/销售订单-托运订单列表-订单完结-数据查询
     *
     * @param orderId 物流订单id
     * @param type    1采购订单2销售订单
     * @return
     */
    public HttpResult selectOrderFinishVo(String orderId, String type) {
        HttpResult httpResult = new HttpResult();
        httpResult.setCode(HttpStatus.SUCCESS_CODE);
        if (String.valueOf(NumberConstant.ONE).equals(type)) {
            httpResult = selectOrderFinishData(orderId);
        } else if (String.valueOf(NumberConstant.TWO).equals(type)) {
            httpResult = selectOrderFinishData(orderId);
        } else {
            httpResult.setCode(HttpStatus.SUCCESS_CODE);
            httpResult.setMsg("订单完结查询,类型错误！");
        }
        return httpResult;
    }

    /**
     * 采购订单/销售订单-托运订单列表-订单完结-数据查询
     *
     * @param orderId 物流订单id
     * @return
     */
    private HttpResult selectOrderFinishData(String orderId) {
        HttpResult httpResult = new HttpResult();
        OrderFinishVO orderFinishVO = kwtLogisticsOrderMapper.selectOrderFinishData(orderId);
        httpResult.setData(orderFinishVO);
        return httpResult;
    }
}
