package com.sckw.transport.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sckw.core.common.enums.NumberConstant;
import com.sckw.core.common.enums.enums.DictTypeEnum;
import com.sckw.core.model.constant.Global;
import com.sckw.core.model.enums.CarWaybillEnum;
import com.sckw.core.model.enums.CarWaybillQueryEnum;
import com.sckw.core.model.page.PageResult;
import com.sckw.core.utils.*;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.core.web.response.HttpResult;
import com.sckw.excel.utils.DateUtil;
import com.sckw.fleet.api.RemoteFleetService;
import com.sckw.mongo.model.SckwWaybillOrder;
import com.sckw.mongo.model.TableTops;
import com.sckw.system.api.RemoteSystemService;
import com.sckw.system.api.model.dto.res.AreaTreeFrontResDto;
import com.sckw.system.api.model.dto.res.SysDictResDto;
import com.sckw.system.api.model.dto.res.UserCacheResDto;
import com.sckw.transport.dao.*;
import com.sckw.transport.model.*;
import com.sckw.transport.model.dto.*;
import com.sckw.transport.model.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author jc
 * @description 运单相关服务
 * @date 2023-06-29 15:06:45
 */
@Slf4j
@Service
public class WaybillManagementService {

    @DubboReference(version = "1.0.0", group = "design", check = false)
    RemoteFleetService remoteFleetService;

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

    @Autowired
    public KwtWaybillOrderMapper kwtWaybillOrderMapper;

    @Autowired
    public KwtLogisticsOrderMapper kwtLogisticsOrderMapper;

    @Autowired
    public KwtWaybillOrderAddressMapper kwtWaybillOrderAddressMapper;

    @Autowired
    public KwtWaybillOrderTicketMapper kwtWaybillOrderTicketMapper;

    @Autowired
    private KwtLogisticsOrderCirculateMapper orderCirculateDao;

    @Autowired
    public KwtWaybillOrderTrackMapper kwtWaybillOrderTrackMapper;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private CommonService commonService;

