package com.sckw.report.service;

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.enums.LogisticsOrderEnum;
import com.sckw.core.model.enums.TaxRateTypeEnum;
import com.sckw.core.model.page.PageResult;
import com.sckw.core.utils.BeanUtils;
import com.sckw.core.utils.CollectionUtils;
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.DateUtil;
import com.sckw.mongo.model.SckwLogisticsOrder;
import com.sckw.mongo.model.SckwWaybillOrder;
import com.sckw.mongo.model.TableTops;
import com.sckw.report.dao.SckwLogisticsOrderRepository;
import com.sckw.report.service.param.ContractParam;
import com.sckw.report.service.param.WaybillOrderListExport;
import com.sckw.report.service.param.WaybillOrderListSelect;
import com.sckw.report.service.param.WaybillOrderQuery;
import com.sckw.report.service.vo.CarWaybillVo;
import com.sckw.report.service.vo.WaybillsCountVo;
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 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 java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author zk
 * @desc 运输服务
 * @date 2023/7/10 0010
 */
@Slf4j
@Service
public class KwTransportService {

    @Autowired
    public SckwLogisticsOrderRepository sckwLogisticsOrderRepository;

    @Autowired
    private MongoTemplate mongoTemplate;

//    @DubboReference(version = "1.0.0", group = "design", check = false)
//    TransportDubboService transportDubboService;

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

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

//    /**
//     * 托运订单-承运订单(订单详情)
//     * @param id
//     * @return
//     */
//    public HttpResult getOrderDetail(Long id) {
//        Query query = new Query();
//        Criteria criteria = new Criteria();
//        // 1. 全等于
//        criteria.and("entId").is(LoginUserHolder.getEntId());
//        criteria.and("_id").is(id);
//        criteria.and("delFlag").is(NumberConstant.ZERO);
//        query.addCriteria(criteria);
//        SckwLogisticsOrder sckwLogisticsOrder = mongoTemplate.findById(id, SckwLogisticsOrder.class);
//        return HttpResult.ok(sckwLogisticsOrder);
//    }

    /**
     * 司机端 运单详情页面-【作废】
     *
     * @param id
     * @param type
     * @return
     */
    public HttpResult getWaybillDriverDetail(Long id, String type) {
        HttpResult result = new HttpResult();

        /**
         * 当前司机端页面 页面【计划】=1；【出车】=2；【执行】=3；【完结】=4
         * 计划:对应运单状态的[待接单]
         * 出车:对应运单状态的[待出车]
         * 执行:对应[已出车][到达装货地点]、[已装货]、[到达卸货地点]
         * 完结: 对应[已卸货]、[已核单]
         * */

        List<Long> status = new ArrayList<>();
        if (String.valueOf(NumberConstant.ONE).equals(type)) {
            status.add(CarWaybillEnum.PENDING_ORDER.getCode().longValue());
        } else if (String.valueOf(NumberConstant.TWO).equals(type)) {
            status.add(CarWaybillEnum.PENDING_VEHICLE.getCode().longValue());
        } else if (String.valueOf(NumberConstant.THREE).equals(type)) {
            status.add(CarWaybillEnum.EXIT_COMPLETED.getCode().longValue());
            status.add(CarWaybillEnum.WAIT_LOADING.getCode().longValue());
            status.add(CarWaybillEnum.COMPLETION_LOADING.getCode().longValue());
            status.add(CarWaybillEnum.WAIT_UNLOADING.getCode().longValue());
        } else if (String.valueOf(NumberConstant.FOUR).equals(type)) {
            status.add(CarWaybillEnum.COMPLETION_UNLOADING.getCode().longValue());
            status.add(CarWaybillEnum.APPROVAL_PASS.getCode().longValue());
        } else {
            result.setMsg("类型错误");
            result.setCode(HttpStatus.GLOBAL_EXCEPTION_CODE);
            return result;
        }
        // 创建条件对象
        Criteria criteria = new Criteria();
        Query query = new Query(criteria);
        //in查询
        if (CollectionUtils.isNotEmpty(status)) {
            query.addCriteria(Criteria.where("_id").in(status));
        }
        // 执行查询
        List<SckwWaybillOrder> all1 = mongoTemplate.findAll(SckwWaybillOrder.class);
        return HttpResult.ok(all1);
    }

//    public List<KwtLogisticsOrderVO> transportDubboService(List<String> ids) {
//        List<KwtLogisticsOrderVO> acceptCarriageOrderDetail = transportDubboService.getAcceptCarriageOrderDetail(ids);
//        return acceptCarriageOrderDetail;
//    }

