package com.tofly.gpsboot.service.calculate.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.tofly.api.UserClent;
import com.tofly.common.core.util.Date8Util;
import com.tofly.es.dto.EsQueryDto;
import com.tofly.es.dto.EsQueryParamDto;
import com.tofly.es.dto.StatisticalInfoDto;
import com.tofly.es.vo.StatisticalInfoVo;
import com.tofly.gpsboot.common.Constant;
import com.tofly.gpsboot.common.system.IsPlaceEnum;
import com.tofly.gpsboot.mapper.maintain.RepairtypeMapper;
import com.tofly.gpsboot.mapper.plan.GpscalculateMapper;
import com.tofly.gpsboot.service.build.BuildService;
import com.tofly.gpsboot.service.build.BuildplanService;
import com.tofly.gpsboot.service.calculate.ICalculateGpsService;
import com.tofly.gpsboot.service.es.IPdaDeviceService;
import com.tofly.gpsboot.service.maintain.RepairorderService;
import com.tofly.gpsboot.service.maintain.RepairuserService;
import com.tofly.gpsboot.service.paln.GpscalculateService;
import com.tofly.gpsboot.service.paln.task.PlanService;
import com.tofly.gpsboot.service.paln.task.PlanchildService;
import com.tofly.gpsboot.service.process.PointtempService;
import com.tofly.gpsboot.service.sign.PdasignhisService;
import com.tofly.gpsboot.service.trouble.ToubleplanService;
import com.tofly.gpsboot.service.trouble.TroubleService;
import com.tofly.gpsboot.util.DateTimeUtil;
import com.tofly.pojo.User;
import com.tofly.pojo.build.Build;
import com.tofly.pojo.build.Buildplan;
import com.tofly.pojo.maintain.Repairorder;
import com.tofly.pojo.maintain.Repairuser;
import com.tofly.pojo.plan.*;
import com.tofly.pojo.trouble.Toubleplan;
import com.tofly.pojo.trouble.Trouble;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.metrics.sum.InternalSum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @author BZ-DJJ
 * 统计巡检里程、耗时、有效里程、有效耗时、实际里程，实际耗时，发现隐患数、发现工地数、签到时间段
 */
@Service
public class CalculateGpsServiceImpl implements ICalculateGpsService {
    @Autowired
    private UserClent userClent;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Autowired
    private IPdaDeviceService iPdaDeviceService;

    @Autowired
    private PlanchildService planChildService;

    @Autowired
    private PointtempService pointtempService;

    @Autowired
    private PlanService planService;

    @Autowired
    private TroubleService troubleService;

    @Autowired
    private ToubleplanService toubleplanService;

    @Autowired
    private BuildService buildService;

    @Autowired
    private BuildplanService buildplanService;

    @Autowired
    private PdasignhisService pdasignhisService;

    @Autowired
    private RepairorderService repairorderService;

    @Autowired
    private RepairuserService repairuserService;

    @Autowired
    private GpscalculateService gpscalculateService;

    @Autowired
    private RepairtypeMapper repairtypeMapper;