    /**
     * 运单详情
     *
     * @param id
     * @return
     */
    public HttpResult waybillData(Long id) {
        if (Objects.isNull(id)) {
            return HttpResult.error("id不能为空");
        }
        WaybillDataVO waybillDataVO = new WaybillDataVO();
        Criteria criteria = new Criteria();
        //criteria.and("wOrderId").is(id);
        criteria.and("_id").is(id);
//        criteria.and("entId").is(LoginUserHolder.getAuthUserIdList());
        criteria.and("delFlag").is(NumberConstant.ZERO);
        Query queryFormat = new Query(criteria);
        SckwWaybillOrder info = mongoTemplate.findOne(queryFormat, SckwWaybillOrder.class);
        WayBillDetailDTO wayBillDetailDTO = new WayBillDetailDTO();
        WaybillTicketVO waybillTicketVO = new WaybillTicketVO();
        WaybillCarVO waybillCarVO = new WaybillCarVO();
        if (!ObjectUtils.isEmpty(info)) {
            // 基础信息
            wayBillDetailDTO.setTruckId(info.getTruckId());
            wayBillDetailDTO.setStatus(String.valueOf(info.getStatus()));
            wayBillDetailDTO.setTruckNo(info.getTruckNo());
            wayBillDetailDTO.setDriverId(info.getDriverId());
            wayBillDetailDTO.setDriverName(info.getDriverName());
            wayBillDetailDTO.setDriverPhone(info.getDriverPhone());
            wayBillDetailDTO.setDriverId(info.getDriverId());
            wayBillDetailDTO.setWOrderId(info.getWOrderId());
            wayBillDetailDTO.setWOrderNo(info.getWOrderNo());
            wayBillDetailDTO.setLOrderId(info.getLOrderId());
            wayBillDetailDTO.setLOrderNo(info.getLOrderNo());
            wayBillDetailDTO.setLOrderNo(info.getLOrderNo());
            wayBillDetailDTO.setEntrustAmount(String.valueOf(info.getEntrustAmount()));
            wayBillDetailDTO.setType(String.valueOf(info.getType()));
            wayBillDetailDTO.setTypeLabel(info.getType().equals(NumberConstant.ONE) ? "趟次" : "循环");
            wayBillDetailDTO.setStartTime(info.getStartTime());
            wayBillDetailDTO.setEndTime(info.getEndTime());
            wayBillDetailDTO.setCreateBy(info.getCreateByName());
            wayBillDetailDTO.setGoodsName(info.getGoodsName());
            wayBillDetailDTO.setLoadDetailAddress(info.getLoadCityName().concat(info.getLoadDetailAddress()));
            wayBillDetailDTO.setUnloadDetailAddress(info.getUnloadCityName().concat(info.getUnloadDetailAddress()));
            wayBillDetailDTO.setLoadName(info.getLoadName());
            wayBillDetailDTO.setUnloadName(info.getUnloadName());
            wayBillDetailDTO.setCarrierFirmName(info.getCarrierFirmName());
            wayBillDetailDTO.setCheckFirmName(info.getCheckFirmName());
            // 计费方式
            KwtLogisticsOrder kwtLogisticsOrder = kwtLogisticsOrderMapper.selectById(info.getLOrderId());
            if (!ObjectUtils.isEmpty(kwtLogisticsOrder)) {
                wayBillDetailDTO.setPriceType(kwtLogisticsOrder.getBillingMode());
                SysDictResDto billingMode = remoteSystemService.queryDictByTypeAndValue(DictTypeEnum.CHARGING_TYPE.getType(), kwtLogisticsOrder.getBillingMode());
                if (!ObjectUtils.isEmpty(billingMode)) {
                    wayBillDetailDTO.setPriceTypeLabe(billingMode.getLabel());
                }
            }
            wayBillDetailDTO.setCheckFirmName(info.getCheckFirmName());
            // 运输量单位
            wayBillDetailDTO.setUnit(info.getUnit() == null ? null : info.getUnit());
            if (info.getUnit() != null) {
                Map<String, SysDictResDto> unitType = remoteSystemService.queryDictMapByType(DictTypeEnum.UNIT_TYPE.getType());
                SysDictResDto sysDict = unitType.get(info.getUnit());
                wayBillDetailDTO.setUnitLabel(sysDict == null ? null : sysDict.getLabel());
            }
            // 派车人信息
            UserCacheResDto createUser = remoteSystemService.queryUserCacheById(info.getCreateBy());
            if (!ObjectUtils.isEmpty(createUser)) {
                wayBillDetailDTO.setCreateByPhone(createUser.getPhone());
            }
            // 车辆信息
            SysDictResDto truckTypeString = remoteSystemService.queryDictByTypeAndValue(DictTypeEnum.TRUCK_TYPE.getType(), info.getTruckType());
            if (!ObjectUtils.isEmpty(truckTypeString)) {
                waybillCarVO.setTypeLabel(truckTypeString.getLabel());
            }
            waybillCarVO.setTruckId(String.valueOf(info.getTruckId()));
            waybillCarVO.setTruckNo(info.getTruckNo());
            waybillCarVO.setType(info.getTruckType());
            waybillCarVO.setDriverName(info.getDriverName());
            waybillCarVO.setDriverPhone(info.getDriverPhone());
            waybillCarVO.setDriverId(String.valueOf(info.getTruckId()));
            waybillCarVO.setTrailerNo(info.getTruckTrailerNo());
            // 票据
            List<KwtWaybillOrderTicket> waybillOrderTickets = kwtWaybillOrderTicketMapper.selectList(new LambdaQueryWrapper<KwtWaybillOrderTicket>()
                    .eq(KwtWaybillOrderTicket::getWOrderId, id)
            );
            if (!org.springframework.util.CollectionUtils.isEmpty(waybillOrderTickets)) {
                for (KwtWaybillOrderTicket waybillOrderTicket : waybillOrderTickets) {
                    //1装货单/2卸货单
                    if (waybillOrderTicket.getType() == 1) {
                        if (info.getLoadTime() != null) {
                            waybillTicketVO.setLoadTime(waybillOrderTicket.getOperateTime() == null ? null : DateUtil.getDateTime(waybillOrderTicket.getOperateTime()));
                        }
                        waybillTicketVO.setLoadWeight(String.valueOf(info.getLoadAmount()));
                        waybillTicketVO.setLoadUrl(FileUtils.splice(String.valueOf(info.getLoadUrls())));
                    }
                    if (waybillOrderTicket.getType() == 2) {
                        if (info.getUnloadTime() != null) {
                            waybillTicketVO.setUnloadTime(waybillOrderTicket.getOperateTime() == null ? null : DateUtil.getDateTime(waybillOrderTicket.getOperateTime()));
                        }
                        waybillTicketVO.setUnloadWeight(String.valueOf(info.getUnloadAmount()));
                        waybillTicketVO.setUnloadUrl(FileUtils.splice(String.valueOf(info.getUnloadUrls())));
                    }
                }
            }
            waybillTicketVO.setDeficitAmount(String.valueOf(info.getDeficitAmount()));
            // 计算扣亏量
            BigDecimal deficitLoss = info.getLoss() == null ? BigDecimal.valueOf(0) : info.getLoss();
            BigDecimal loadAmount = info.getLoadAmount() == null ? new BigDecimal("0.00") : info.getLoadAmount();
            BigDecimal unloadAmount = info.getUnloadAmount() == null ? new BigDecimal("0.00") : info.getUnloadAmount();
            BigDecimal deficitRealAmount = commonService.deficitLossAmount(
                    info.getLoadAmount(),
                    loadAmount.subtract(unloadAmount),
                    deficitLoss,
                    info.getLossUnit()
            );
            waybillTicketVO.setDeficitRealAmount(deficitRealAmount.toString());
        }

        List<Integer> statuses = initWaybillIndexStatus();
        // 初始化各状态
        List<WaybillStatusVO> statusVOS = new ArrayList<>();
        statuses.forEach(e -> {
            WaybillStatusVO waybillStatusVO = new WaybillStatusVO();
            waybillStatusVO.setStatus(false);
            if(e.equals(CarWaybillEnum.PENDING_ORDER.getCode())) {
                // 默认选中 待接单 状态
                waybillStatusVO.setStatus(true);
            }
            waybillStatusVO.setCode(e);
            waybillStatusVO.setDestination(CarWaybillEnum.getName(e));
            statusVOS.add(waybillStatusVO);
        });

        List<KwtWaybillOrderTrack> kwtWaybillOrderTracks = kwtWaybillOrderTrackMapper
                .selectList(new LambdaQueryWrapper<KwtWaybillOrderTrack>()
                        .eq(KwtWaybillOrderTrack::getWOrderId, id));
        List<WaybillTrackVO> waybillTrackVOS = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(kwtWaybillOrderTracks)) {
            List<Long> userIds = new ArrayList<>();
            kwtWaybillOrderTracks.forEach(e -> userIds.add(e.getCreateBy()));
            List<UserInfoVo> users = commonService.findUserList(userIds);
            Map<Long, String> userNameMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            users.forEach(e -> userNameMap.put(e.getId(), e.getName()));
            Map<Long, String> userPhoneMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            users.forEach(e -> userPhoneMap.put(e.getId(), e.getPhone()));

            for (KwtWaybillOrderTrack track : kwtWaybillOrderTracks) {
                for (WaybillStatusVO statusVO : statusVOS) {
                    if (statusVO.getCode().equals(track.getStatus())) {
                        statusVO.setStatus(true);
                        statusVO.setId(track.getId());
                        statusVO.setCreateTime(DateUtil.getDateTime(track.getCreateTime()));
                        statusVO.setOperateTime(DateUtil.getDateTime(track.getOperateTime()));
                        statusVO.setCreateByName(userNameMap.get(track.getCreateBy()));
                        break;
                    }
                }

                WaybillTrackVO waybillTrackVO = new WaybillTrackVO();
                waybillTrackVO.setId(String.valueOf(track.getId()))
                        .setRemark(track.getRemark())
                        .setStatus(String.valueOf(track.getStatus()))
                        .setStatusLabel(CarWaybillEnum.getName(track.getStatus()))
                        .setCreateBy(track.getCreateBy())
                        .setCreateByPhone(userPhoneMap.get(track.getCreateBy()))
                        .setCreateByName(userNameMap.get(track.getCreateBy()))
                        .setCreateTime(DateUtil.getDateTime(track.getCreateTime()))
                        .setOperateTime(DateUtil.getDateTime(track.getOperateTime()));
                waybillTrackVOS.add(waybillTrackVO);
            }
        }