    /**
     * 获取运单列表
     *
     * @param query
     * @return {@link HttpResult }
     * @author jc
     * @date 2023/07/21
     */
    public HttpResult getWaybillOrders(WaybillOrderListSelect query) throws ParseException {
        Criteria criteria = newBuildWaybillOrdersQuery(query);
        Query queryFormat = new Query(criteria);
        // in查询
        List<Long> wOrderIds = StringUtils.splitStrToList(query.getIds(), ",", Long.class);
        if (CollectionUtils.isNotEmpty(wOrderIds)) {
            queryFormat.addCriteria(Criteria.where("wOrderId").in(wOrderIds));
        }

        // 总记录数
        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<CarWaybillVo> returnList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(list)) {
            packageWayBillReturnList(list, returnList, query.getStatus());
        }
        PageResult build = PageResult.build(query.getPage(), query.getPageSize(), total, returnList);
        return HttpResult.ok(build);
    }

    /**
     * 构造运单关联查询条件
     *
     * @param query
     * @return
     */
    public Criteria newBuildWaybillOrdersQuery(WaybillOrderQuery 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);

        /**
         * 【拒绝接单】、【拒绝出车】、【已撤销】状态在列表页的表头，都归类到【已作废】状态中；
         *
         * 【审核通过】、【核单驳回】、【修改审核】状态都归类于【单证审核】大类状态下
         * */
        if (StringUtils.isNotBlank(query.getStatus()) && (!"all".equals(query.getStatus()))) {
            List<Integer> statuses = new ArrayList<>();
            if (query.getStatus().equals(CarWaybillQueryEnum.DOCUMENT_CHECK.getStatus())) {
                statuses.add(CarWaybillEnum.APPROVAL_IN.getCode());
                statuses.add(CarWaybillEnum.APPROVAL_NO_PASS.getCode());
                statuses.add(CarWaybillEnum.APPROVAL_PASS.getCode());
                criteria.and("status").in(statuses);
            } else if (query.getStatus().equals(String.valueOf(CarWaybillQueryEnum.ABROGATE.getCode()))) {
                statuses.clear();
                statuses.add(CarWaybillEnum.REJECT_ORDER.getCode());
                statuses.add(CarWaybillEnum.REFUSE_TRAFFIC.getCode());
                statuses.add(CarWaybillEnum.REVOKED.getCode());
                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 {@link HttpResult }
     * @author jc
     * @date 2023/07/21
     */
    public HttpResult getWayBillStatistics(WaybillOrderQuery query) {
        Criteria criteria = newBuildWaybillOrdersQuery(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();
        // 填充默认值
        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);
//        ArrayList<Long> expiredStatuses = new ArrayList<>();
//        expiredStatuses.add(CarWaybillEnum.REJECT_ORDER.getCode().longValue());
//        expiredStatuses.add(CarWaybillEnum.REFUSE_TRAFFIC.getCode().longValue());
//        expiredStatuses.add(CarWaybillEnum.REVOKED.getCode().longValue());
//        expiredStatuses.add(CarWaybillEnum.APPROVAL_NO_PASS.getCode().longValue());
//        for (CarWaybillEnum status : CarWaybillEnum.values()) {
//            boolean expiredFlag = expiredStatuses.contains(status.getCode().longValue());
//            TableTops top = new TableTops();
//            top.setName(status.getDestination());
//            top.setValue(String.valueOf(status.getCode()));
//            top.setTotal(0);
//            if (CollectionUtils.isNotEmpty(results)) {
//                for (TableTops result : results) {
//                    if (StringUtils.isNotEmpty(result.getValue())
//                            && String.valueOf(result.getValue()).equals(String.valueOf(status.getCode()))) {
//                        if (expiredFlag) {
//                            topExpired.setTotal(topExpired.getTotal() + result.getTotal());
//                        } else {
//                            top.setTotal(result.getTotal());
//                        }
//                        break;
//                    }
//                }
//            }
//            if (!expiredFlag) {
//                list.add(top);
//            }
//        }
        /**数据统计计算*/
        //单证审核合并计算
        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.add(topExpired);
        /**去除不展示统计字段*/
        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());
        returnList.add(0, topTotal);
        // 总计
        topTotal.setTotal(returnList.parallelStream().mapToInt(item -> item.getTotal()).sum());
        // 查询结果
        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 query 查询
     * @return {@link HttpResult }
     * @author jc
     * @date 2023/07/21
     */
    public HttpResult wayBillTotalCount(WaybillOrderQuery query) {
        // 统计项字段
        Criteria criteria = newBuildWaybillOrdersQuery(query);
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria),
                Aggregation.group("id").count().as("countTotal")
                        .sum("entrustAmount").as("entrustTotal")
                        .sum("loadAmount").as("loadTotal")
                        .sum("unloadAmount").as("unloadTotal"),
                Aggregation.project("countTotal", "entrustTotal", "loadTotal", "unloadTotal")
        );
        AggregationResults<WaybillsCountVo> outputTypeCount = mongoTemplate.aggregate(aggregation, SckwWaybillOrder.class, WaybillsCountVo.class);
        List<WaybillsCountVo> results = outputTypeCount.getMappedResults();
        return HttpResult.ok(results);
    }

    /**
     * 运单处理运单查询结果
     *
     * @param list
     * @param returnList
     */
    private void packageWayBillReturnList(List<SckwWaybillOrder> list, List<CarWaybillVo> returnList, String status) {
        for (SckwWaybillOrder waybillOrder : list) {
            CarWaybillVo vo = new CarWaybillVo();
            vo.setWOrderNo(waybillOrder.getWOrderNo() == null ?
                    null : waybillOrder.getWOrderNo());
            vo.setWOrderId(waybillOrder.getWOrderId() == null ?
                    String.valueOf(waybillOrder.get_id()) : String.valueOf(waybillOrder.getWOrderId()));
            vo.setLOrderNo(waybillOrder.getLOrderNo() == null ?
                    null : waybillOrder.getLOrderNo());
            vo.setTruckNo(waybillOrder.getTruckNo());
            vo.setDriverName(waybillOrder.getDriverName() == null ?
                    null : String.valueOf(waybillOrder.getDriverName()));
            vo.setType(String.valueOf(waybillOrder.getType()));
            String typeString = "";
            if (waybillOrder.getType().equals(NumberConstant.ONE)) {
                typeString = "趟次";
            }
            if (waybillOrder.getType().equals(NumberConstant.TWO)) {
                typeString = "循环";
            }
            vo.setTypeLabel(typeString);
//            if (status.equals(String.valueOf(NumberConstant.ONE_ZERO_ZERO))) {
//                vo.setStatus(String.valueOf(NumberConstant.ONE_ZERO_ZERO));
//            } else {
//                vo.setStatus(waybillOrder.getStatus() == null ?
//                        null : String.valueOf(waybillOrder.getStatus()));
//            }
            vo.setStatus(waybillOrder.getStatus() == null ?
                    null : String.valueOf(waybillOrder.getStatus()));
            vo.setStatusLabel(CarWaybillEnum.getName(waybillOrder.getStatus()));
            // 托量单位
            vo.setUnit(waybillOrder.getUnit() == null ? null : waybillOrder.getUnit());
            if (waybillOrder.getUnit() != null) {
                Map<String, SysDictResDto> unitType = remoteSystemService.queryDictMapByType(DictTypeEnum.UNIT_TYPE.getType());
                if (!unitType.isEmpty()) {
                    SysDictResDto sysDict = unitType.get(waybillOrder.getUnit());
                    vo.setUnitLabel(sysDict == null ? null : sysDict.getLabel());
                }
            }
            vo.setSendCarTime(waybillOrder.getCreateTime() == null ?
                    null : DateUtil.getDateTime(waybillOrder.getCreateTime()));
            vo.setStartTime(waybillOrder.getStartTime() == null ?
                    null : waybillOrder.getStartTime());
            vo.setEndTime(waybillOrder.getEndTime() == null ?
                    null : waybillOrder.getEndTime());
            vo.setEntrustAmount(String.valueOf(waybillOrder.getEntrustAmount()));
            vo.setLoadName(waybillOrder.getLoadName() == null ?
                    null : waybillOrder.getLoadName());
            vo.setLoadAddress((waybillOrder.getLoadCityName() == null ? "" : waybillOrder.getLoadCityName())
                    .concat(waybillOrder.getLoadDetailAddress() == null ? "" : waybillOrder.getLoadDetailAddress()));
            vo.setUnloadName(waybillOrder.getUnloadName() == null ?
                    null : waybillOrder.getUnloadName());
            vo.setUnloadAddress((waybillOrder.getUnloadCityName() == null ? "" : waybillOrder.getUnloadCityName())
                    .concat(waybillOrder.getUnloadDetailAddress() == null ? "" : waybillOrder.getUnloadDetailAddress()));
            vo.setLoadAmount(waybillOrder.getLoadAmount() == null ?
                    null : String.valueOf(waybillOrder.getLoadAmount()));
            vo.setUnloadAmount(waybillOrder.getUnloadAmount() == null ?
                    null : String.valueOf(waybillOrder.getUnloadAmount()));
            vo.setLoadDateTime(waybillOrder.getLoadTime() == null ?
                    null : DateUtil.getDateTime(waybillOrder.getLoadTime()));
            vo.setUnloadDateTime(waybillOrder.getUnloadTime() == null ?
                    null : DateUtil.getDateTime(waybillOrder.getUnloadTime()));
            vo.setCreateTime(waybillOrder.getCreateTime() == null ?
                    null : DateUtil.getDateTime(waybillOrder.getCreateTime()));
            vo.setUpdateTime(waybillOrder.getUpdateTime() == null ?
                    null : DateUtil.getDateTime(waybillOrder.getUpdateTime()));
            // 货损量
            BigDecimal deficitAmount = waybillOrder.getDeficitAmount() == null ?
                    BigDecimal.valueOf(0) : waybillOrder.getDeficitAmount();
            vo.setDeficitAmount(String.valueOf(deficitAmount));
            // 存在装卸货差时 计算扣亏量
            BigDecimal deficitLossAmount = deficitLossAmount(
                    waybillOrder.getLoadAmount(),
                    waybillOrder.getDeficitAmount(),
                    waybillOrder.getLoss(),
                    waybillOrder.getLossUnit());
            // 实际扣亏量
            vo.setDeficitRealAmount(deficitLossAmount.setScale(2, RoundingMode.HALF_UP).toString());
            vo.setGoodsPriceUnit(waybillOrder.getGoodsPriceUnit() == null ?
                    null : String.valueOf(waybillOrder.getGoodsPriceUnit()));
            returnList.add(vo);
        }
    }

    /**
     * 承运订单-分包托运列表数据展示
     *
     * @param lOrderId
     * @param page
     * @param pageSize
     * @return
     */
    public HttpResult getSubcontractConsignment(String lOrderId, int page, int pageSize) {
        //模糊匹配
        //根据条件查询所有并排序，且分页
        //设置模糊查询匹配规则  忽略大小写
        // 创建条件对象
        Criteria criteria = new Criteria();
        // 1. 全等于
//        criteria.and("entId").is(LoginUserHolder.getEntId());
//        criteria.and("_id").is(lOrderId);
//        criteria.and("delFlag").is(String.valueOf(NumberConstant.ZERO));
        Query query1 = new Query(criteria);
        //多条件模糊查询
        Criteria c1 = new Criteria().and("carrierEntId").is(LoginUserHolder.getEntId());
        Criteria c2 = new Criteria().and("_id").is(lOrderId);
        Criteria c3 = new Criteria().and("delFlag").is(String.valueOf(NumberConstant.ZERO));
        criteria.orOperator(c1, c2, c3);
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria),
//                Aggregation.group("_id").sum().as("sum")
                Aggregation.project("total").and("value").previousOperation()
        );
        query1.addCriteria(Criteria.where("pid").in(lOrderId));
        AggregationResults<TableTops> outputTypeCount = mongoTemplate.aggregate(aggregation, SckwLogisticsOrder.class, TableTops.class);
        List<TableTops> mappedResults = outputTypeCount.getMappedResults();
        // 执行查询