    @Autowired
    private GpscalculateMapper gpscalculateMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void CalculateGps() {
        // 是否处理并保存
//        LocalDateTime todayBeginTime = DateTimeUtil.fromLong2LocalDateTime(start.getTime());
        // 每日计算
        LocalDateTime todayBeginTime = DateTimeUtil.getTodayBeginTime();
        Date startDate = DateTimeUtil.convertLDTToDate(todayBeginTime);
        Date endDate = DateTimeUtil.convertLDTToDate(todayBeginTime.plusDays(1));

        // 存入计算后对象
        List<Gpscalculate> gpscalulateList = new ArrayList<>();
        // 根据设备上传的数据获取当前需要计算的用户列表
        EsQueryDto dto = new EsQueryDto();
        dto.setStartDate(startDate);
        dto.setEndDate(endDate);
//        Long testId = 292L;
        List<Long> userIdList = repairtypeMapper.getUserIdList();
//        List<Long> userIdList = new ArrayList<>();
//        userIdList.add(testId);
        userIdList.forEach(userId -> {
            // 人巡总里程/总耗时 车巡总里程/总耗时
            Gpscalculate gpsCalculate = new Gpscalculate();
            gpsCalculate.setUserId(userId);
            gpsCalculate.setGpsDate(startDate);
            // 总里程耗时计算
            EsQueryParamDto esQueryParam = new EsQueryParamDto();
            esQueryParam.setStartDate(startDate);
            esQueryParam.setStartDate(startDate);
            esQueryParam.setEndDate(endDate);
            esQueryParam.setUserId(userId);
            esQueryParam.setGpsType(0L);
            esQueryParam.setIsvalid(new BigDecimal(1));
            List<Double> getTotal = this.getGpsTotal(elasticsearchTemplate, esQueryParam);
            if (null != getTotal && getTotal.size() > 0) {
                gpsCalculate.setPlanTotalDistance(getTotal.get(0));
                gpsCalculate.setPlanTotalTime(getTotal.get(1));
                gpsCalculate.setPlanTotalAverage(gpsCalculate.getPlanTotalTime() == 0 ? 0 : getTotal.get(0) / getTotal.get(1));
            }

            // 车巡里程耗时计算
            esQueryParam.setGpsType(1L);
            List<Double> getCarTotal = this.getGpsTotal(elasticsearchTemplate, esQueryParam);
            if (null != getCarTotal && getCarTotal.size() > 0) {
                gpsCalculate.setCarTotalDistance(getCarTotal.get(0));
                gpsCalculate.setCarTotalTime(getCarTotal.get(1));
                gpsCalculate.setCarTotalAverage(gpsCalculate.getCarTotalTime() == 0 ? 0 : getCarTotal.get(0) / getCarTotal.get(1));
            }

            // 对应计划下的总点数/总长度/计划巡检点数/实际巡检点数/计划巡检线长度/
            // 实际长度/发现隐患数/计划巡检隐患个数/实际巡检隐患个数/工地发现数/
            // 计划巡检工地监护数/实际巡检工地监护个数/签到时间段
            // 个人完成巡检点数/个人完成巡检长度
            this.getNowPlanList(userId, startDate, endDate, gpsCalculate);
            // 计划工单个数/完成工单个数
            this.getRepairOrderCont(userId, startDate, endDate, gpsCalculate);
            gpscalulateList.add(gpsCalculate);

        });

        List<Gpscalculate> list = gpscalculateService.list(new QueryWrapper<Gpscalculate>().lambda().in(Gpscalculate::getUserId, userIdList).eq(Gpscalculate::getGpsDate, startDate));
        // 已存在的当前统计的数据  key userId vale id
        Map<Long, Long> longLongMap = list.stream().collect(Collectors.toMap(Gpscalculate::getUserId, Gpscalculate::getId));
        gpscalulateList.forEach(t -> {
            // 存在则更新
            Long userId = t.getUserId();
            if (longLongMap.containsKey(userId)) {
                Long aLong = longLongMap.get(userId);
                t.setId(aLong);
                gpscalculateService.updateById(t);
            } else {
                gpscalculateService.save(t);
            }
        });


    }

