package com.clx.performance.service.impl;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.clx.open.sdk.callback.OpenCallBackClient;
import com.clx.open.sdk.callback.message.OrderInfoMessage;
import com.clx.open.sdk.callback.message.TransportExceptionReportMessage;
import com.clx.order.enums.SyncPlatformEnum;
import com.clx.order.feign.InternalReportRouteExceptionFeign;
import com.clx.order.feign.OrderFeign;
import com.clx.order.param.feign.InternalReportRouteExceptionParam;
import com.clx.order.vo.feign.*;
import com.clx.performance.config.ThirdAppConfig;
import com.clx.performance.dao.OrderChildDao;
import com.clx.performance.dao.OrderGoodsDao;
import com.clx.performance.dao.PerformanceProgressDao;
import com.clx.performance.dao.PerformanceProgressLogDao;
import com.clx.performance.dto.gd.GdRouteDTO;
import com.clx.performance.enums.*;
import com.clx.performance.extranal.user.AddressService;
import com.clx.performance.extranal.user.OrderService;
import com.clx.performance.model.OrderChild;
import com.clx.performance.model.OrderGoods;
import com.clx.performance.model.PerformanceProgress;
import com.clx.performance.model.PerformanceProgressLog;
import com.clx.performance.param.pc.carrier.PagePerformanceProgress;
import com.clx.performance.param.pc.carrier.UpdatePerformanceProgressParam;
import com.clx.performance.service.OrderGoodsService;
import com.clx.performance.service.PerformanceProgressLogService;
import com.clx.performance.service.PerformanceProgressService;
import com.clx.performance.struct.PerformanceProgressLogStruct;
import com.clx.performance.struct.PerformanceProgressStruct;
import com.clx.performance.struct.export.ExportFieldStruct;
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.utils.gd.GdService;
import com.clx.performance.vo.pc.PerformanceProgressDetailVO;
import com.clx.performance.vo.pc.PerformanceProgressOperationLogVO;
import com.clx.performance.vo.pc.PerformanceProgressVO;
import com.clx.performance.vo.pc.export.ExportFieldVo;
import com.google.common.base.Joiner;
import com.msl.common.base.Optional;
import com.msl.common.exception.ServiceSystemException;
import com.msl.common.result.Result;
import com.msl.common.utils.DateUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.clx.performance.dao.export.ExportFieldDao;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author kavin
 * Date 2024-07-12
 * Time 16:02
 */
@Service
@Slf4j
@AllArgsConstructor
public class PerformanceProgressServiceImpl  implements PerformanceProgressService {


    private static final String TEMPLATE_PERFORMANCE_PROGRESS = "performance_progress";
    private final PerformanceProgressDao performanceProgressDao;
    private final PerformanceProgressStruct performanceProgressStruct;
    private final PerformanceProgressLogDao performanceProgressLogDao;
    private final PerformanceProgressLogStruct performanceProgressLogStruct;
    private final PerformanceProgressLogService performanceProgressLogService;
    private final AddressService addressService;
    private final GdService gdService;
    private final OrderGoodsDao orderGoodsDao;
    private final OrderChildDao orderChildDao;
    private final OrderService orderService;
    private final ThirdAppConfig thirdAppConfig;
    private final OrderFeign orderFeign;
    private final OrderGoodsService orderGoodsService;
    public static List<Integer> inProcessStatusList;
    public static List<Integer> endStatusList ;
    public static List<Integer> allStatusList ;
    private final ExportFieldStruct exportFieldStruct;
    private final ExportFieldDao exportFieldDao;
    private final InternalReportRouteExceptionFeign internalReportRouteExceptionFeign;

    static {
       inProcessStatusList = Arrays.asList(
                OrderEnum.Status.PLATFORM_UNDERTAKING.getCode(),
                OrderEnum.Status.SUSPEND.getCode(),
                OrderEnum.Status.ON_ORDER.getCode(),
                OrderEnum.Status.IN_TRANSIT.getCode());

        endStatusList = Arrays.asList(
                OrderEnum.Status.SUCCESS.getCode(),
                OrderEnum.Status.COMPLETED.getCode());


        allStatusList = Arrays.asList(
                OrderEnum.Status.PLATFORM_UNDERTAKING.getCode(),
                OrderEnum.Status.SUSPEND.getCode(),
                OrderEnum.Status.ON_ORDER.getCode(),
                OrderEnum.Status.IN_TRANSIT.getCode(),
                OrderEnum.Status.SUCCESS.getCode(),
                OrderEnum.Status.COMPLETED.getCode());

    }