//        List<SckwLogisticsOrder> list = mongoTemplate.findAll(query1, SckwLogisticsOrder.class);
////        PageResult build = PageResult.build(query.getPage(), query.getPageSize(), total, list);
//        List<ConsignOrderVo> returnList = new ArrayList<>();
//        if (CollectionUtils.isNotEmpty(list)) {
//            packageReturnList(list, returnList);
//        }
        return null;
    }

    /**
     * 承运合同/托运合同-根据合同id获取托运订单列表
     *
     * @param contractParam
     * @return
     */
    public HttpResult getLogisticsOrderByContractId(ContractParam contractParam) {
        HttpResult result = new HttpResult();
        if (String.valueOf(NumberConstant.ONE).equals(contractParam.getContractType())) {
            result = getLogisticsOrderContract(contractParam, "1");
        } else if (String.valueOf(NumberConstant.TWO).equals(contractParam.getContractType())) {
            result = getLogisticsOrderContract(contractParam, "2");
        } else {
            return HttpResult.error("合同类型错误");
        }
        return result;
    }

    private HttpResult getLogisticsOrderContract(ContractParam contractParam, String unitType) {
        String contractIds = contractParam.getContractIds();
        int page = contractParam.getPage();
        int pageSize = contractParam.getPageSize();
        //模糊匹配
        //根据条件查询所有并排序，且分页
        //设置模糊查询匹配规则  忽略大小写
        // 创建条件对象
        Criteria criteria = new Criteria();
        Long entId = LoginUserHolder.getEntId();
        //判断承运还是托运企业
//        if (unitType.equals(String.valueOf(NumberConstant.ONE))) {
//            //托运
//            criteria.orOperator(
//                    Criteria.where("checkTopEntId").is("177802391955968000"),
//                    Criteria.where("checkEntId").is("177802391955968000"));
//        } else {
//            //承运企业主键ID
////            criteria.and("carrierTopEntId").is(entMap.get(LoginUserHolder.getEntId()).getId());
//            criteria.orOperator(
//                    Criteria.where("carrierTopEntId").is("177802391955968000"),
//                    Criteria.where("carrierEntId").is("177802391955968000"));
//        }
        List<String> stringList = StringUtils.splitStrToList(contractIds, String.class);
        criteria.and("delFlag").is(String.valueOf(NumberConstant.ZERO));
        Query query1 = new Query(criteria);
        // 1. 模糊查询
        if (CollectionUtils.isNotEmpty(stringList)) {
            query1.addCriteria(Criteria.where("contractId").in(stringList));
        } else {
            PageResult build = PageResult.build(page, pageSize, 0L, null);
            return HttpResult.ok(build);
        }
//        if (StringUtils.isBlank(contractIds)) {
//            return HttpResult.error("合同id为空");
//        } else {
//            criteria.and("contractId").is(contractIds);
//        }
        // 12. 总记录数
        long total = mongoTemplate.count(query1, SckwLogisticsOrder.class);
        // 10. 分页
        query1.with(PageRequest.of(page - 1, pageSize, Sort.by(Sort.Direction.DESC, "contractId", "createTime")));
        // 执行查询
        List<SckwLogisticsOrder> list = mongoTemplate.find(query1, SckwLogisticsOrder.class);
        //字典等数据转换
        //计费方式
        Map<String, SysDictResDto> chargingType = remoteSystemService.queryDictMapByType(DictTypeEnum.CHARGING_TYPE.getType());
        //结算周期
        Map<String, SysDictResDto> settlementCycle = remoteSystemService.queryDictMapByType(DictTypeEnum.SETTLEMENT_CYCLE.getType());
        for (SckwLogisticsOrder logisticsOrder : list) {
            Long settlementCycle1 = logisticsOrder.getSettlementCycle();
            String billingMode = logisticsOrder.getBillingMode();
            SysDictResDto sysDictResDto = chargingType.get(String.valueOf(settlementCycle1));
            SysDictResDto sysDictResDto1 = settlementCycle.get(billingMode);
            if (Objects.nonNull(sysDictResDto)) {
                logisticsOrder.setSettlementCycleLabel(sysDictResDto.getLabel());
            }
            if (Objects.nonNull(sysDictResDto1)) {
                logisticsOrder.setBillingModeLabel(sysDictResDto1.getLabel());
            }
            logisticsOrder.setStatusLabel(LogisticsOrderEnum.getDestination(logisticsOrder.getStatus()));
//            logisticsOrder.setCreateTime(DateUtil.offsetDay(logisticsOrder.getCreateTime()))
        }
//        Map<String, List<SckwLogisticsOrder>> atomMap = list.stream().collect(Collectors.groupingBy(SckwLogisticsOrder::getContractId,Collectors.(
//                        Comparator.comparing(SckwLogisticsOrder::getContractId).reversed())));

        Map<String, List<SckwLogisticsOrder>> collect = list.stream().collect(Collectors.groupingBy(SckwLogisticsOrder::getContractId, Collectors.toList()));
        List<SckwLogisticsOrder> returnList = new ArrayList<>();
        for (List<SckwLogisticsOrder> value : collect.values()) {
            returnList.addAll(value);
        }
        PageResult build = PageResult.build(page, pageSize, total, returnList);
        return HttpResult.ok(build);
    }

    /**
     * 运单管理-运单列表 运单地址查询接口
     *
     * @param type
     * @return
     */
    public HttpResult getWayBillAddresses(int type) {
        Criteria criteria = new Criteria();
        criteria.and("entId").is(LoginUserHolder.getEntId());
        criteria.and("delFlag").is(NumberConstant.ZERO);
        Query query = new Query(criteria);
        String field;
        if (type == NumberConstant.ONE) {
            field = "loadCityCode";
        } else {
            field = "unloadCityCode";
        }
        List<Integer> list = mongoTemplate.findDistinct(query, field, SckwWaybillOrder.class, Integer.class);
        List<AreaTreeFrontResDto> areaTreeFrontResDtos = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(list)) {
            areaTreeFrontResDtos = remoteSystemService.queryAreaTreeFrontByCodeList(list);
        }
        return HttpResult.ok(areaTreeFrontResDtos);
    }

    /**
     * 运单列表导出
     *
     * @param query
     * @return
     */
    public List<WaybillOrderListExport> wayBillOrderExport(WaybillOrderQuery query) {
        Criteria criteria = newBuildWaybillOrdersQuery(query);
        Query queryFormat = new Query(criteria);
        List<Long> wOrderIds = StringUtils.splitStrToList(query.getIds(), ",", Long.class);
        if (CollectionUtils.isNotEmpty(wOrderIds)) {
            queryFormat.addCriteria(Criteria.where("wOrderId").in(wOrderIds));
        }
        List<SckwWaybillOrder> wOrders = mongoTemplate.find(queryFormat, SckwWaybillOrder.class);
        List<WaybillOrderListExport> list = new ArrayList<>();
        AtomicInteger i = new AtomicInteger(1);
        wOrders.forEach(e -> {
            WaybillOrderListExport export = BeanUtils.copyProperties(e, WaybillOrderListExport.class);
            export.setSerialNumber(String.valueOf(i.getAndIncrement()))
                    .setStatus(CarWaybillEnum.getName(e.getStatus()))
                    .setWOrderNo(e.getWOrderNo())
                    .setTruckNo(e.getTruckNo())
                    .setDriverName(e.getDriverName())
                    .setType(e.getType().equals(NumberConstant.ONE) ? "趟次" : "循环")
                    .setSendCarTime(e.getCreateTime() == null ? null : DateUtil.getDateTime(e.getCreateTime()))
                    .setStartTime(e.getStartTime() == null ? null : DateUtil.getDateTime(e.getStartTime()))
                    .setEndTime(e.getEndTime() == null ? null : DateUtil.getDateTime(e.getEndTime()))
                    .setEntrustAmount(String.valueOf(e.getEntrustAmount()))
                    .setLoadName(e.getLoadName())
                    .setLoadAddress((e.getLoadCityName() == null ? "" : e.getLoadCityName())
                            .concat(e.getLoadDetailAddress() == null ? "" : e.getLoadDetailAddress()))
                    .setUnloadName(e.getUnloadName())
                    .setUnloadAddress((e.getUnloadCityName() == null ? "" : e.getUnloadCityName())
                            .concat(e.getUnloadDetailAddress() == null ? "" : e.getUnloadDetailAddress()))
                    .setLoadAmount(String.valueOf(e.getLoadAmount()))
                    .setUnloadAmount(String.valueOf(e.getUnloadAmount()))
                    .setDeficitAmount(String.valueOf(e.getDeficitAmount()))
                    .setLoadDateTime(e.getLoadTime() == null ? null : DateUtil.getDateTime(e.getLoadTime()))
                    .setUnloadDateTime(e.getUnloadTime() == null ? null : DateUtil.getDateTime(e.getUnloadTime()))
                    .setUpdateTime(e.getUpdateTime() == null ? null : DateUtil.getDateTime(e.getUpdateTime()));
            list.add(export);
        });
        return list;
    }

    /**
     * @param loadAmount    装货量
     * @param deficitAmount 亏吨量
     * @param loss          合理损耗
     * @desc 计算扣亏量
     * @author zk
     * @date 2023/7/27
     **/
    public BigDecimal deficitLossAmount(BigDecimal loadAmount, BigDecimal deficitAmount, BigDecimal loss, String lossUnit) {
        if (loadAmount == null || deficitAmount == null) {
            return new BigDecimal(Global.AMOUNT);
        }
        //亏吨<=0
        if (deficitAmount.compareTo(new BigDecimal(Global.AMOUNT)) <= 0) {
            return new BigDecimal(Global.AMOUNT);
        }
        if (StringUtils.isBlank(lossUnit)) {
            lossUnit = String.valueOf(NumberConstant.ZERO);
        }
        //承运订单亏吨扣款=（承运订单亏吨量 -（承运订单装货量 * 承运订单合理损耗））* 扣亏货值
        loss = loss == null ? new BigDecimal(Global.AMOUNT) : loss;
        if (loss.doubleValue() > 0 && StringUtils.isNotBlank(lossUnit)) {
            if (lossUnit.equals(String.valueOf(TaxRateTypeEnum.PERCENT.getCode()))) {
                loss = loss.divide(new BigDecimal(TaxRateTypeEnum.PERCENT.getValue()));
            }
            if (lossUnit.equals(String.valueOf(TaxRateTypeEnum.MILLIMETER.getCode()))) {
                loss = loss.divide(new BigDecimal(TaxRateTypeEnum.MILLIMETER.getValue()));
            }
        }
        //扣亏量=亏吨量【合理损耗占比为空或为0】
        if (loss.doubleValue() == Global.NUMERICAL_ZERO) {
            return deficitAmount;
        }
        //扣亏量=亏吨量-合理损耗值【要求大于0，如果小于0则扣亏货量取0】
        BigDecimal deficitLossAmount = deficitAmount.subtract(loadAmount.multiply(loss).setScale(2, RoundingMode.HALF_UP));
        if (deficitLossAmount.doubleValue() <= 0) {
            return new BigDecimal(Global.AMOUNT);
        }
        return deficitLossAmount;
    }
}