    @Override
    public void calculateGps(String start, String end) {

        DateTime startTime = DateUtil.parse(start, "yyyy-MM-dd");
        DateTime endTime = DateUtil.parse(end, "yyyy-MM-dd");

        long l = DateUtil.betweenDay(startTime, endTime, true);
        while (l != 0) {
            LocalDateTime todayBeginTime = LocalDateTime.ofInstant(startTime.toInstant(), ZoneId.systemDefault());
            Date startDate = DateTimeUtil.convertLDTToDate(todayBeginTime);
            Date endDate = DateTimeUtil.convertLDTToDate(todayBeginTime.plusDays(1));

            // 存入计算后对象
            List<Gpscalculate> gpscalulateList = new ArrayList<>();
            // 根据设备上传的数据获取当前需要计算的用户列表
            EsQueryDto dto = new EsQueryDto();
            dto.setStartDate(startDate);
            dto.setEndDate(endDate);

            List<Long> userIdList = repairtypeMapper.getUserIdList();

            userIdList.forEach(userId -> {
                // 人巡总里程/总耗时 车巡总里程/总耗时
                Gpscalculate gpsCalculate = new Gpscalculate();
                gpsCalculate.setUserId(userId);
                gpsCalculate.setGpsDate(startDate);
                // 总里程耗时计算
                EsQueryParamDto esQueryParam = new EsQueryParamDto();
                esQueryParam.setStartDate(startDate);
                esQueryParam.setStartDate(startDate);
                esQueryParam.setEndDate(endDate);
                esQueryParam.setUserId(userId);
                esQueryParam.setGpsType(0L);
                esQueryParam.setIsvalid(new BigDecimal(1));
                List<Double> getTotal = this.getGpsTotal(elasticsearchTemplate, esQueryParam);
                if (null != getTotal && getTotal.size() > 0) {
                    gpsCalculate.setPlanTotalDistance(getTotal.get(0));
                    gpsCalculate.setPlanTotalTime(getTotal.get(1));
                    gpsCalculate.setPlanTotalAverage(gpsCalculate.getPlanTotalTime() == 0 ? 0 : getTotal.get(0) / getTotal.get(1));
                }

                // 车巡里程耗时计算
                esQueryParam.setGpsType(1L);
                List<Double> getCarTotal = this.getGpsTotal(elasticsearchTemplate, esQueryParam);
                if (null != getCarTotal && getCarTotal.size() > 0) {
                    gpsCalculate.setCarTotalDistance(getCarTotal.get(0));
                    gpsCalculate.setCarTotalTime(getCarTotal.get(1));
                    gpsCalculate.setCarTotalAverage(gpsCalculate.getCarTotalTime() == 0 ? 0 : getCarTotal.get(0) / getCarTotal.get(1));
                }

                // 对应计划下的总点数/总长度/计划巡检点数/实际巡检点数/计划巡检线长度/
                // 实际长度/发现隐患数/计划巡检隐患个数/实际巡检隐患个数/工地发现数/
                // 计划巡检工地监护数/实际巡检工地监护个数/签到时间段
                // 个人完成巡检点数/个人完成巡检长度
                this.getNowPlanList(userId, startDate, endDate, gpsCalculate);
                // 计划工单个数/完成工单个数
                this.getRepairOrderCont(userId, startDate, endDate, gpsCalculate);
                gpscalulateList.add(gpsCalculate);
            });

            List<Gpscalculate> list = gpscalculateService.list(new QueryWrapper<Gpscalculate>().lambda().in(Gpscalculate::getUserId, userIdList).eq(Gpscalculate::getGpsDate, startDate));
            // 已存在的当前统计的数据  key userId vale id
            Map<Long, Long> longLongMap = list.stream().collect(Collectors.toMap(Gpscalculate::getUserId, Gpscalculate::getId));
            gpscalulateList.forEach(t -> {
                // 存在则更新
                Long userId = t.getUserId();
                if (longLongMap.containsKey(userId)) {
                    Long aLong = longLongMap.get(userId);
                    t.setId(aLong);
                    gpscalculateService.updateById(t);
                } else {
                    gpscalculateService.save(t);
                }
            });
            startTime = DateUtil.offsetDay(startTime, 1);
            l--;
        }

    }