    @Override
    public IPage<PerformanceProgressVO> pagePerformanceProgress(PagePerformanceProgress param) {

        IPage<PerformanceProgress> page = new Page<>();
        IPage<PerformanceProgressVO> returnPage = new Page<>();


        if(Objects.equals(param.getTab(), PerformanceProgressEnum.Tab.IN_PROCESS.getCode())){
            param.setPage(1);
            param.setPageSize(10000);
            page =  performanceProgressDao.pagePerformanceProgress(inProcessStatusList,param);

        }else if(Objects.equals(param.getTab(), PerformanceProgressEnum.Tab.END.getCode())){
            page =  performanceProgressDao.pagePerformanceProgress(endStatusList,param);

        }else if(Objects.equals(param.getTab(), PerformanceProgressEnum.Tab.ALL.getCode())){
            page =  performanceProgressDao.pagePerformanceProgress(allStatusList,param);

        }
        if(CollectionUtils.isEmpty(page.getRecords())){
            return returnPage;
        }

        List<PerformanceProgressVO> records = performanceProgressStruct.convertList(page.getRecords());

        // 筛选出OrderNo集合
        List<String> orderNoList = records.stream().map(PerformanceProgressVO::getOrderNo).collect(Collectors.toList());
        // 获取内部线路异常信息Map集合
        Map<String, String> internalReportRouteExceptionMap = this.getInternalReportRouteException(orderNoList);

        records.forEach(item->{
                    if(StringUtils.isNotBlank(item.getSeniorLogisticsManagerName())){
                        item.setSeniorLogisticsManagerName(Joiner.on(",")
                                .join(JSON.parseArray(item.getSeniorLogisticsManagerName())));
                    }
                    if(Objects.nonNull(item.getPendingWeight())
                            && item.getPendingWeight().compareTo(BigDecimal.ZERO) != 0
                            && Objects.nonNull(item.getOrderedWeight())
                            && item.getOrderedWeight().compareTo(BigDecimal.ZERO) != 0){
                        item.setOrderedRate(calcOrderedRate(item.getOrderedWeight(),item.getPendingWeight()));
                    }
                    if(Objects.nonNull(item.getTaskWeight()) && item.getTaskWeight().compareTo(BigDecimal.ZERO) >0
                            && Objects.nonNull(item.getSumUnloadWeight())){
                        //任务完成率 =  到站量 / 任务量
                        BigDecimal taskCompleteRatio =  item.getSumUnloadWeight()
                                .divide(item.getTaskWeight(),
                                        3, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
                        item.setTaskCompleteRatio(taskCompleteRatio);
                    }
                    // 通过订单关联订单异常上报信息
                    if(StringUtils.isNotBlank(item.getOrderNo())
                            && internalReportRouteExceptionMap.containsKey(item.getOrderNo()) ) {
                        // 履约进度表中异常备注同步该订单的内部【异常上报】信息，多次上报与编辑中的异常备注间，用”/“进行分割
                        // 拼接远程调用的异常信息
                        StringBuilder stringBuilder = new StringBuilder();
                        if (StringUtils.isNotBlank(item.getAbnormalRemark())) {
                            stringBuilder.append(item.getAbnormalRemark())
                                    .append("/")
                                    .append(internalReportRouteExceptionMap.get(item.getOrderNo()));
                        } else {
                            stringBuilder.append(internalReportRouteExceptionMap.get(item.getOrderNo()));
                        }
                        // 赋值异常备注
                        item.setAbnormalRemark(stringBuilder.toString());
                    }
                }
        );

        returnPage.setPages(page.getPages());
        returnPage.setTotal(page.getTotal());
        returnPage.setRecords(records);


        //如果查询的是 已结束线路,则不需要计算，直接返回
        if(Objects.equals(param.getTab(), PerformanceProgressEnum.Tab.END.getCode())){
            return returnPage;
        }

        returnPage.getRecords().forEach(item ->{
            //TODO  进行订单运费预估调用  开发批量调用的接口。 订单完结完成后把运费预估查询出来的数据存入到数据库，后续不再实时查询
            if(inProcessStatusList.contains(item.getOrderStatus())){  //进行中的订单线路

            }
        });

        return returnPage;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateAdjustOrder(Integer adjustOrderId, Integer adjustOrderBeforeId) {
        Optional<PerformanceProgress> one = performanceProgressDao.getEntityByKey(adjustOrderId);
        //如果上调，这条记录传的是移动数据后面的记录id，如果下调，这条记录传的是移动数据前面的记录id
        Optional<PerformanceProgress> two = performanceProgressDao.getEntityByKey(adjustOrderBeforeId);
        if(!one.isPresent() || !two.isPresent()){
            throw new ServiceSystemException(ResultEnum.DATA_NOT_FIND);
        }
        boolean isUp = false;
        //通过seq判断是上调还是下调
        if(one.get().getSeq()  <  two.get().getSeq()){
            isUp = true;
        }
        //上调：大于two 这条记录的seq + 1 ； 下调：大于等于two这条记录的seq + 1 ;
        performanceProgressDao.updateRecordOrder(two.get().getSeq(),isUp);
        if(isUp){   //上调
            //调整的记录使用 two 的seq + 1;
            PerformanceProgress updateOne = new PerformanceProgress();
            updateOne.setId(one.get().getId());
            updateOne.setSeq(two.get().getSeq() + 1);
            performanceProgressDao.updateEntityByKey(updateOne);
        }else{    //下调
            //调整的记录使用 two 的seq;
            PerformanceProgress updateOne = new PerformanceProgress();
            updateOne.setId(one.get().getId());
            updateOne.setSeq(two.get().getSeq());
            performanceProgressDao.updateEntityByKey(updateOne);
        }
    }

    //通过dts监听订单、货单、运单表进行更新履约进度表的数据
    @Override
    public void saveOrUpdatePerformanceProgress(PerformanceProgress item) {
        Optional<PerformanceProgress> optional = performanceProgressDao.getOneByField(PerformanceProgress::getOrderNo,
                item.getOrderNo());
        if(optional.isPresent()){
            item.setId(optional.get().getId());
            performanceProgressDao.updateEntityByKey(item);
        }else{
            performanceProgressDao.saveEntity(item);
        }
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updatePerformanceProgress(UpdatePerformanceProgressParam param, Long userNo, String userName) {
        PerformanceProgress item = performanceProgressDao.getEntityByKey(param.getId()).
                orElseThrow(ResultEnum.DATA_NOT_FIND);

        List<PerformanceProgressLog> logs = new ArrayList<>();
        boolean change = false;
        BigDecimal todayExpectComplete = Objects.nonNull(item.getTodayExpectComplete())
                ?item.getTodayExpectComplete():BigDecimal.ZERO;

        if(Objects.nonNull(param.getTodayExpectComplete())){
            if(param.getTodayExpectComplete().compareTo(todayExpectComplete) !=  0){
                PerformanceProgressLog log = performanceProgressLogService.generateLog(item.getOrderNo(),
                        PerformanceProgressEnum.LogType.TODAY_EXPECT_COMPLETE,
                        param.getTodayExpectComplete(),userNo,userName);
                logs.add(log);
                change = true;
            }
        }else{
            //今日预计完成吨数从有变成无
            if(todayExpectComplete.compareTo(BigDecimal.ZERO) != 0){
                PerformanceProgressLog log = performanceProgressLogService.generateLog(item.getOrderNo(),
                        PerformanceProgressEnum.LogType.TODAY_EXPECT_COMPLETE,
                        "-",userNo,userName);
                logs.add(log);
                change = true;
            }
        }

        String tradeRequireArriveStationTime = StringUtils.isBlank(param.getTradeRequireArriveStationTime())
                ?null:param.getTradeRequireArriveStationTime();

        if(!StringUtils.equals(item.getTradeRequireArriveStationTime(),tradeRequireArriveStationTime)){
            PerformanceProgressLog log = performanceProgressLogService.generateLog(item.getOrderNo(),
                    PerformanceProgressEnum.LogType.TRADE_REQUIRE_ARRIVE_STATION_TIME,
                    param.getTradeRequireArriveStationTime(),userNo,userName);
            logs.add(log);
            change = true;
        }

        String transportExpectArriveStationTime = StringUtils.isBlank(param.getTransportExpectArriveStationTime())
                ?null:param.getTransportExpectArriveStationTime();
        if(!StringUtils.equals(item.getTransportExpectArriveStationTime(),transportExpectArriveStationTime)){
            PerformanceProgressLog log = performanceProgressLogService.generateLog(item.getOrderNo(),
                    PerformanceProgressEnum.LogType.TRANSPORT_EXPECT_ARRIVE_STATION_TIME,
                    param.getTransportExpectArriveStationTime(),userNo,userName);
            logs.add(log);
            change = true;
        }

        if(!StringUtils.equals(item.getAbnormalRemark(),param.getAbnormalRemark())){
            PerformanceProgressLog log = performanceProgressLogService.generateLog(item.getOrderNo(),
                    PerformanceProgressEnum.LogType.ABNORMAL_REMARK,
                    param.getAbnormalRemark(),userNo,userName);
            logs.add(log);
            change = true;
        }
        if(!StringUtils.equals(item.getPerformanceAbnormalReason(),param.getPerformanceAbnormalReason())){
            PerformanceProgressLog progressLog = performanceProgressLogService.generateLog(item.getOrderNo(),
                    PerformanceProgressEnum.LogType.PERFORMANCE_ABNORMAL_REASON,
                    param.getPerformanceAbnormalReason(),userNo,userName);
            logs.add(progressLog);
            change = true;

            //上报履约异常
            if (StringUtils.isNotBlank(param.getPerformanceAbnormalReason())) {
                FeignOrderVO orderVO = orderFeign.getOrderInfoFeign(item.getOrderNo());
                if (orderVO != null && Objects.equals(orderVO.getOrderSource(), SyncPlatformEnum.Source.NEW_OWNER_CLIENT.getCode())) {
                    OpenCallBackClient openCallBackClient = thirdAppConfig.getOpenCallBackClient(SyncPlatformEnum.Source.NEW_OWNER_CLIENT.getCode().toString());
                    TransportExceptionReportMessage message = new TransportExceptionReportMessage();
                    message.setOrderNo(item.getOrderNo());
                    message.setCreateName(progressLog.getCreateName());
                    message.setOperateContent(param.getPerformanceAbnormalReason());
                    message.setReportTime(LocalDateTime.now());
                    Result<?> result = openCallBackClient.encryptPost(JSONUtil.parse(message).toString(), message.topic());
                    if (result.succeed()) {
                        log.info("上报履约异常成功,响应信息:{}", JSONUtil.parse(result));
                    } else {
                        log.info("上报履约异常失败,响应信息:{}", JSONUtil.parse(result));
                    }
                }
            }
        }
        if(!StringUtils.equals(item.getDispatchFollow(),param.getDispatchFollow())){
            PerformanceProgressLog log = performanceProgressLogService.generateLog(item.getOrderNo(),
                    PerformanceProgressEnum.LogType.DISPATCH_FOLLOW,
                    param.getDispatchFollow(),userNo,userName);
            logs.add(log);
            change = true;
        }

        PerformanceProgress update = performanceProgressStruct.convertParam(param);
        performanceProgressDao.updatePerformanceProgress(update);
        if(change){
            performanceProgressLogDao.saveBatchList(logs);
        }
    }


    @Override
    public PerformanceProgressDetailVO getPerformanceProgressDetail(Integer id) {
        PerformanceProgress item = performanceProgressDao.getEntityByKey(id).orElseThrow(ResultEnum.DATA_NOT_FIND);
        return performanceProgressStruct.convert(item);
    }

    @Override
    public List<PerformanceProgressOperationLogVO> getOperationLog(String orderNo,Integer operateType) {
        List<PerformanceProgressLog> list = performanceProgressLogDao.getOperationLog(orderNo,operateType);
        return performanceProgressLogStruct.convertList(list);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void dealPerformanceProgress4OrderInfo(OrderInfoMessage data) {
        //如果取消，删除履约进度表这条记录
        if(Objects.equals(data.getOrderStatus(),OrderEnum.Status.CANCELED.getCode())){
            performanceProgressDao.deleteByField(PerformanceProgress::getOrderNo,data.getOrderNo());
        }

        Optional<PerformanceProgress> performanceProgressOptional = performanceProgressDao.getOneByField(PerformanceProgress::getOrderNo,
                data.getOrderNo());

        PerformanceProgress item = new PerformanceProgress();

        item.setOrderStatus(data.getOrderStatus());
        item.setGoodsTypeCode(data.getGoodsTypeCode());
        item.setGoodsTypeName(data.getGoodsTypeName());
        item.setGoodsNameId(data.getGoodsNameId());
        item.setGoodsName(data.getGoodsName());
        item.setSendOverStandard(data.getOverWeight());
        item.setTaskWeight(data.getTransportWeight());

        item.setTransportTimeSlot(DateUtils.formatDateTime(data.getTransportBeginTime()).get() + "至" +
                DateUtils.formatDateTime(data.getTransportEndTime()).get());


        if(performanceProgressOptional.isPresent()){
            item.setId(performanceProgressOptional.get().getId());
            if(Objects.nonNull(data.getSendSystemAddressId()) &&
                    !Objects.equals(performanceProgressOptional.get().getSendSystemAddressId(),data.getSendSystemAddressId())){
                item.setSendSystemAddressId(data.getSendSystemAddressId());
                item.setSendSystemAddressShorter(getSystemAddressShorter(data.getSendSystemAddressId()));
            }
            performanceProgressDao.updateEntityByKey(item);
        }else{
            //查询最大的seq
            long seq = performanceProgressDao.getMaxSeq();
            item.setSeq(seq + 1);

            Optional<FeignAddressVO> sendAndReceiveAddress = addressService.getSendAndReceiveAddress(
                    data.getSendAddressId(), data.getReveiveAddressId());

            if (Objects.isNull(sendAndReceiveAddress.get().getSendAddress())  ||
                    Objects.isNull(sendAndReceiveAddress.get().getReceiveAddress())) {
                log.warn("通过发货地址Id:{},收货地址Id：{} 查询对应的地址信息结果：{}",
                        data.getSendAddressId(),data.getReveiveAddressId(),sendAndReceiveAddress);
                throw new ServiceSystemException(ResultEnum.DATA_ERROR,"履约进度表订单对应的收发货地址信息为空");
            }
            FeignAddressVO.Address sendAddress = sendAndReceiveAddress.get().getSendAddress();
            FeignAddressVO.Address receiveAddress = sendAndReceiveAddress.get().getReceiveAddress();

            BigDecimal distance = null;
            //重车运距（收发货地址距离）
            try{
                List<GdRouteDTO> route = gdService.getRoute(sendAddress.getLongitude(), sendAddress.getLatitude(),
                        receiveAddress.getLongitude(), receiveAddress.getLatitude());
                if (!route.isEmpty()){
                    distance = new BigDecimal(route.get(0).getDistance() /1000);
                }
            }catch (Exception e){
                log.warn("订单计算重车运距失败，订单号:{},失败原因：{}",data.getOrderNo(), ExceptionUtils.getStackTrace(e));
            }

            item.setOrderDistance(distance);
            item.setOrderNo(data.getOrderNo());

            if(Objects.nonNull(data.getSendSystemAddressId())){
                item.setSendSystemAddressId(data.getSendSystemAddressId());
                item.setSendSystemAddressShorter(getSystemAddressShorter(data.getSendSystemAddressId()));
            }
            item.setSendAddressId(data.getSendAddressId());
            item.setSendAddressShorter(data.getSendAddressShorter());
            item.setSendAddress(addressService.generateAddressDetail(sendAddress.getProvince(),
                    sendAddress.getCity(),sendAddress.getCounty(),sendAddress.getAddress()));
            performanceProgressDao.saveEntity(item);
        }
    }

    private String getSystemAddressShorter(Integer addressId){
        Optional<SystemAddressVO> systemAddress = addressService.getSystemAddress(addressId);
        if (!systemAddress.isPresent()) {
            log.warn("通过发货系统地址Id:{},查询对应的地址信息结果：{}",
                    addressId,systemAddress);
            throw new ServiceSystemException(ResultEnum.DATA_ERROR,"履约进度表订单对应的系统发货地址信息为空");
        }
        return systemAddress.get().getAddressShorter();
    }

    //履约进度表----货单部分
    @Override
    public void dealPerformanceProgress4OrderGoods(OrderGoods data) {
        Optional<PerformanceProgress> optional = performanceProgressDao.getOneByField(PerformanceProgress::getOrderNo,
                data.getOrderNo());
        if(!optional.isPresent()){
            log.error("货单对应的订单信息不存在,订单号:{},货单号:{}",data.getOrderNo(),data.getOrderGoodsNo());
            throw new ServiceSystemException(ResultEnum.DATA_NOT_FIND);
        }
        //根据挂单时间倒序排序
        List<OrderGoods> orderGoods = orderGoodsDao.listAllByOrderNo(data.getOrderNo());
        if(CollectionUtils.isEmpty(orderGoods)){
            return;
        }
        Set<String> seniorLogisticsManagerNameSet = new HashSet<>();
        BigDecimal pendingOrderFreight =  null;  //最新的货单的司机运费，取消的也算
        LocalDateTime firstPendingTime = null;  //挂单时间，取消的也算
        BigDecimal pendingWeight = BigDecimal.ZERO;
        Integer pendingTruck = calcPendingTruck(orderGoods);
        for(OrderGoods item : orderGoods){
            //只有挂单车数统计所有货单的
            if(Objects.equals(item.getOrderGoodsStatus(),OrderGoodsStatusEnum.Status.CREATED.getCode())){
                continue;
            }

            seniorLogisticsManagerNameSet.add(item.getSeniorLogisticsManagerName());
            if(Objects.isNull(pendingOrderFreight)){
                pendingOrderFreight = item.getPendingOrderFreight();
            }
            //最后一个挂单中的货单的挂单时间为最早的挂单时间
            firstPendingTime = item.getPendingOrderTime();

            pendingWeight = pendingWeight.add(calcPendingWeight(item));

        }
        PerformanceProgress update = new PerformanceProgress();
        update.setId(optional.get().getId());
        update.setSeniorLogisticsManagerName(JSON.toJSONString(new ArrayList<>(seniorLogisticsManagerNameSet)));
        update.setDriverFreightPrice(pendingOrderFreight);
        update.setPendingTime(firstPendingTime);
        update.setPendingWeight(pendingWeight);
        update.setPendingTruck(pendingTruck);
        performanceProgressDao.updateEntityByKey(update);
    }


    //统计挂单车数
    public Integer calcPendingTruck(List<OrderGoods> orderGoods){
        int totalNeedTruck = 0;
        List<String> cancelOrderGoodsNo = new ArrayList<>();
        for (OrderGoods item : orderGoods) {
            if(Objects.equals(item.getOrderGoodsStatus(),OrderGoodsStatusEnum.Status.CANCEL.getCode())){
                cancelOrderGoodsNo.add(item.getOrderGoodsNo());
            }else{
                totalNeedTruck = totalNeedTruck + item.getNeedTruckNum();
            }
        }
        if(CollectionUtils.isNotEmpty(cancelOrderGoodsNo)){
            Long count = orderChildDao.countNotCancelOrderChild(cancelOrderGoodsNo);
            totalNeedTruck = totalNeedTruck + count.intValue();
        }

        return totalNeedTruck;
    }

    //计算履约进度表货单的挂单吨数
    @Override
    public BigDecimal calcPendingWeight(OrderGoods item){
        if(Objects.equals(item.getOrderGoodsStatus(), OrderGoodsStatusEnum.Status.CANCEL.getCode())){
            return Objects.nonNull(item.getAlreadyTransportWeight())?item.getAlreadyTransportWeight():BigDecimal.ZERO;
        }
        return item.getExtractWeight();
    }



    //履约进度表----运单部分
    @Override
    public void dealPerformanceProgress4OrderChild(OrderChild data) {
        Optional<PerformanceProgress> optional = performanceProgressDao.getOneByField(PerformanceProgress::getOrderNo,
                data.getOrderNo());
        if(!optional.isPresent()){
            log.error("运单对应的订单信息不存在,订单号:{},运单号:{}",data.getOrderNo(),data.getChildNo());
            throw new ServiceSystemException(ResultEnum.DATA_NOT_FIND);
        }
        FeignOrderInfoVO orderInfo = orderService.getOrderInfo(data.getOrderNo()).get();

        //取完成之前的运单数据
        List<OrderChild> orderChildList = orderChildDao.listBeforeCompleteByOrderNo(data.getOrderNo());
        int orderedTruckNum = orderChildList.size();  //接单车数
        int arriveSendTruckNum = 0; //到达货源地车数
        int loadTruckNum = 0;  //装车车数
        int unloadTruckNum = 0;   //卸车车数
        int onTheWayTruckNum ;    // 在途车数
        BigDecimal taskCompleteRatio ;    //任务完成率
        BigDecimal sumLoadWeight = BigDecimal.ZERO;    //矿发吨数
        BigDecimal sumUnloadWeight = BigDecimal.ZERO;    //到站吨数
        BigDecimal sumOnTheWayWeight = BigDecimal.ZERO;   //在途吨数

        BigDecimal orderedWeight = BigDecimal.ZERO;     //接单吨数

        for (OrderChild child : orderChildList) {
            if(child.getStatus() >= OrderChildEnum.Status.ARRIVE_SEND.getCode()){
                arriveSendTruckNum = arriveSendTruckNum + 1;
            }
            if(child.getStatus() >= OrderChildEnum.Status.LOAD.getCode()){
                loadTruckNum = loadTruckNum + 1;
                sumLoadWeight = sumLoadWeight.add(child.getLoadNet());
                orderedWeight =  orderedWeight.add(child.getLoadNet());
            }else{
                orderedWeight =  orderedWeight.add(child.getWeight());
            }
            if(child.getStatus() >= OrderChildEnum.Status.UNLOAD.getCode()){
                unloadTruckNum = unloadTruckNum + 1;
                sumUnloadWeight = sumUnloadWeight.add(child.getWeight());
            }
            if(Objects.equals(child.getStatus(), OrderChildEnum.Status.LOAD.getCode()) ||
                    Objects.equals(child.getStatus(), OrderChildEnum.Status.GO_TO_RECEIVE.getCode()) ||
                    Objects.equals(child.getStatus(), OrderChildEnum.Status.ARRIVE_RECEIVE.getCode())
            ){
                sumOnTheWayWeight = sumOnTheWayWeight.add(child.getLoadNet());
            }
        }


        //在途车辆数 = 装车车数 - 卸车车数
        onTheWayTruckNum = loadTruckNum - unloadTruckNum;





        PerformanceProgress update = new PerformanceProgress();
        update.setId(optional.get().getId());
        update.setOrderedTruckNum(orderedTruckNum);
        update.setArriveSendTruckNum(arriveSendTruckNum);
        update.setLoadTruckNum(loadTruckNum);
        update.setUnloadTruckNum(unloadTruckNum);
        update.setOnTheWayTruckNum(onTheWayTruckNum);
        update.setOrderedWeight(orderedWeight);
        update.setSumLoadWeight(sumLoadWeight);
        update.setSumUnloadWeight(sumUnloadWeight);
        update.setSumOnTheWayWeight(sumOnTheWayWeight);
        performanceProgressDao.updateEntityByKey(update);
    }

    @Override
    public List<PerformanceProgressVO> queryPerformanceProgress(List<String> orderNoList) {
        return performanceProgressStruct.convertList(performanceProgressDao.listInField(PerformanceProgress::getOrderNo, orderNoList));
    }

    @Override
    public SXSSFWorkbook exportPerformanceProgress(PagePerformanceProgress param) {
        param.setPage(1);
        param.setPageSize(1000000);
        IPage<PerformanceProgressVO> page = pagePerformanceProgress(param);
        List<PerformanceProgressVO> list = page.getRecords();

        List<ExportFieldVo> selectFieldList = exportFieldStruct.convert(exportFieldDao.listFieldByTemplate(param.getTemplateId()));
        if (selectFieldList.isEmpty()) {
            selectFieldList = exportFieldStruct.convert(exportFieldDao.listFieldByFunctionCode(TEMPLATE_PERFORMANCE_PROGRESS));
        }

        // 组装表头
        List<ExcelField> fieldList = new ArrayList<>();
        fieldList.add(new ExcelField(0, "序号", "index", 2000));
        int column = 1;
        for (ExportFieldVo item : selectFieldList) {
            fieldList.add(new ExcelField(column, item.getName(), item.getCode(), 5000));
        }

        // 组装数据
        List<List<ExcelData>> dataList = new ArrayList<>();
        for (int i=0; i<list.size(); i++){

            PerformanceProgressVO vo = list.get(i);
            List<ExcelData> rowData = new ArrayList<>();

            rowData.add(new ExcelData(i+1));

            for (ExportFieldVo item : selectFieldList) {
                if (item.getCode().equals("sendAddressShorter")) {
                    rowData.add(new ExcelData(vo.getSendAddressShorter()));
                } else if (item.getCode().equals("sendSystemAddressShorter")) {
                    rowData.add(new ExcelData(vo.getSendSystemAddressShorter()));
                } else if (item.getCode().equals("seniorLogisticsManagerName")) {
                    rowData.add(new ExcelData(vo.getSeniorLogisticsManagerName()));
                } else if (item.getCode().equals("goodsTypeName")) {
                    rowData.add(new ExcelData(vo.getGoodsTypeName()));
                } else if (item.getCode().equals("goodsName")) {
                    rowData.add(new ExcelData(vo.getGoodsName()));
                }

                else if (item.getCode().equals("sendAddress")) {
                    rowData.add(new ExcelData(vo.getSendAddress()));
                } else if (item.getCode().equals("sendOverStandardMsg")) {
                    rowData.add(new ExcelData(vo.getSendOverStandardMsg()));
                } else if (item.getCode().equals("driverFreightPrice")) {
                    rowData.add(new ExcelData(vo.getDriverFreightPrice()==null?null:vo.getDriverFreightPrice().movePointLeft(2)));
                } else if (item.getCode().equals("taskWeight")) {
                    rowData.add(new ExcelData(vo.getTaskWeight()));
                } else if (item.getCode().equals("pendingWeight")) {
                    rowData.add(new ExcelData(vo.getPendingWeight()));
                }else if (item.getCode().equals("pendingTruck")) {
                    rowData.add(new ExcelData(vo.getPendingTruck()));
                }

                else if (item.getCode().equals("orderedTruckNum")) {
                    rowData.add(new ExcelData(vo.getOrderedTruckNum()));
                } else if (item.getCode().equals("arriveSendTruckNum")) {
                    rowData.add(new ExcelData(vo.getArriveSendTruckNum()));
                } else if (item.getCode().equals("loadTruckNum")) {
                    rowData.add(new ExcelData(vo.getLoadTruckNum()));
                } else if (item.getCode().equals("unloadTruckNum")) {
                    rowData.add(new ExcelData(vo.getUnloadTruckNum()));
                } else if (item.getCode().equals("onTheWayTruckNum")) {
                    rowData.add(new ExcelData(vo.getOnTheWayTruckNum()));
                }

                else if (item.getCode().equals("orderedRate")) {
                    rowData.add(new ExcelData(vo.getOrderedRate()));
                } else if (item.getCode().equals("taskCompleteRatio")) {
                    rowData.add(new ExcelData(vo.getTaskCompleteRatio()));
                } else if (item.getCode().equals("sumLoadWeight")) {
                    rowData.add(new ExcelData(vo.getSumLoadWeight()));
                } else if (item.getCode().equals("sumUnloadWeight")) {
                    rowData.add(new ExcelData(vo.getSumUnloadWeight()));
                } else if (item.getCode().equals("sumOnTheWayWeight")) {
                    rowData.add(new ExcelData(vo.getSumOnTheWayWeight()));
                }

                else if (item.getCode().equals("todayExpectComplete")) {
                    rowData.add(new ExcelData(vo.getTodayExpectComplete()));
                } else if (item.getCode().equals("abnormalRemark")) {
                    rowData.add(new ExcelData(vo.getAbnormalRemark()));
                } else if (item.getCode().equals("performanceAbnormalReason")) {
                    rowData.add(new ExcelData(vo.getPerformanceAbnormalReason()));
                } else if (item.getCode().equals("dispatchFollow")) {
                    rowData.add(new ExcelData(vo.getDispatchFollow()));
                } else if (item.getCode().equals("orderDistance")) {
                    rowData.add(new ExcelData(vo.getOrderDistance()+""));
                }

                else if (item.getCode().equals("transportTimeSlot")) {
                    rowData.add(new ExcelData(vo.getTransportTimeSlot()));
                } else if (item.getCode().equals("pendingTime")) {
                    rowData.add(new ExcelData(vo.getPendingTime()));
                } else if (item.getCode().equals("tradeRequireArriveStationTime")) {
                    rowData.add(new ExcelData(vo.getTradeRequireArriveStationTime()));
                } else if (item.getCode().equals("transportExpectArriveStationTime")) {
                    rowData.add(new ExcelData(vo.getTransportExpectArriveStationTime()));
                } else if (item.getCode().equals("predictionFreightPrice")) {
                    rowData.add(new ExcelData(vo.getPredictionFreightPrice()==null?null:vo.getPredictionFreightPrice().movePointLeft(2)));
                }
            }
            dataList.add(rowData);
        }

        ExcelSheet excelSheet = new ExcelSheet("履约进度", "履约进度", fieldList, dataList);

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

    // 计算接单率
    public BigDecimal calcOrderedRate(BigDecimal orderedWeight,BigDecimal pendingWeight){
        //接单率 =  接单吨数 / 挂单吨数
        return orderedWeight.divide(pendingWeight,3, RoundingMode.HALF_UP).multiply(new BigDecimal("100"));
    }

    /**
     * 通过远程代用clx-order服务获取“线路异常上报”数据，构建map集合
     *
     * @param orderNoList
     * @return
     */
    public Map<String, String> getInternalReportRouteException(List<String> orderNoList) {
        // 构建查询参数
        InternalReportRouteExceptionParam action = new InternalReportRouteExceptionParam();
        action.setOrderNoList(orderNoList);
        // 远程查询，异常上报信息
        List<InternalReportRouteExceptionFeignVO> list = Optional.of(internalReportRouteExceptionFeign
                        .getInternalReportRouteExceptionList(action)).filter(Result::succeed)
                .map(Result::getData).orElse(null);
        log.info("通过远程代用clx-order服务获取“线路异常上报”数据{}", JSONUtil.parseArray(list));
        // 如果为空，返回空map集合
        if (CollectionUtils.isEmpty(list)) {
            return new HashMap<>();
        }
        // 以订单编号作为key，多条异常上报信息作为value，构建map集合
        Map<String, List<InternalReportRouteExceptionFeignVO>> reportRouteExceptionMap =
                list.stream().collect(Collectors.groupingBy(InternalReportRouteExceptionFeignVO::getOrderNo));
        log.info("通过远程代用clx-order服务获取reportRouteExceptionMap{}", JSONObject.toJSONString(reportRouteExceptionMap));

            // 构建map集合，key为订单编号，value为异常上报信息
        return reportRouteExceptionMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
                    entry -> entry.getValue().stream().map(InternalReportRouteExceptionFeignVO::getExceptionInfo)
                            .collect(Collectors.joining("/"))));
    }
}