        waybillDataVO.setAgreement(waybillTicketVO);
        waybillDataVO.setCar(waybillCarVO);
        waybillDataVO.setTransport(wayBillDetailDTO);
        waybillDataVO.setProcess(statusVOS);
        waybillDataVO.setLogs(waybillTrackVOS);
        return HttpResult.ok(waybillDataVO);
    }

    /**
     * 简洁版运单详情
     *
     * @param id
     * @return
     */
    public HttpResult waybillSimpleData(Long id) {
        // 数据校验
        if (id == null) {
            return HttpResult.error("车辆运单ID不能为空！");
        }
        WaybillSimpleDataVO waybillSimpleDataVO = new WaybillSimpleDataVO();
        KwtWaybillOrder waybillOrder = kwtWaybillOrderMapper.selectById(id);
        if (waybillOrder != null) {
            BeanUtils.copyPropertiesValue(waybillOrder, waybillSimpleDataVO);
            waybillSimpleDataVO.setWOrderId(waybillOrder.getId());
        } else {
            KwtLogisticsOrderCirculate orderCirculate = orderCirculateDao.selectById(id);
            if (orderCirculate == null) {
                return HttpResult.error("车辆运单已不存在！");
            }
            BeanUtils.copyPropertiesValue(orderCirculate, waybillSimpleDataVO);
            waybillSimpleDataVO.setWOrderId(orderCirculate.getId());
        }

        // 初始化各状态
        List<WaybillStatusVO> statusVOS = new ArrayList<>();
        List<Integer> statuses = initWaybillIndexStatus();
        statuses.forEach(e -> {
            WaybillStatusVO waybillStatusVO = new WaybillStatusVO();
            waybillStatusVO.setStatus(false);
            waybillStatusVO.setCode(e);
            waybillStatusVO.setDestination(CarWaybillEnum.getName(e));
            statusVOS.add(waybillStatusVO);
        });

        List<KwtWaybillOrderTrack> kwtWaybillOrderTracks = kwtWaybillOrderTrackMapper.selectList(new LambdaQueryWrapper<KwtWaybillOrderTrack>().eq(KwtWaybillOrderTrack::getWOrderId, id));
        if (CollectionUtils.isNotEmpty(kwtWaybillOrderTracks)) {
            List<Long> userIds = new ArrayList<>();
            kwtWaybillOrderTracks.forEach(e -> userIds.add(e.getCreateBy()));
            List<UserCacheResDto> users = remoteSystemService.queryUserCacheByIds(userIds);
            Map<Long, UserCacheResDto> usersMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
            users.forEach(e -> usersMap.put(e.getId(), e));
            for (KwtWaybillOrderTrack kwtWaybillOrderTrack : kwtWaybillOrderTracks) {
                for (WaybillStatusVO statusVO : statusVOS) {
                    if (statusVO.getCode().equals(kwtWaybillOrderTrack.getStatus())) {
                        statusVO.setStatus(true);
                        statusVO.setId(kwtWaybillOrderTrack.getId());
                        statusVO.setCreateTime(DateUtil.getDateTime(kwtWaybillOrderTrack.getCreateTime()));
                        statusVO.setOperateTime(kwtWaybillOrderTrack.getOperateTime() == null
                                ? null : DateUtil.getDateTime(kwtWaybillOrderTrack.getOperateTime()));
                        statusVO.setCreateByName(usersMap.get(kwtWaybillOrderTrack.getCreateBy()) == null
                                ? null : usersMap.get(kwtWaybillOrderTrack.getCreateBy()).getName());
                        break;
                    }
                }
            }
        }
        waybillSimpleDataVO.setProcess(statusVOS);
        return HttpResult.ok(waybillSimpleDataVO);
    }

    /**
     * 运单看板列表
     *
     * @param query
     * @return
     * @throws Exception
     */
    public HttpResult waybillIndex(WaybillOrderDTO query) throws Exception {
        // mongo查询列数据，不足的数据单独关联表查询
        // 状态查询 status [2-8]
        List<Integer> statuses = initWaybillIndexStatus();
        // 初始化各状态
        List<WaybillStatusVO> statusVOS = new ArrayList<>();
        // 已作废
        List<Integer> abortStatues = new ArrayList<>();
        abortStatues.add(CarWaybillQueryEnum.REJECT_ORDER.getCode());
        abortStatues.add(CarWaybillEnum.REFUSE_TRAFFIC.getCode());
        abortStatues.add(CarWaybillEnum.REVOKED.getCode());
        statuses.forEach(e -> {
            WaybillStatusVO waybillStatusVO = new WaybillStatusVO();
            waybillStatusVO.setStatus(false);
            if(e.equals(CarWaybillEnum.PENDING_ORDER.getCode()) && !abortStatues.contains(e)) {
                // 默认选中 待接单 状态, 已作废的不选中
                waybillStatusVO.setStatus(true);
            }
            waybillStatusVO.setCode(e);
            waybillStatusVO.setDestination(CarWaybillEnum.getName(e));
            statusVOS.add(waybillStatusVO);
        });

        Criteria criteria = buildWaybillIndexQuery(query);
        Query queryFormat = new Query(criteria);
        long total = mongoTemplate.count(queryFormat, SckwWaybillOrder.class);
        queryFormat.with(PageRequest.of(query.getPage() - 1, query.getPageSize(), Sort.by(Sort.Order.desc("createTime"))));
        // 执行查询
        List<SckwWaybillOrder> list = mongoTemplate.find(queryFormat, SckwWaybillOrder.class);
        List<WaybillBoardListVO> orders = new ArrayList<>();
        packageWaybillIndexResult(list, statusVOS, orders);
        PageResult build = PageResult.build(query.getPage(), query.getPageSize(), total, orders);
        return HttpResult.ok(build);
    }

    /**
     * @return
     */
    public void packageWaybillIndexResult(List<SckwWaybillOrder> list, List<WaybillStatusVO> statusVOS, List<WaybillBoardListVO> returnList) {
        // 执行查询
        for (SckwWaybillOrder sckwWaybillOrder : list) {
            WaybillBoardListVO waybillBoardListVO = new WaybillBoardListVO();
            waybillBoardListVO.setWOrderId(sckwWaybillOrder.getWOrderId() != null ? String.valueOf(sckwWaybillOrder.getWOrderId()) : String.valueOf(sckwWaybillOrder.get_id()));
            waybillBoardListVO.setWOrderNo(sckwWaybillOrder.getWOrderNo() == null ? null : sckwWaybillOrder.getWOrderNo());
            waybillBoardListVO.setStatus(String.valueOf(sckwWaybillOrder.getStatus()));
            waybillBoardListVO.setType(String.valueOf(sckwWaybillOrder.getType()));
            waybillBoardListVO.setStatusLabel(CarWaybillEnum.getName(sckwWaybillOrder.getStatus()));
            waybillBoardListVO.setGoodsName(String.valueOf(sckwWaybillOrder.getGoodsName()));
            waybillBoardListVO.setLoadAmount(sckwWaybillOrder.getLoadAmount());
            waybillBoardListVO.setLoadName(sckwWaybillOrder.getLoadName());
            waybillBoardListVO.setLoadDetailAddress(String.valueOf(sckwWaybillOrder.getLoadDetailAddress()));
            waybillBoardListVO.setUnloadAmount(sckwWaybillOrder.getUnloadAmount());
            waybillBoardListVO.setUnloadName(sckwWaybillOrder.getUnloadName());
            waybillBoardListVO.setUnloadDetailAddress(String.valueOf(sckwWaybillOrder.getUnloadDetailAddress()));
            waybillBoardListVO.setStartTime(DateUtil.getDateTime(sckwWaybillOrder.getStartTime()));
            waybillBoardListVO.setEndTime(DateUtil.getDateTime(sckwWaybillOrder.getEndTime()));
            waybillBoardListVO.setFirmName(String.valueOf(sckwWaybillOrder.getFirmName()));
            waybillBoardListVO.setCreateByName(String.valueOf(sckwWaybillOrder.getCreateByName()));
            waybillBoardListVO.setCreateTime(DateUtil.getDateTime(sckwWaybillOrder.getCreateTime()));
            waybillBoardListVO.setDriverName(String.valueOf(sckwWaybillOrder.getDriverName()));
            waybillBoardListVO.setDriverPhone(String.valueOf(sckwWaybillOrder.getDriverPhone()));
            waybillBoardListVO.setTruckNo(String.valueOf(sckwWaybillOrder.getTruckNo()));
            waybillBoardListVO.setLoadGrossAmount(sckwWaybillOrder.getLoadGrossAmount() != null ? String.valueOf(sckwWaybillOrder.getLoadGrossAmount()) : null);
            waybillBoardListVO.setUnloadGrossAmount(sckwWaybillOrder.getUnloadGrossAmount() != null ? String.valueOf(sckwWaybillOrder.getUnloadGrossAmount()) : null);
            waybillBoardListVO.setLoadUrls(FileUtils.splice(sckwWaybillOrder.getLoadUrls()));
            waybillBoardListVO.setUnloadUrls(FileUtils.splice(sckwWaybillOrder.getUnloadUrls()));

            List<WaybillStatusVO> statusVOS2 = new ArrayList<>();
            statusVOS.forEach(e -> {
                WaybillStatusVO temp = new WaybillStatusVO();
                BeanUtils.copyProperties(e, temp);
                statusVOS2.add(temp);
            });
            waybillBoardListVO.setTracks(statusVOS2);
            // 运单量单位
            waybillBoardListVO.setUnit(sckwWaybillOrder.getUnit());
            if (sckwWaybillOrder.getUnit() != null) {
                Map<String, String> unitType = commonService.getDictData(DictTypeEnum.UNIT_TYPE.getType());
                String sysDict = unitType == null ? null : unitType.get(sckwWaybillOrder.getUnit());
                waybillBoardListVO.setUnitLabel(sysDict);
            }
            // 运单进度
            List<KwtWaybillOrderTrack> kwtWaybillOrderTracks = kwtWaybillOrderTrackMapper
                    .selectList(new LambdaQueryWrapper<KwtWaybillOrderTrack>()
                            .eq(KwtWaybillOrderTrack::getWOrderId, sckwWaybillOrder.getWOrderId()));

            if (CollectionUtils.isNotEmpty(kwtWaybillOrderTracks)) {
                List<Long> userIds = new ArrayList<>();
                kwtWaybillOrderTracks.forEach(e -> userIds.add(e.getCreateBy()));
                List<UserInfoVo> users = commonService.findUserList(userIds);
                Map<Long, String> usersMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
                users.forEach(e -> usersMap.put(e.getId(), e.getName()));
                waybillBoardListVO.getTracks().forEach(e -> {
                    kwtWaybillOrderTracks.forEach(e2 -> {
                        if (e.getCode().equals(e2.getStatus())) {
                            e.setStatus(true);
                            e.setId(e2.getId());
                            e.setOperateTime(e2.getOperateTime() == null ? null : DateUtil.getDateTime(e2.getOperateTime()));
                            e.setCreateTime(e2.getCreateTime() == null ? null : DateUtil.getDateTime(e2.getCreateTime()));
                            e.setCreateByName(usersMap.get(e2.getCreateBy()) == null ? null : usersMap.get(e2.getCreateBy()));
                        }
                    });
                });
            }
            returnList.add(waybillBoardListVO);
        }
    }

    /**
     * @return
     */
    public List<Integer> initWaybillIndexStatus() {
        List<Integer> statuses = new ArrayList<>();
        statuses.add(CarWaybillEnum.PENDING_ORDER.getCode());
        statuses.add(CarWaybillEnum.PENDING_VEHICLE.getCode());
        statuses.add(CarWaybillEnum.EXIT_COMPLETED.getCode());
        statuses.add(CarWaybillEnum.WAIT_LOADING.getCode());
        statuses.add(CarWaybillEnum.COMPLETION_LOADING.getCode());
        statuses.add(CarWaybillEnum.WAIT_UNLOADING.getCode());
        statuses.add(CarWaybillEnum.COMPLETION_UNLOADING.getCode());
        statuses.add(CarWaybillEnum.APPROVAL_PASS.getCode());
//        List<Integer> statuses = CarWaybillEnum.getCodes();
        return statuses;
    }

    /**
     * 运单看板 查询条件构造
     *
     * @param query
     * @return
     */
    public Criteria buildWaybillIndexQuery(WaybillOrderDTO query) {
        Criteria criteria = new Criteria();
        criteria.and("entId").is(LoginUserHolder.getEntId());
        criteria.and("delFlag").is(NumberConstant.ZERO);

        // 运单创建人或有关授权用户
        List<Long> userIds = LoginUserHolder.getAuthUserIdList();
        criteria.and("createBy").in(userIds);

        List<Long> wOrderIds = StringUtils.splitStrToList(query.getIds(), ",", Long.class);
        if (CollectionUtils.isNotEmpty(wOrderIds)) {
            Criteria.where("wOrderId").in(wOrderIds);
        }
        /**
         * 【拒绝接单】、【拒绝出车】、【已撤销】状态在列表页的表头，都归类到【已作废】状态中；
         *
         * 【审核通过】、【核单驳回】、【修改审核】状态都归类于【单证审核】大类状态下
         * */
        if (StringUtils.isNotBlank(query.getStatus()) && (!"all".equals(query.getStatus()))) {
            List<Long> statuses = new ArrayList<>();
            if (query.getStatus().equals(CarWaybillQueryEnum.DOCUMENT_CHECK.getStatus())) {
                statuses.add(CarWaybillEnum.APPROVAL_IN.getCode().longValue());
                statuses.add(CarWaybillEnum.APPROVAL_NO_PASS.getCode().longValue());
                statuses.add(CarWaybillEnum.APPROVAL_PASS.getCode().longValue());
                criteria.and("status").in(statuses);
            } else if (query.getStatus().equals(String.valueOf(CarWaybillQueryEnum.ABROGATE.getCode()))) {
                statuses.add(CarWaybillEnum.REJECT_ORDER.getCode().longValue());
                statuses.add(CarWaybillEnum.REFUSE_TRAFFIC.getCode().longValue());
                statuses.add(CarWaybillEnum.REVOKED.getCode().longValue());
                criteria.and("status").in(statuses);
            } else {
                criteria.and("status").is(Integer.valueOf(query.getStatus()));
            }
        }
        // 装载时间
        if (Objects.nonNull(query.getStartLoadTime()) && Objects.nonNull(query.getEndLoadTime())) {
            criteria.and("loadTime").gte(query.getStartLoadTime()).lte(DateUtil.offsetDay(query.getEndLoadTime(), 1));
        } else if (Objects.nonNull(query.getStartLoadTime())) {
            criteria.and("loadTime").gte(query.getStartLoadTime());
        } else if (Objects.nonNull(query.getEndLoadTime())) {
            criteria.and("loadTime").lte(DateUtil.offsetDay(query.getEndLoadTime(), 1));
        }
        // 派车时间
        if (Objects.nonNull(query.getStartSendCarTime()) && Objects.nonNull(query.getEndSendCarTime())) {
            criteria.and("sendCarTime").gte(query.getStartSendCarTime()).lte(DateUtil.offsetDay(query.getEndSendCarTime(), 1));
        } else if (Objects.nonNull(query.getStartSendCarTime())) {
            criteria.and("sendCarTime").gte(query.getStartSendCarTime());
        } else if (Objects.nonNull(query.getEndSendCarTime())) {
            criteria.and("sendCarTime").lte(DateUtil.offsetDay(query.getEndSendCarTime(), 1));
        }
        // 卸货时间
        if (Objects.nonNull(query.getStartUnloadTime()) && Objects.nonNull(query.getEndUnloadTime())) {
            criteria.and("unloadTime").gte(query.getStartUnloadTime()).lte(DateUtil.offsetDay(query.getEndUnloadTime(), 1));
        } else if (Objects.nonNull(query.getStartUnloadTime())) {
            criteria.and("unloadTime").gte(query.getStartUnloadTime());
        } else if (Objects.nonNull(query.getEndUnloadTime())) {
            criteria.and("unloadTime").lte(DateUtil.offsetDay(query.getEndUnloadTime(), 1));
        }

        // 装货地址
        String loadCode = query.getLoadCityCode();
        if (StringUtils.isNotBlank(loadCode)) {
            switch (query.getLoadCityCodeLevel()) {
                case 1 -> criteria.and("loadCityCode")
                        .regex(Pattern.compile("^" + loadCode.substring(0, 2) + ".*$", Pattern.CASE_INSENSITIVE));
                case 2 -> criteria.and("loadCityCode")
                        .regex(Pattern.compile("^" + loadCode.substring(0, 4) + ".*$", Pattern.CASE_INSENSITIVE));
                case 3 -> criteria.and("loadCityCode").is(loadCode);
            }
        }

        // 卸货地址
        String unloadCode = query.getUnloadCityCode();
        if (StringUtils.isNotBlank(unloadCode)) {
            switch (query.getUnloadCityCodeLevel()) {
                case 1 -> criteria.and("unloadCityCode")
                        .regex(Pattern.compile("^" + unloadCode.substring(0, 2) + ".*$", Pattern.CASE_INSENSITIVE));
                case 2 -> criteria.and("unloadCityCode")
                        .regex(Pattern.compile("^" + unloadCode.substring(0, 4) + ".*$", Pattern.CASE_INSENSITIVE));
                case 3 -> criteria.and("unloadCityCode").is(unloadCode);
            }
        }

        // 多条件模糊查询
        List<Criteria> orCriteria = new ArrayList<>();
        if (StringUtils.isNotBlank(query.getKeywords())) {
            Pattern pattern = Pattern.compile("^.*" + query.getKeywords() + ".*$", Pattern.CASE_INSENSITIVE);
            orCriteria.add(Criteria.where("wOrderNo").regex(pattern));
            orCriteria.add(Criteria.where("truckNo").regex(pattern));
            orCriteria.add(Criteria.where("driverName").regex(pattern));
            orCriteria.add(Criteria.where("firmName").regex(pattern));
            criteria.orOperator(orCriteria);
        }
        return criteria;
    }

    /**
     * 运单看板TOP
     *
     * @param query
     * @return
     */
    public HttpResult waybillIndexStatistics(WaybillOrderDTO query) {
        List<Integer> statuses = initWaybillIndexStatus();
        Criteria criteria = buildWaybillIndexQuery(query);
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria),
                Aggregation.group("status").count().as("total"),
                Aggregation.project("total").and("value").previousOperation()
        );
        AggregationResults<TableTops> outputTypeCount = mongoTemplate.aggregate(aggregation, SckwWaybillOrder.class, TableTops.class);
        List<TableTops> results = outputTypeCount.getMappedResults();
        Integer allTotal = 0;
        // 填充默认值
        List<TableTops> list = new ArrayList<>();
        TableTops topTotal = new TableTops();
        topTotal.setName("全部");
        topTotal.setValue("all");
        topTotal.setTotal(0);

        //已作废
        TableTops topExpired = new TableTops();
        topExpired.setName(CarWaybillQueryEnum.ABROGATE.getDestination());
        topExpired.setValue(CarWaybillQueryEnum.ABROGATE.getStatus());
        topExpired.setTotal(0);

        //单据审核
        TableTops documentCheck = new TableTops();
        documentCheck.setName(CarWaybillQueryEnum.DOCUMENT_CHECK.getDestination());
        documentCheck.setValue(CarWaybillQueryEnum.DOCUMENT_CHECK.getStatus());
        documentCheck.setTotal(0);

        list.addAll(results);
        list.add(topExpired);
        list.add(documentCheck);

        /**数据统计计算*/
        //单证审核合并计算
        documentCheckNumberCount(list);
        //已作废合并计算
        abrogateNumberCount(list);
        /**补齐全部状态值*/
        List<String> codeList = CarWaybillEnum.getStringCodes();
        List<String> collect = list.stream().map(e -> e.getValue()).collect(Collectors.toList());
        List<String> diffrentList = getDiffrentList(collect, codeList);
        for (String s : diffrentList) {
            TableTops top = new TableTops();
            top.setValue(s);
            top.setTotal(NumberConstant.ZERO);
            top.setSort(Integer.valueOf(s));
            list.add(top);
        }
        /**状态赋值翻译*/
        for (CarWaybillEnum waybillEnum : CarWaybillEnum.values()) {
            for (TableTops tops : list) {
                if (waybillEnum.getStatus().equals(tops.getValue())) {
                    tops.setName(waybillEnum.getDestination());
                    tops.setSort(waybillEnum.getCode());
                    continue;
                }
            }
        }
        /**去除不展示统计字段*/
        List<TableTops> returnList = new ArrayList<>();
        for (TableTops tops : list) {
            if ((!CarWaybillEnum.REFUSE_TRAFFIC.getStatus().equals(tops.getValue()))
                    && (!CarWaybillEnum.APPROVAL_NO_PASS.getStatus().equals(tops.getValue()))
                    && (!CarWaybillEnum.REVOKED.getStatus().equals(tops.getValue()))
                    && (!CarWaybillEnum.REJECT_ORDER.getStatus().equals(tops.getValue()))
                    && (!CarWaybillEnum.APPROVAL_NO_PASS.getStatus().equals(tops.getValue()))
                    && (!CarWaybillEnum.APPROVAL_IN.getStatus().equals(tops.getValue()))
                    && (!CarWaybillEnum.APPROVAL_PASS.getStatus().equals(tops.getValue()))
            ) {
                returnList.add(tops);
            }
        }

        /**排序*/
        returnList = returnList.stream().sorted(Comparator.comparing(TableTops::getSort)).collect(Collectors.toList());
        allTotal = results.stream().collect(Collectors.summingInt(TableTops::getTotal));
        topTotal.setTotal(allTotal);
        returnList.add(0, topTotal);
        return HttpResult.ok(returnList);
    }

    /**
     * 统计top计算
     *
     * @param results
     */
    private void documentCheckNumberCount(List<TableTops> results) {
        if (!org.springframework.util.CollectionUtils.isEmpty(results)) {
            //单证审核计算包含审核通过、审核更新审核中以及审核不通过
            Integer documentCheck = 0;
            for (TableTops result : results) {
                //单证审核计算
                if (CarWaybillEnum.APPROVAL_IN.getStatus().equals(result.getValue())
                        || CarWaybillEnum.APPROVAL_NO_PASS.getStatus().equals(result.getValue())
                        || CarWaybillEnum.APPROVAL_PASS.getStatus().equals(result.getValue())) {
                    documentCheck = documentCheck + result.getTotal();
                }
            }
            for (TableTops result : results) {
                if (CarWaybillQueryEnum.DOCUMENT_CHECK.getStatus().equals(result.getValue())) {
                    result.setTotal(documentCheck);
                    result.setSort(CarWaybillQueryEnum.DOCUMENT_CHECK.getCode());
                    break;
                }
            }
        }
    }

    /**
     * 统计top计算
     *
     * @param results
     */
    private void abrogateNumberCount(List<TableTops> results) {
        if (!org.springframework.util.CollectionUtils.isEmpty(results)) {
            //已作废包含本身以及拒绝出车、已撤销、拒绝接单
            Integer orderCancellation = 0;
            for (TableTops result : results) {
                //已作废计算
                if (CarWaybillEnum.REJECT_ORDER.getStatus().equals(result.getValue())
                        || CarWaybillEnum.REVOKED.getStatus().equals(result.getValue())
                        || CarWaybillEnum.REFUSE_TRAFFIC.getStatus().equals(result.getValue())
                ) {
                    orderCancellation = orderCancellation + result.getTotal();
                }
            }
            for (TableTops result : results) {
                if (CarWaybillQueryEnum.ABROGATE.getStatus().equals(result.getValue())) {
                    result.setTotal(orderCancellation);
                    result.setSort(CarWaybillQueryEnum.ABROGATE.getCode());
                }
            }
        }
    }


    /**
     * @param sourceList 源数据  [1]
     * @param targetList 目标数据 [1,2,3]
     * @Description: 获取targetList中在sourceList中不存在的项
     * @return: List<String>    [2,3]
     */
    public List<String> getDiffrentList(List<String> sourceList, List<String> targetList) {
        return targetList.stream().filter(item -> sourceList.stream().allMatch(each -> !item.equals(each))).collect(Collectors.toList());
    }

    /**
     * app 运单分类统计数据 [运输中|已完成]
     *
     * @param keyword
     * @return
     */
    public HttpResult waybillDataStatisticApp(String keyword, String startDate, String endDate) {
        Long entId = LoginUserHolder.getEntId();
        if (StringUtils.isNotBlank(startDate)) {
            startDate = StringTimeUtil.fillStart(startDate);
        }
        if (StringUtils.isNotBlank(endDate)) {
            endDate = StringTimeUtil.fillEnd(endDate);
        }
        // 运输途中
        Map<String, String> _onway = new HashMap<>();
        _onway.put("name", "运输中");
        _onway.put("value", "onway");
        _onway.put("total", "0");
        List<Long> onWayStates = getWallBillStatues("onway");
        Long onWayCount = kwtWaybillOrderMapper.selectWaybillOrderCountByStatus(
            entId,
            LoginUserHolder.getAuthUserIdList(),
            onWayStates,
            keyword,
            null,
            null
        );
        _onway.put("total", onWayCount.toString());
        // 已完成
        Map<String, String> _finish = new HashMap<>();
        _finish.put("name", "已完成");
        _finish.put("value", "finish");
        _finish.put("total", "0");
        List<Long> finishStates = getWallBillStatues("finish");
        Long finishCount = kwtWaybillOrderMapper.selectWaybillOrderCountByStatus(
            entId,
            LoginUserHolder.getAuthUserIdList(),
            finishStates,
            keyword,
            startDate,
            endDate
        );
        _finish.put("total", finishCount.toString());
        List<Map<String, String>> _list = new ArrayList<>();
        _list.add(_onway);
        _list.add(_finish);
        return HttpResult.ok(_list);
    }

    /**
     * app 运单列表 [运输中|已完成]
     *
     * @param query
     * @return
     */
    public HttpResult waybillDataApp(WaybillListAppDTO query) {
        List<Integer> processStatuses = initWaybillIndexStatus();
        List<Long> _statuses = getWallBillStatues(query.getStatus());
        Criteria criteria = new Criteria();
        criteria.and("entId").is(LoginUserHolder.getEntId());
        criteria.and("delFlag").is(NumberConstant.ZERO);
        // 多条件模糊查询
        List<Criteria> orCriteria = new ArrayList<>();
        if (StringUtils.isNotBlank(query.getKeyword())) {
            Pattern pattern = Pattern.compile("^.*" + query.getKeyword() + ".*$", Pattern.CASE_INSENSITIVE);
            orCriteria.add(Criteria.where("wOrderNo").regex(pattern));
            orCriteria.add(Criteria.where("truckNo").regex(pattern));
            orCriteria.add(Criteria.where("driverName").regex(pattern));
            orCriteria.add(Criteria.where("firmName").regex(pattern));
            criteria.orOperator(orCriteria);
        }
        // in查询
        if (CollectionUtils.isNotEmpty(_statuses)) {
            criteria.and("status").in(_statuses);
        }
        // 查询时间段
        if (Objects.nonNull(query.getStartDate()) && Objects.nonNull(query.getEndDate())) {
            criteria.and("createTime")
                    .gte(DateUtil.strDateTimeToDateTime(StringTimeUtil.fillStart(query.getStartDate())))
                    .lte(DateUtil.strDateTimeToDateTime(StringTimeUtil.fillEnd(query.getEndDate())));
        }
        Query queryFormat = new Query(criteria);
        // 总记录数
        long total = mongoTemplate.count(queryFormat, SckwWaybillOrder.class);
        queryFormat.with(PageRequest.of(query.getPage() - 1, query.getPageSize(),
                Sort.by(Sort.Order.desc("createTime"))));
        // 执行查询
        List<SckwWaybillOrder> list = mongoTemplate.find(queryFormat, SckwWaybillOrder.class);
        List<WaybillBoardListVO> returnList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(list)) {
            List<WaybillStatusVO> statusVOS = new ArrayList();
            processStatuses.forEach(e -> {
                WaybillStatusVO waybillStatusVO = new WaybillStatusVO();
                waybillStatusVO.setStatus(false);
                waybillStatusVO.setCode(e);
                waybillStatusVO.setDestination(CarWaybillEnum.getName(e));
                statusVOS.add(waybillStatusVO);
            });
            packageWaybillIndexResult(list, statusVOS, returnList);
        }
        PageResult build = PageResult.build(query.getPage(), query.getPageSize(), total, returnList);
        return HttpResult.ok(build);
    }

    /**
     * 物流订单-运单列表
     *
     * @param query
     * @return
     */
    public HttpResult logisticOrderWaybillData(WaybillListAppDTO query) {
        List<Integer> processStatuses = initWaybillIndexStatus();
        Criteria criteria = new Criteria();
        criteria.and("delFlag").is(NumberConstant.ZERO);

        List<Long> lOrderIds = StringUtils.splitStrToList(query.getLOrderId(), ",", Long.class);
        if (CollectionUtils.isEmpty(lOrderIds)) {
            return HttpResult.ok();
        }
        criteria.and("lOrderId").in(lOrderIds);
        criteria.and("wOrderId").ne("").ne(null);
        // 多条件模糊查询
        List<Criteria> orCriteria = new ArrayList<>();
        if (StringUtils.isNotBlank(query.getKeyword())) {
            Pattern pattern = Pattern.compile("^.*" + query.getKeyword() + ".*$", Pattern.CASE_INSENSITIVE);
            orCriteria.add(Criteria.where("wOrderNo").regex(pattern));
            orCriteria.add(Criteria.where("truckNo").regex(pattern));
            orCriteria.add(Criteria.where("driverName").regex(pattern));
            orCriteria.add(Criteria.where("firmName").regex(pattern));
            criteria.orOperator(orCriteria);
        }
        Query queryFormat = new Query(criteria);
        // 总记录数
        long total = mongoTemplate.count(queryFormat, SckwWaybillOrder.class);
        queryFormat.with(PageRequest.of(query.getPage() - 1, query.getPageSize(),
                Sort.by(Sort.Order.desc("createTime"))));
        // 执行查询
        List<SckwWaybillOrder> list = mongoTemplate.find(queryFormat, SckwWaybillOrder.class);
        List<WaybillBoardListVO> returnList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(list)) {
            List<WaybillStatusVO> statusVOS = new ArrayList();
            processStatuses.forEach(e -> {
                WaybillStatusVO waybillStatusVO = new WaybillStatusVO();
                waybillStatusVO.setStatus(false);
                waybillStatusVO.setCode(e);
                waybillStatusVO.setDestination(CarWaybillEnum.getName(e));
                statusVOS.add(waybillStatusVO);
            });
            packageWaybillIndexResult(list, statusVOS, returnList);
        }

        PageResult build = PageResult.build(query.getPage(), query.getPageSize(), total, returnList);
        return HttpResult.ok(build);
    }


    /**
     * app 运单分类吨量统计数据 [运输中|已完成]
     *
     * @param query
     * @return
     */
    public HttpResult waybillAmountStatistic(WaybillListAppDTO query) {
        List<Long> _statuses = getWallBillStatues(query.getStatus());
        List<WaybillAmountDTO> wOrders = kwtWaybillOrderMapper.selectWaybillOrdersByStatus(
                LoginUserHolder.getEntId(),
                LoginUserHolder.getAuthUserIdList(),
                _statuses,
                query.getKeyword(),
                StringUtils.isBlank(query.getStartDate()) ? null : StringTimeUtil.fillStart(query.getStartDate()),
                StringUtils.isBlank(query.getEndDate()) ? null : StringTimeUtil.fillEnd(query.getEndDate())
        );
        Map<String, String> amount = new HashMap<>();
        // 总计条数
        amount.put("total", String.valueOf(wOrders.size()));
        BigDecimal loadAmount = new BigDecimal(Global.AMOUNT);
        BigDecimal unloadAmount = new BigDecimal(Global.AMOUNT);
        BigDecimal lossAmount = new BigDecimal(Global.AMOUNT);
        BigDecimal deficitRealAmount = new BigDecimal(Global.AMOUNT);
        if(CollectionUtils.isNotEmpty(wOrders)) {
            for (WaybillAmountDTO wOrder:wOrders) {
                loadAmount = loadAmount.add(wOrder.getLoadAmount() == null ? new BigDecimal(Global.AMOUNT) : wOrder.getLoadAmount());
                unloadAmount = unloadAmount.add(wOrder.getUnloadAmount() == null ? new BigDecimal(Global.AMOUNT) : wOrder.getUnloadAmount());
                lossAmount = lossAmount.add(wOrder.getDeficitAmount() == null ? new BigDecimal(Global.AMOUNT) : wOrder.getDeficitAmount());
                if(wOrder.getLoadAmount() != null
                        && wOrder.getUnloadAmount() != null
                        && wOrder.getDeficitAmount() != null
                ) {
                    BigDecimal realDeficitAMount = commonService.deficitLossAmount(
                            wOrder.getLoadAmount(),
                            wOrder.getDeficitAmount(),
                            wOrder.getLoss(),
                            wOrder.getLossUnit()
                    );
                    deficitRealAmount = deficitRealAmount.add(realDeficitAMount);
                }
            }
        }
        // 总计装货量
        amount.put("loadAmount",  String.valueOf(loadAmount));
        // 总计卸货量
        amount.put("unloadAmount",  String.valueOf(unloadAmount));
        // 总计货损量
        amount.put("lossAmount",  String.valueOf(lossAmount));
        // 总计扣亏量
        amount.put("deficitRealAmount",  String.valueOf(deficitRealAmount));
        return HttpResult.ok(amount);
    }

    /**
     * 获取 [运输中|已完成] 状态列表
     *
     * @param status
     * @return
     */
    public List<Long> getWallBillStatues(String status) {
        List<Long> _list = new ArrayList<>();
        if (status.equals("onway")) {
            _list.add(CarWaybillEnum.PENDING_ORDER.getCode().longValue());
            _list.add(CarWaybillEnum.PENDING_VEHICLE.getCode().longValue());
            _list.add(CarWaybillEnum.EXIT_COMPLETED.getCode().longValue());
            _list.add(CarWaybillEnum.WAIT_LOADING.getCode().longValue());
            _list.add(CarWaybillEnum.COMPLETION_LOADING.getCode().longValue());
            _list.add(CarWaybillEnum.WAIT_UNLOADING.getCode().longValue());
        }
        if (status.equals("finish")) {
            _list.add(CarWaybillEnum.COMPLETION_UNLOADING.getCode().longValue());
            _list.add(CarWaybillEnum.APPROVAL_PASS.getCode().longValue());
            _list.add(CarWaybillEnum.APPROVAL_NO_PASS.getCode().longValue());
            _list.add(CarWaybillEnum.APPROVAL_IN.getCode().longValue());
        }
        return _list;
    }

    /**
     * @desc 获取企业地址信息
     * @author zk
     * @date 2023/9/1
     **/
    public AddressDropListDTO findAddressList() {
        AddressDropListDTO res = new AddressDropListDTO();
        //装货地址树
        List<Integer> loadAddressList = kwtWaybillOrderAddressMapper.findAddressCodeList(LoginUserHolder.getEntId(), Global.NUMERICAL_ONE);
        //卸货地址树
        List<Integer> unloadAddressList = kwtWaybillOrderAddressMapper.findAddressCodeList(LoginUserHolder.getEntId(), Global.NUMERICAL_TWO);

        //装货地址下拉列表树
        List<AreaTreeFrontResDto> loadTree = remoteSystemService.queryAreaTreeFrontByCodeList(loadAddressList);
        res.setLoadAddressList(loadTree);
        //卸货地址下拉列表树
        List<AreaTreeFrontResDto> unloadTree = remoteSystemService.queryAreaTreeFrontByCodeList(unloadAddressList);
        res.setUnloadAddressList(unloadTree);
        return res;
    }
}