    @Override
    public List<StatisticalInfoVo> getStatisticalInfo(StatisticalInfoDto dto) {
        Date startDate = dto.getStartDate();
        Date endDate = dto.getEndDate();
        Long userId = dto.getUserId();
        List<StatisticalInfoVo> voList = new ArrayList<>();
        List<Gpscalculate> gpscalculateList = new ArrayList<>();
        if (null != userId && 0 != userId) {
            gpscalculateList = gpscalculateService.list(new QueryWrapper<Gpscalculate>().lambda().eq(Gpscalculate::getUserId, userId).ge(Gpscalculate::getGpsDate, startDate).le(Gpscalculate::getGpsDate, endDate));
        } else {
            gpscalculateList = gpscalculateService.list(new QueryWrapper<Gpscalculate>().lambda().ge(Gpscalculate::getGpsDate, startDate).le(Gpscalculate::getGpsDate, endDate));
        }
        if (gpscalculateList.size() > 0) {
            // 按照用户分组
            Map<Long, List<Gpscalculate>> collect = gpscalculateList.stream().collect(Collectors.groupingBy(Gpscalculate::getUserId));
            collect.forEach((k, v) -> {
                StatisticalInfoVo vo = new StatisticalInfoVo();
                vo.setUserId(k);
                v.forEach(info -> {
                    User result = userClent.getById(info.getUserId()).getResult();
                    if (null != result) {
                        vo.setUserIdName(result.getRealName());
                    }

                    vo.setPlanTotalDistance(BigDecimal.valueOf(vo.getPlanTotalDistance() == null ? 0 : vo.getPlanTotalDistance()).add(BigDecimal.valueOf(info.getPlanTotalDistance())).doubleValue());
                    vo.setPlanTotalTime(BigDecimal.valueOf(vo.getPlanTotalTime() == null ? 0 : vo.getPlanTotalTime()).add(BigDecimal.valueOf(info.getPlanTotalTime())).doubleValue());
                    vo.setPlanTotalAverage(BigDecimal.valueOf(vo.getPlanTotalAverage() == null ? 0 : vo.getPlanTotalAverage()).add(BigDecimal.valueOf(info.getPlanTotalAverage())).doubleValue());
                    vo.setVaildTotalDistance(BigDecimal.valueOf(vo.getVaildTotalDistance() == null ? 0 : vo.getVaildTotalDistance()).add(BigDecimal.valueOf(info.getVaildTotalDistance())).doubleValue());
                    vo.setVaildTotalTime(BigDecimal.valueOf(vo.getVaildTotalTime() == null ? 0 : vo.getVaildTotalTime()).add(BigDecimal.valueOf(info.getVaildTotalTime())).doubleValue());
                    vo.setVaildSpeed(BigDecimal.valueOf(vo.getVaildSpeed() == null ? 0 : vo.getVaildSpeed()).add(BigDecimal.valueOf(info.getVaildSpeed())).doubleValue());
                });
                voList.add(vo);
            });
        }

        return voList;
    }

    @Override
    public Gpscalculate CalculateGpsByUseDate(Long userId,Date startDate,Date endDate) {

        // 存入计算后对象
        Gpscalculate gpsCalculate = new Gpscalculate();
        // 根据设备上传的数据获取当前需要计算的用户列表
        EsQueryDto dto = new EsQueryDto();
        dto.setStartDate(startDate);
        dto.setEndDate(endDate);
        // 人巡总里程/总耗时 车巡总里程/总耗时
        gpsCalculate.setUserId(userId);
        gpsCalculate.setGpsDate(startDate);
        gpsCalculate.setUserName(gpscalculateMapper.getRealName(userId));
        gpsCalculate.setDeptName(gpscalculateMapper.getDeptName(userId));
        // 总里程耗时计算
        EsQueryParamDto esQueryParam = new EsQueryParamDto();
        esQueryParam.setStartDate(startDate);
        esQueryParam.setEndDate(endDate);
        esQueryParam.setUserId(userId);
        esQueryParam.setGpsType(0L);
        esQueryParam.setIsvalid(new BigDecimal(1));
        List<Double> getTotal = this.getGpsTotal(elasticsearchTemplate, esQueryParam);
        if (null != getTotal && getTotal.size() > 0) {
            gpsCalculate.setPlanTotalDistance(getTotal.get(0));
            gpsCalculate.setPlanTotalTime(getTotal.get(1));
            gpsCalculate.setPlanTotalAverage(gpsCalculate.getPlanTotalTime() == 0 ? 0 : getTotal.get(0) / getTotal.get(1));
        }
        // 车巡里程耗时计算
        esQueryParam.setGpsType(1L);
        List<Double> getCarTotal = this.getGpsTotal(elasticsearchTemplate, esQueryParam);
        if (null != getCarTotal && getCarTotal.size() > 0) {
            gpsCalculate.setCarTotalDistance(getCarTotal.get(0));
            gpsCalculate.setCarTotalTime(getCarTotal.get(1));
            gpsCalculate.setCarTotalAverage(gpsCalculate.getCarTotalTime() == 0 ? 0 : getCarTotal.get(0) / getCarTotal.get(1));
        }

        // 对应计划下的总点数/总长度/计划巡检点数/实际巡检点数/计划巡检线长度/
        // 实际长度/发现隐患数/计划巡检隐患个数/实际巡检隐患个数/工地发现数/
        // 计划巡检工地监护数/实际巡检工地监护个数/签到时间段
        // 个人完成巡检点数/个人完成巡检长度
        this.getNowPlanList(userId, startDate, endDate, gpsCalculate);
        // 计划工单个数/完成工单个数
        this.getRepairOrderCont(userId, startDate, endDate, gpsCalculate);

        return gpsCalculate;
    }

