package com.ningdatech.carapi.car.datascreen.manage;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.basic.util.NdDateUtils;
import com.ningdatech.cache.repository.CachePlusOps;
import com.ningdatech.carapi.car.datascreen.model.dto.DataScreenParam;
import com.ningdatech.carapi.car.datascreen.model.po.OnlineVehicleRegionsPO;
import com.ningdatech.carapi.car.datascreen.model.po.OnlineVehicleTimesPO;
import com.ningdatech.carapi.car.datascreen.model.po.OverspeedStatisticsPO;
import com.ningdatech.carapi.car.datascreen.model.vo.StatisticsCenterVO;
import com.ningdatech.carapi.car.datascreen.service.VehicleStatisticsService;
import com.ningdatech.carapi.car.position.manage.PositionMonitorManage;
import com.ningdatech.carapi.car.position.model.po.ReqRealTimeMonitorPO;
import com.ningdatech.carapi.car.position.model.vo.ResRealTimeMonitorVehicleGisListVO;
import com.ningdatech.carapi.car.vehicle.model.NdVehicleBaseInfo;
import com.ningdatech.carapi.car.vehicle.service.IVehicleBaseInfoService;
import com.ningdatech.carapi.common.aop.BuildChildrenRegionEntity;
import com.ningdatech.carapi.common.constant.VehicleTypeEnum;
import com.ningdatech.carapi.common.model.KeyValueDTO;
import com.ningdatech.carapi.common.model.MapDataVO;
import com.ningdatech.carapi.common.model.po.MapDataPO;
import com.ningdatech.carapi.common.util.CodeUtil;
import com.ningdatech.carapi.datascope.aop.LambdaDataScope;
import com.ningdatech.carapi.datascope.aop.XmlDataScope;
import com.ningdatech.carapi.safe.entity.NdInsureOutDanger;
import com.ningdatech.carapi.safe.entity.VehicleOverspeedInfo;
import com.ningdatech.carapi.safe.model.po.OutDangerAnalysisPO;
import com.ningdatech.carapi.safe.model.po.OverspeedAnalysisPO;
import com.ningdatech.carapi.safe.service.INdInsureOutDangerService;
import com.ningdatech.carapi.safe.service.INdVehicleViolationService;
import com.ningdatech.carapi.safe.service.IVehicleOverspeedInfoService;
import com.ningdatech.carapi.safe.service.SecurityManageDataScreenService;
import com.ningdatech.carapi.safe.utils.InitDataUtil;
import com.ningdatech.carapi.sys.entity.dto.RegionDTO;
import com.ningdatech.carapi.sys.helper.RegionsCacheHelper;
import com.ningdatech.carapi.sys.service.CompanyService;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.NumberUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @Classname DigitalCockpitManage
 * @Description
 * @Date 2022/11/17 9:01
 * @Created by PoffyZhang
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class DigitalCockpitManage {

    private final CachePlusOps cachePlusOps;

    private final IVehicleOverspeedInfoService vehicleOverspeedInfoService;

    private final INdVehicleViolationService vehicleViolationService;
    private final INdInsureOutDangerService insureOutDangerService;

    private final RegionsCacheHelper regionsCacheHelper;

    private final PositionMonitorManage positionMonitorManage;
    private final CompanyService companyService;

    private final VehicleStatisticsService vehicleStatisticsService;

    private final IVehicleBaseInfoService vehicleBaseInfoService;
    private final SecurityManageDataScreenService securityManageDataScreenService;

    /**
     * 大屏中间统计数字
     *
     * @param
     * @return
     */
    @XmlDataScope
    @Cacheable(cacheNames = "cockpit:statisticsCenter",key = "#param.regionId+'-'+#param.operatorId")
    public StatisticsCenterVO statisticsCenter(DataScreenParam param) {

        List<Long> regionIds = null;
        if (Objects.nonNull(param.getRegionId())) {
            regionIds = regionsCacheHelper.listChildRegionId(param.getRegionId());
        }

        // 日超速总数
        LocalDateTime todayStart =
            NdDateUtils.getStartTime(NdDateUtils.format(LocalDateTime.now(), DatePattern.NORM_DATE_PATTERN));
        LocalDateTime todayEnd =
            NdDateUtils.getEndTime(NdDateUtils.format(LocalDateTime.now(), DatePattern.NORM_DATE_PATTERN));
        Long dailyOverspeeds = vehicleOverspeedInfoService.countStatistics(regionIds, todayStart, todayEnd);

        // 月违章
        LocalDateTime monthStart =
            NdDateUtils.getStartTime(NdDateUtils.format(LocalDateTime.now().minusMonths(1), DatePattern.NORM_MONTH_PATTERN));
        LocalDateTime monthEnd =
            NdDateUtils.getEndTime(NdDateUtils.format(LocalDateTime.now().minusMonths(1), DatePattern.NORM_MONTH_PATTERN));
        Long monthlyViolation = vehicleViolationService.countStatistics(regionIds, monthStart, monthEnd);

        LocalDateTime yearStart = getYearStartTime();
        LocalDateTime yearEnd = getYearEndTime();
        // 年出险 受伤 死亡
        List<NdInsureOutDanger> statistics = insureOutDangerService.statistics(regionIds, yearStart, yearEnd);
        Long yearlyOutdanger = statistics.stream().count();
        Long yearlyInjuries = statistics.stream().mapToLong(NdInsureOutDanger::getInjuries).sum();
        Long yearlyDeathToll = statistics.stream().mapToLong(NdInsureOutDanger::getDeathToll).sum();
        return StatisticsCenterVO.of(dailyOverspeeds, monthlyViolation, yearlyOutdanger, yearlyInjuries,
            yearlyDeathToll);
    }

    /**
     * 获取GPS列表 根据区域id
     *
     * @param param
     * @return
     */
    @XmlDataScope
    @Cacheable(cacheNames = "cockpit:getVehicleGps",key = "#param.regionId+'-'+#param.operatorId")
    public List<ResRealTimeMonitorVehicleGisListVO> getVehicleGps(DataScreenParam param) {
        List<String> companyIds = companyService.findCompanyIdsByRegionId(param);

        ReqRealTimeMonitorPO po = new ReqRealTimeMonitorPO(companyIds);

        return positionMonitorManage.realTimeMonitorVehicleGisList(po);
    }

    /**
     * 超速次数
     *
     * @param param
     * @return
     */
    @XmlDataScope
    @Cacheable(cacheNames = "cockpit:overspeedGroup",key = "#param.regionId+'-'+#param.operatorId")
    public List<MapDataVO> overspeedGroup(DataScreenParam param) {
        List<MapDataPO> mapDatas = vehicleStatisticsService.getOverspeedRegions(param);
        if (CollUtil.isEmpty(mapDatas)) {
            return Collections.emptyList();
        }
        List<MapDataVO> list = mapDatas.stream().map(d -> {
            MapDataVO vo = new MapDataVO();
            BeanUtils.copyProperties(d, vo);
            return vo;
        }).collect(Collectors.toList());
        CodeUtil.complementaryRegion(list, param.getRegionId());
        return list;
    }

    /**
     * 违章次数
     *
     * @param param
     * @return
     */
    @XmlDataScope
    @Cacheable(cacheNames = "cockpit:violationGroup",key = "#param.regionId+'-'+#param.operatorId")
    public List<MapDataVO> violationGroup(DataScreenParam param) {
        List<MapDataPO> mapDatas = vehicleStatisticsService.getViolationRegions(param);
        if (CollUtil.isEmpty(mapDatas)) {
            return Collections.emptyList();
        }
        List<MapDataVO> list = mapDatas.stream().map(d -> {
            MapDataVO vo = new MapDataVO();
            BeanUtils.copyProperties(d, vo);
            return vo;
        }).collect(Collectors.toList());
        CodeUtil.complementaryRegion(list, param.getRegionId());
        return list;
    }

    /**
     * 出险次数计算
     *
     * @param param
     * @return
     */
    @XmlDataScope
    @Cacheable(cacheNames = "cockpit:outDangerGroup",key = "#param.regionId+'-'+#param.operatorId")
    public List<MapDataVO> outDangerGroup(DataScreenParam param) {
        List<MapDataPO> mapDatas = vehicleStatisticsService.getOutDangerRegions(param);
        if (CollUtil.isEmpty(mapDatas)) {
            return Collections.emptyList();
        }
        List<MapDataVO> list = mapDatas.stream().map(d -> {
            MapDataVO vo = new MapDataVO();
            BeanUtils.copyProperties(d, vo);
            return vo;
        }).collect(Collectors.toList());
        CodeUtil.complementaryRegion(list, param.getRegionId());
        return list;
    }

    /**
     * 受伤人数
     *
     * @param param
     * @return
     */
    @XmlDataScope
    @Cacheable(cacheNames = "cockpit:injuriesGroup",key = "#param.regionId+'-'+#param.operatorId")
    public List<MapDataVO> injuriesGroup(DataScreenParam param) {
        List<MapDataPO> mapDatas = vehicleStatisticsService.getInjuriesRegion(param);
        if (CollUtil.isEmpty(mapDatas)) {
            return Collections.emptyList();
        }
        List<MapDataVO> list = mapDatas.stream().map(d -> {
            MapDataVO vo = new MapDataVO();
            BeanUtils.copyProperties(d, vo);
            return vo;
        }).collect(Collectors.toList());
        CodeUtil.complementaryRegion(list, param.getRegionId());
        return list;
    }

    /**
     * 死亡人数
     *
     * @param param
     * @return
     */
    @XmlDataScope
    @Cacheable(cacheNames = "cockpit:deathGroup",key = "#param.regionId+'-'+#param.operatorId")
    public List<MapDataVO> deathGroup(DataScreenParam param) {
        List<MapDataPO> mapDatas = vehicleStatisticsService.getDeathRegion(param);
        if (CollUtil.isEmpty(mapDatas)) {
            return Collections.emptyList();
        }
        List<MapDataVO> list = mapDatas.stream().map(d -> {
            MapDataVO vo = new MapDataVO();
            BeanUtils.copyProperties(d, vo);
            return vo;
        }).collect(Collectors.toList());
        CodeUtil.complementaryRegion(list, param.getRegionId());
        return list;
    }

    /**
     * 万车死亡人数
     *
     * @param param
     * @return
     */
    @Cacheable(cacheNames = "cockpit:deathGroupTenThousand",key = "#param.regionId+'-'+#param.operatorId")
    public List<MapDataVO> deathGroupTenThousand(DataScreenParam param) {
        List<MapDataPO> mapDatas = vehicleStatisticsService.getDeathRegion(param);
        List<KeyValueDTO<Long, Long>> carCntByRegion = vehicleStatisticsService.getVehicleNumsGroupByRegion(param);
        Map<Long, Long> carCntMap = CollUtils.listToMap(carCntByRegion, KeyValueDTO::getKey, KeyValueDTO::getValue);
        if (CollUtil.isEmpty(mapDatas)) {
            return Collections.emptyList();
        }
        List<MapDataVO> list = mapDatas.stream().map(d -> {
            MapDataVO vo = new MapDataVO();
            BeanUtils.copyProperties(d, vo);
            Long carCnt = carCntMap.getOrDefault(d.getRegionId(), 0L);
            if (carCnt == 0) {
                vo.setPercent("0");
            } else {
                BigDecimal percent = NumberUtil.div(vo.getValue(), carCnt).multiply(BigDecimal.valueOf(10000))
                    .setScale(0, RoundingMode.UP);
                vo.setPercent(percent.stripTrailingZeros().toPlainString());
            }
            return vo;
        }).collect(Collectors.toList());
        CodeUtil.complementaryRegion(list, param.getRegionId());
        return list;
    }

    /**
     * 上线率分析
     *
     * @param param
     * @return
     */
    @XmlDataScope
    @Cacheable(cacheNames = "cockpit:onlineAnalysis",key = "#param.regionId+'-'+#param.operatorId")
    public JSONObject onlineAnalysis(DataScreenParam param) {
        JSONObject res = new JSONObject();
        JSONObject timeOnlineData = genericOnlineData(param);
        List<OnlineVehicleRegionsPO> regionOnlineVehicleNums = vehicleStatisticsService.getVehicleOnlineRegions(param);
        CodeUtil.complementaryRegions(regionOnlineVehicleNums, param.getRegionId());
        return convertOnlineJson(regionOnlineVehicleNums, timeOnlineData, res);
    }

    /**
     * 超速占比分析图
     *
     * @param param
     * @return
     */
    @XmlDataScope
    @Cacheable(cacheNames = "cockpit:overspeedAnalysis",key = "#param.regionId+'-'+#param.operatorId")
    public JSONObject overspeedAnalysis(DataScreenParam param) {
        JSONObject res = new JSONObject();
        // 查询今日
        param.setStartTime(LocalDateTimeUtil.beginOfDay(LocalDateTime.now()));
        param.setEndTime(LocalDateTimeUtil.endOfDay(LocalDateTime.now()));

        // List<MapDataPO> mapDatas = vehicleStatisticsService.getOverspeedRegions(param);

        List<MapDataPO> mapDatas = Lists.newArrayList();

        List<Long> regionIds = null;
        if (Objects.nonNull(param.getRegionId())) {
            regionIds = regionsCacheHelper.listChildRegionId(param.getRegionId());
        }

        LambdaQueryWrapper<VehicleOverspeedInfo> wrapper = Wrappers.lambdaQuery(VehicleOverspeedInfo.class);
        DigitalCockpitManage contex = (DigitalCockpitManage)AopContext.currentProxy();
        contex.dataScopeCount(wrapper, regionIds, param.getStartTime(), param.getEndTime());
        List<VehicleOverspeedInfo> overspeedInfos = vehicleOverspeedInfoService.list(wrapper);

        // 根据车辆类型，过滤出真实超速的
        Map<String, NdVehicleBaseInfo> baseInfoMap =
            vehicleBaseInfoService.list().stream().collect(Collectors.toMap(NdVehicleBaseInfo::getCarPlate, v -> v));
        List<VehicleOverspeedInfo> overspeedInfoList = overspeedInfos.stream().filter(v -> {
            NdVehicleBaseInfo baseInfo = baseInfoMap.get(v.getCarPlate());
            if (Objects.nonNull(baseInfo)) {
                if (Boolean.TRUE.equals(checkIsOverSpeed(v, baseInfo))) {
                    return true;
                }
            }
            return false;
        }).collect(Collectors.toList());

        RegionDTO regionDto = regionsCacheHelper.getByRegionId(param.getRegionId());
        List<Long> regionIdList = Lists.newArrayList();
        // 传入区域为浙江省,筛选出市级(不包含市本级)
        if (regionIds.size() > 1 && regionDto.getParentId().equals(0L)) {

            regionIdList = regionsCacheHelper.listChildOnly(param.getRegionId()).stream().map(RegionDTO::getId)
                .collect(Collectors.toList());

            for (Long id : regionIdList) {
                MapDataPO po = new MapDataPO();
                po.setRegionId(id);
                RegionDTO dto = regionsCacheHelper.getByRegionId(id);
                String regionCode = dto.getRegionCode();
                po.setRegionCode(regionCode);
                po.setRegionName(dto.getRegionName());
                List<VehicleOverspeedInfo> infos = overspeedInfoList.stream().filter(c -> {
                    Long regionId = c.getRegionId();
                    RegionDTO regionDTO = regionsCacheHelper.getByRegionId(regionId);
                    if (regionDTO.getParentId().equals(id)) {
                        return true;
                    }
                    return false;
                }).collect(Collectors.toList());
                po.setValue(infos.size());
                mapDatas.add(po);
            }
            complementaryRegion(mapDatas, param.getRegionId());
            return convertAnalysisJson(mapDatas, res);
        }
        // 传入区域为市级
        else if (regionIds.size() > 1 && regionDto.getParentId().equals(116L)) {
            regionIdList = regionsCacheHelper.listChildOnly(param.getRegionId()).stream().map(RegionDTO::getId)
                .collect(Collectors.toList());
            for (Long id : regionIdList) {
                MapDataPO po = new MapDataPO();
                po.setRegionId(id);
                RegionDTO dto = regionsCacheHelper.getByRegionId(id);
                String regionCode = dto.getRegionCode();
                po.setRegionCode(regionCode);
                po.setRegionName(dto.getRegionName());
                List<VehicleOverspeedInfo> infos = overspeedInfoList.stream().filter(c -> {
                    Long regionId = c.getRegionId();
                    RegionDTO regionDTO = regionsCacheHelper.getByRegionId(regionId);
                    if (regionDTO.getId().equals(id)) {
                        return true;
                    }
                    return false;
                }).collect(Collectors.toList());
                po.setValue(infos.size());
                mapDatas.add(po);
            }
            complementaryRegion(mapDatas, param.getRegionId());
            return convertAnalysisJson(mapDatas, res);
        }
        // 传入区域为区县
        else {
            MapDataPO po = new MapDataPO();
            po.setRegionId(param.getRegionId());
            RegionDTO dto = regionsCacheHelper.getByRegionId(param.getRegionId());
            String regionCode = dto.getRegionCode();
            po.setRegionCode(regionCode);
            po.setRegionName(dto.getRegionName());
            List<VehicleOverspeedInfo> infos = overspeedInfoList.stream()
                .filter(c -> c.getRegionId().equals(param.getRegionId())).collect(Collectors.toList());
            po.setValue(infos.size());
            mapDatas.add(po);
            return convertAnalysisJson(mapDatas, res);
        }

    }

    @LambdaDataScope
    public void dataScopeCount(LambdaQueryWrapper<VehicleOverspeedInfo> wrapper, List<Long> regionIds,
        LocalDateTime startTime, LocalDateTime endTime) {
        wrapper.in(CollUtil.isNotEmpty(regionIds), VehicleOverspeedInfo::getRegionId, regionIds)
            .ge(VehicleOverspeedInfo::getOverspeedDate, startTime).le(VehicleOverspeedInfo::getOverspeedDate, endTime);
    }

    private void complementaryRegion(List<MapDataPO> mapDatas, Long regionId) {
        Map<Long, MapDataPO> dataMap = CollUtils.listToMap(mapDatas, MapDataPO::getRegionId);
        List<RegionDTO> regions = regionsCacheHelper.listChildOnly(regionId, true);
        List<MapDataPO> tmpList = new ArrayList<>();
        regions.forEach(w -> {
            MapDataPO odc = dataMap.get(w.getId());
            if (odc == null) {
                odc = new MapDataPO();
                odc.setRegionId(w.getId());
                odc.setRegionName(w.getRegionName());
                odc.setRegionName(w.getRegionName());
                odc.setRegionCode(w.getRegionCode());
                odc.setValue(0);
                odc.setPercent("0");
            }
            tmpList.add(odc);
        });
        mapDatas.clear();
        mapDatas.addAll(tmpList);
    }

    /**
     * 月度 超速 对比
     *
     * @param param
     * @return
     */
    @XmlDataScope
    @BuildChildrenRegionEntity
    @Cacheable(cacheNames = "cockpit:monthlyOverspeedAnalysis",key = "#param.regionId+'-'+#param.operatorId")
    public JSONObject monthlyOverspeedAnalysis(DataScreenParam param) {
        List<OverspeedAnalysisPO> times = securityManageDataScreenService.getOverspeedAnalysis(param);
        return convertOverspeed(times);
    }

    /**
     * 出险相关统计 月份
     *
     * @param param
     * @param type
     * @return
     */
    @XmlDataScope
    @BuildChildrenRegionEntity
    @Cacheable(cacheNames = "cockpit:getInsureAnalysis",key = "#param.regionId+'-'+#param.operatorId+'-'+#param.type")
    public JSONObject getInsureAnalysis(DataScreenParam param, Integer type) {
        List<OutDangerAnalysisPO> times = securityManageDataScreenService.getOutDangerAnalysis(param);
        return convertInsureAnalysis(times, type);
    }

    private JSONObject convertInsureAnalysis(List<OutDangerAnalysisPO> outDangerTimes, Integer type) {
        Map<String, Map<String, Object>> yearMap = InitDataUtil.initTwoYears();
        for (OutDangerAnalysisPO outDangerTime : outDangerTimes) {
            if (yearMap.containsKey(outDangerTime.getYear())) {
                Map<String, Object> monthMap = yearMap.get(outDangerTime.getYear());
                if (monthMap.containsKey(outDangerTime.getMonth())) {
                    switch (type) {
                        case 1:
                            monthMap.put(outDangerTime.getMonth(), outDangerTime.getOutDangerTimes());
                            break;
                        case 2:
                            monthMap.put(outDangerTime.getMonth(), outDangerTime.getInjuries());
                            break;
                        case 3:
                            monthMap.put(outDangerTime.getMonth(), outDangerTime.getDeathToll());
                            break;
                        default:
                            monthMap.put(outDangerTime.getMonth(), outDangerTime.getOutDangerTimes());
                    }
                }
            }
        }
        Map<String, Object> total = countTotal(yearMap);
        yearMap.put("total", total);
        return JSONObject.parseObject(JSON.toJSONString(yearMap));
    }

    private JSONObject convertOverspeed(List<OverspeedAnalysisPO> times) {
        Map<String, Map<String, Object>> yearMap = InitDataUtil.initTwoYears();
        for (OverspeedAnalysisPO time : times) {
            if (yearMap.containsKey(time.getYear())) {
                Map<String, Object> monthMap = yearMap.get(time.getYear());
                if (monthMap.containsKey(time.getMonth())) {
                    monthMap.put(time.getMonth(), time.getTimes());
                }
            }
        }
        Map<String, Object> total = countTotal(yearMap);
        yearMap.put("total", total);
        return JSONObject.parseObject(JSON.toJSONString(yearMap));
    }

    private Map<String, Object> countTotal(Map<String, Map<String, Object>> yearMap) {
        Map<String, Object> total = Maps.newHashMap();
        Map<String, Object> currentMap = yearMap.get(String.valueOf(LocalDateTime.now().getYear()));
        int currentSum =
            currentMap.entrySet().stream().mapToInt(o -> Integer.parseInt(String.valueOf(o.getValue()))).sum();
        total.put(String.valueOf(LocalDateTime.now().getYear()), currentSum);
        Map<String, Object> lastMap = yearMap.get(String.valueOf(LocalDateTime.now().minusYears(1).getYear()));
        int lastSum = lastMap.entrySet().stream().mapToInt(o -> Integer.parseInt(String.valueOf(o.getValue()))).sum();
        total.put(String.valueOf(LocalDateTime.now().minusYears(1).getYear()), lastSum);
        return total;
    }

    private JSONObject convertAnalysisJson(List<MapDataPO> mapDatas, JSONObject res) {
        Long total = mapDatas.stream().mapToLong(MapDataPO::getValue).sum();
        for (MapDataPO po : mapDatas) {
            po.setPercent(total.compareTo(0L) == 0 ? "0"
                : BigDecimal.valueOf(po.getValue() * 100).divide(BigDecimal.valueOf(total), 2, BigDecimal.ROUND_HALF_UP)
                    + StringUtils.EMPTY);
        }
        res.put("total", total);
        res.put("data", mapDatas);
        return res;
    }

    /**
     * 上线率
     *
     * @param data
     * @param res
     * @return
     */
    private JSONObject convertOnlineJson(List<OnlineVehicleRegionsPO> data, JSONObject timeOnlineData, JSONObject res) {
        JSONObject rate = new JSONObject();
        for (OnlineVehicleRegionsPO po : data) {
            rate.put(po.getRegionName(), po.getRate());
        }
        res.put("time-data", timeOnlineData);
        res.put("rate", rate);
        return res;
    }

    /**
     * 先弄点假数据
     *
     * @return
     */
    private JSONObject genericOnlineData(DataScreenParam param) {
        List<OnlineVehicleTimesPO> onlineVehicleDatas = vehicleStatisticsService.getOnlineRateToday(param);
        Long vehicleNums = vehicleStatisticsService.getVehicleNums(param);
        JSONObject res = new JSONObject();
        for (OnlineVehicleTimesPO onlineVehicleTimes : onlineVehicleDatas) {
            BigDecimal rate = 0L == vehicleNums ? BigDecimal.ZERO
                : BigDecimal.valueOf(onlineVehicleTimes.getOnlineNum()).multiply(BigDecimal.valueOf(100))
                    .divide(BigDecimal.valueOf(vehicleNums), 2, BigDecimal.ROUND_HALF_UP);
            res.put(onlineVehicleTimes.getHour() + ":00", rate);
        }
        return res;
    }

    private JSONObject convertCityJson(List<OverspeedStatisticsPO> data, JSONObject res) {
        for (OverspeedStatisticsPO po : data) {
            res.put(po.getRegionName(), po.getTimes());
        }
        return res;
    }

    private LocalDateTime getYearStartTime() {
        LocalDate nowDay = LocalDate.now();
        LocalDate firstDayOfYear = nowDay.with(TemporalAdjusters.firstDayOfYear());
        return LocalDateTime.of(firstDayOfYear, LocalTime.MIN);
    }

    private LocalDateTime getYearEndTime() {
        LocalDate nowDay = LocalDate.now();
        LocalDate lastDayOfYear = nowDay.with(TemporalAdjusters.lastDayOfYear());
        return LocalDateTime.of(lastDayOfYear, LocalTime.MAX);
    }

    private Boolean checkIsOverSpeed(VehicleOverspeedInfo gpsData, NdVehicleBaseInfo baseInfo) {
        // 混凝土和移动泵车 是50
        Integer vehicleType = baseInfo.getVehicleType();
        VehicleTypeEnum enumByValue = VehicleTypeEnum.getEnumByValue(vehicleType);
        if (VehicleTypeEnum.OTHER.equals(enumByValue)) {
            if (gpsData.getMaxSpeed().compareTo(BigDecimal.valueOf(80)) > 0) {
                return Boolean.TRUE;
            }
        } else if (VehicleTypeEnum.KRHP.equals(enumByValue)) {
            if (gpsData.getMaxSpeed().compareTo(BigDecimal.valueOf(50)) > 0) {
                return Boolean.TRUE;
            }
        } else if (VehicleTypeEnum.MIXER.equals(enumByValue)) {
            if (gpsData.getMaxSpeed().compareTo(BigDecimal.valueOf(50)) > 0) {
                return Boolean.TRUE;
            }
        } else if (VehicleTypeEnum.BULK_CEMENT_TRUCK.equals(enumByValue)) {
            if (gpsData.getMaxSpeed().compareTo(BigDecimal.valueOf(80)) > 0) {
                return Boolean.TRUE;
            }
        } else if (VehicleTypeEnum.READY_MIXED_MORTAR_TRUC.equals(enumByValue)) {
            return gpsData.getMaxSpeed().compareTo(BigDecimal.valueOf(80)) > 0;
        }
        return Boolean.FALSE;
    }

    /**
     * 清缓存
     * @param cacheName
     */
    public String removeCache(String cacheName) {
        if(StringUtils.isBlank(cacheName)){
            removeCacheAll();
            return "清缓存成功";
        }
        if(cachePlusOps.del(cacheName) > 0){
            return "清缓存" + cacheName + "成功";
        }
        return "清缓存失败";
    }

    /**
     * 请所有
     */
    @Caching(evict ={
            @CacheEvict(cacheNames = "cockpit:statisticsCenter",allEntries = true),
            @CacheEvict(cacheNames = "cockpit:getVehicleGps",allEntries = true),
            @CacheEvict(cacheNames = "cockpit:overspeedGroup",allEntries = true),
            @CacheEvict(cacheNames = "cockpit:violationGroup",allEntries = true),
            @CacheEvict(cacheNames = "cockpit:outDangerGroup",allEntries = true),
            @CacheEvict(cacheNames = "cockpit:injuriesGroup",allEntries = true),
            @CacheEvict(cacheNames = "cockpit:deathGroup",allEntries = true),
            @CacheEvict(cacheNames = "cockpit:deathGroupTenThousand",allEntries = true),
            @CacheEvict(cacheNames = "cockpit:onlineAnalysis",allEntries = true),
            @CacheEvict(cacheNames = "cockpit:overspeedAnalysis",allEntries = true),
            @CacheEvict(cacheNames = "cockpit:monthlyOverspeedAnalysis",allEntries = true),
            @CacheEvict(cacheNames = "cockpit:getInsureAnalysis",allEntries = true)
    })
    public void removeCacheAll() {
        log.info("清空驾驶舱所有缓存!");
    }
}