    /**
     * 获取对应用户下的巡检计算值
     *
     * @param userId
     * @return
     */
    private boolean getNowPlanList(Long userId, Date startDate, Date endDate, Gpscalculate gpsCalculate) {
        QueryWrapper<Plan> queryWrapper = new QueryWrapper<>();
        queryWrapper.and(wrapper->wrapper.between("PLAN_BEGINDATE",startDate,endDate)
                .or().between("PLAN_ENDDATE",startDate,endDate)
                .or(a->a.ge("PLAN_BEGINDATE",startDate).le("PLAN_ENDDATE",startDate))
                .or(a->a.ge("PLAN_BEGINDATE",endDate).le("PLAN_ENDDATE",endDate)));
        List<Plan> list =planService.list(queryWrapper);

        // 判断当前人员是否有执行任务
        if (null != list && list.size() > 0) {
            Map<Long, List<Plan>> collect = list.stream().collect(Collectors.groupingBy(Plan::getId));
            List<Planchild> planchildList = planChildService.list(new QueryWrapper<Planchild>().lambda().in(Planchild::getPlanId, collect.keySet()).eq(Planchild::getRespUser, userId));
            if (null != planchildList && planchildList.size() > 0) {
                // 获取该用户下的计划
                Set<Long> planSet = planchildList.stream().map(Planchild::getPlanId).collect(Collectors.toSet());
                List<Plan> planList = new ArrayList<>();
                collect.forEach((i, o) -> {
                    if (planSet.contains(i)) {
                        planList.addAll(o);
                    }
                });
                //总点数
                AtomicReference<BigDecimal> totalCount = new AtomicReference<>(BigDecimal.ZERO);
                ///总长度
                AtomicReference<BigDecimal> totalLength = new AtomicReference<>(BigDecimal.ZERO);
                //实际巡检点个数
                AtomicReference<BigDecimal> overCount = new AtomicReference<>(BigDecimal.ZERO);
                //实际巡检线个数
                AtomicReference<BigDecimal> overLength = new AtomicReference<>(BigDecimal.ZERO);

                //个人完成点个数
                AtomicReference<BigDecimal> userOverCount = new AtomicReference<>(BigDecimal.ZERO);
                //个人完成线个数
                AtomicReference<BigDecimal> userOverLength = new AtomicReference<>(BigDecimal.ZERO);

                List<Pointtemp> pointTempList = pointtempService.list(new QueryWrapper<Pointtemp>().lambda().in(Pointtemp::getPlanId, planSet));

                pointTempList.forEach(item->{
                    totalCount.set(totalCount.get().add(BigDecimal.ONE));
                    totalLength.set(totalLength.get().add(item.getPipeLength()));
                    if(item.getIsover().equals(IsPlaceEnum.IS_PLACE_NO.getCode())){
                        overCount.set(overCount.get().add(BigDecimal.ONE));
                        overLength.set(overLength.get().add(item.getPipeLength()));
                        if(item.getUserId().equals(userId)){
                            userOverCount.set(userOverCount.get().add(BigDecimal.ONE));
                            userOverLength.set(userOverLength.get().add(item.getPipeLength()));
                        }
                    }

                });
                // 计划个数
                gpsCalculate.setPlanNum((long) planSet.size());
                Long completeNum=planList.stream().filter(item->item.getPlanState().equals("4")).count();
                gpsCalculate.setPlanCompleteNum(completeNum);
                // 计划巡检点数和实际巡检点数
                gpsCalculate.setPointinplan(totalCount.get().longValue());
                gpsCalculate.setPointpatroled(overCount.get().longValue());
                // 计划巡检线长度，实际长度
                gpsCalculate.setPathinplan(totalLength.get());
                gpsCalculate.setPathpatroled(overLength.get());

                gpsCalculate.setOverCount(userOverCount.get().longValue());

                gpsCalculate.setOverLen(userOverLength.get());


                // 计划巡检隐患个数/实际巡检隐患个数
                this.getTroublePlanCount(pointTempList, planSet, gpsCalculate);
                // 计划巡检工地监护数/实际巡检工地监护个数
                this.getBuildPlanCount(pointTempList, planSet, gpsCalculate);
                // 个人完成巡检点数/个人完成巡检长度
                //  this.getUserOver(planchildList, pointTempList, gpsCalculate);
            }
        }

        // 发现隐患数
        int troubleNums = troubleService.count(Wrappers.<Trouble>lambdaQuery()
                .eq(Trouble::getCreateUser, userId)
                .ge(Trouble::getCreateTime, startDate)
                .le(Trouble::getCreateTime, endDate));
        gpsCalculate.setFindTroubleNum((long) troubleNums);

        // 工地发现数
        int siteNums = buildService.count(Wrappers.<Build>lambdaQuery()
                .eq(Build::getCreateUser, userId)
                .ge(Build::getCreateTime, startDate)
                .le(Build::getCreateTime, endDate));
        gpsCalculate.setBuildingsitefinded((long) siteNums);

        // 签到时间段
        this.getSignRange(userId, startDate, endDate, gpsCalculate);
        return true;

    }


    private void getTroublePlanCount(List<Pointtemp> pointTempList, Set<Long> planSet, Gpscalculate gpsCalculate) {
        // 获取 隐患巡检计划
        Set<Long> troublePlanList = toubleplanService.list().stream().map(Toubleplan::getPlanId).filter(planSet::contains).collect(Collectors.toSet());
        // 计划巡检隐患个数
        gpsCalculate.setTroubleinplan((long) troublePlanList.size());
        // 实际巡检隐患个数
        long count = pointTempList.stream().filter(pointTemp -> troublePlanList.contains(pointTemp.getPlanId()) && pointTemp.getIsover().equals(IsPlaceEnum.IS_PLACE_NO.getCode())).count();
        gpsCalculate.setTroubleipatroled(count);
    }

    private void getBuildPlanCount(List<Pointtemp> pointTempList, Set<Long> planSet, Gpscalculate gpsCalculate) {
        // 获取 工地巡检计划
        Set<Long> buildPlanList = buildplanService.list().stream().map(Buildplan::getPlanId).filter(planSet::contains).collect(Collectors.toSet());
        // 计划巡检工地监护个数
        gpsCalculate.setBuildingsitemonitor((long) buildPlanList.size());
        // 实际巡检工地监护个数
        long count = pointTempList.stream().filter(pointTemp -> buildPlanList.contains(pointTemp.getPlanId()) && pointTemp.getIsover().equals(IsPlaceEnum.IS_PLACE_NO.getCode())).count();
        gpsCalculate.setBuildingpatroled(count);
    }

    private boolean getRepairOrderCont(Long userId, Date startDate, Date endDate, Gpscalculate gpsCalculate) {
        // 获取当前用户下在指定时间范围内需要处理的工单,以及完成工单的数量
        Set<Long> orderIdList = repairuserService.list(new QueryWrapper<Repairuser>().lambda().eq(Repairuser::getRespUser, userId)).stream().map(Repairuser::getRepairId).collect(Collectors.toSet());
        if (orderIdList.size() > 0) {
            List<Repairorder> repairorderList = repairorderService.list(new QueryWrapper<Repairorder>().lambda()
                    .in(Repairorder::getId, orderIdList)
                    .between(Repairorder::getStartTime, startDate, endDate)
                    .between(Repairorder::getEndTime, startDate, endDate)
                    .select(Repairorder::getNum));
            List<Repairorder> repairOverOrderList = repairorderService.list(new QueryWrapper<Repairorder>().lambda()
                    .in(Repairorder::getId, orderIdList)
                    .ge(Repairorder::getOverTime, startDate)
                    .le(Repairorder::getOverTime, endDate).select(Repairorder::getOverNum));
            long sum = repairOverOrderList.stream().mapToLong(o -> o.getOverNum() == null ? BigDecimal.ZERO.longValue() : o.getOverNum()).sum();
            gpsCalculate.setRepairOrderNum(repairorderList.stream().mapToLong(Repairorder::getNum).sum());
            gpsCalculate.setCompleteOrderNum(sum);
            return true;
        } else {
            return false;
        }

    }

    private void getUserOver(List<Planchild> planChildList, List<Pointtemp> pointTempList, Gpscalculate gpsCalculate) {
        // 获取当前用户的子计划信息已完成的点到位信息id
        // 获取用户下的子计划完成点位的IDS
        Set<Long> overIdList = new HashSet<>();
        List<String> collect = planChildList.stream().map(Planchild::getOverIds).collect(Collectors.toList());
        collect.forEach(ids -> {
            if (!StringUtils.isEmpty(ids)) {
                overIdList.addAll(Arrays.stream(ids.split(Constant.CSV)).map(s -> Long.parseLong(s.trim()))
                        .collect(Collectors.toList()));
            }
        });
        // 个人完成巡检点数 / 个人完成巡检长度
        AtomicReference<BigDecimal> overCount = new AtomicReference<>(BigDecimal.ZERO);
        AtomicReference<BigDecimal> overLen = new AtomicReference<>(BigDecimal.ZERO);
        pointTempList.forEach(info -> {
            if (overIdList.contains(info.getId())) {
                overCount.getAndSet(BigDecimal.ONE);
                overLen.getAndSet(info.getPipeLength() == null ? BigDecimal.ZERO : info.getPipeLength());
            }
        });
        gpsCalculate.setOverCount(overCount.get().longValue());
        gpsCalculate.setOverLen(overLen.get());

    }

    private void getSignRange(Long userId, Date startDate, Date endDate, Gpscalculate gpsCalculate) {
        //签到时间段
        List<Pdasignhis> signList = pdasignhisService.list(Wrappers.<Pdasignhis>lambdaQuery()
                .select(Pdasignhis::getSignTime, Pdasignhis::getSignType)
                .eq(Pdasignhis::getSignUser, userId)
                .ge(Pdasignhis::getSignTime, startDate)
                .le(Pdasignhis::getSignTime, endDate)
                .orderByAsc(Pdasignhis::getSignTime));

        int k = 0;
        StringBuilder sb = new StringBuilder();
        for (Pdasignhis sign : signList) {
            if (k % 2 == 0) {
                sb.append(Date8Util.format(sign.getSignTime(), "yyyy-MM-dd HH:mm:ss")).append("~");
                if (signList.size() == (k + 1)) {
                    sb.append(Date8Util.format(Date8Util.getCurrentDate(), "yyyy-MM-dd HH:mm:ss"));
                }
            } else {
                sb.append(Date8Util.format(sign.getSignTime(), "yyyy-MM-dd HH:mm:ss"));
                if (signList.size() != (k + 1)) {
                    sb.append(", ");
                }
            }
            k++;
        }
        gpsCalculate.setSignRange(sb.toString());
    }

    /**
     * 总里程总耗时计算
     *
     * @param elasticsearchTemplate es实例
     * @param esQueryParam          查询条件
     * @return
     */
    private List<Double> getGpsTotal(ElasticsearchTemplate elasticsearchTemplate, EsQueryParamDto esQueryParam) {
        BoolQueryBuilder qb = QueryBuilders.boolQuery();
        if (esQueryParam.getUserId() != null) {
            MatchQueryBuilder qbUserId = QueryBuilders.matchQuery("userId", esQueryParam.getUserId());
            qb.must(qbUserId);
        }
        if (esQueryParam.getGpsType() != null) {
            MatchQueryBuilder qbGpsType = QueryBuilders.matchQuery("gpsType", esQueryParam.getGpsType());
            qb.must(qbGpsType);
        }
        if (esQueryParam.getIsvalid() != null) {
            MatchQueryBuilder qbIsvalid = QueryBuilders.matchQuery("isValid", esQueryParam.getIsvalid().toString());
            qb.must(qbIsvalid);
        }
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("checkTime");
        rangeQueryBuilder.from(esQueryParam.getStartDate().getTime());
        rangeQueryBuilder.to(esQueryParam.getEndDate().getTime());
        qb.must(rangeQueryBuilder);

        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(qb)
                .addAggregation(AggregationBuilders.sum("gpsTimespan").field("gpsTimespan"))
                .addAggregation(AggregationBuilders.sum("distance").field("distance"))
                .build();
        return elasticsearchTemplate.query(searchQuery, response -> {
            InternalSum sum = response.getAggregations().get("distance");
            InternalSum sum2 = response.getAggregations().get("gpsTimespan");
            List<Double> list = new ArrayList<>();
            list.add(fix2(sum.getValue()));
            list.add(fix2(sum2.getValue()));
            return list;
        });
    }

    /**
     * double 保留两位小数（四舍五入）
     *
     * @param d
     * @return
     */
    private static Double fix2(Double d) {
        BigDecimal b = new BigDecimal(d);
        return b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
}
