package com.njcn.device.pq.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.njcn.device.common.mapper.onlinerate.OnLineRateMapper;
import com.njcn.device.common.service.GeneralDeviceService;
import com.njcn.device.line.mapper.LineMapper;
import com.njcn.device.line.service.DeptLineService;
import com.njcn.device.pq.enums.LineBaseEnum;
import com.njcn.device.pq.enums.PowerFlagEnum;
import com.njcn.device.pq.enums.RunFlagEnum;
import com.njcn.device.pq.mapper.RStatOnlinerateDMapper;
import com.njcn.device.pq.pojo.dto.GeneralDeviceDTO;
import com.njcn.device.pq.pojo.dto.MonitorInfoDTO;
import com.njcn.device.pq.pojo.param.DevRunEvaluateParam;
import com.njcn.device.pq.pojo.param.DeviceInfoParam;
import com.njcn.device.pq.pojo.param.OnlineRateParam;
import com.njcn.device.pq.pojo.po.*;
import com.njcn.device.pq.pojo.vo.*;
import com.njcn.device.pq.service.DeviceRunEvaluateService;
import com.njcn.device.pq.service.IPqDataVerifyCountService;
import com.njcn.device.rstatintegrity.mapper.RStatIntegrityDMapper;
import com.njcn.device.userledger.service.UserLedgerService;
import com.njcn.harmonic.api.RStatLimitRateDClient;
import com.njcn.harmonic.pojo.param.RStatLimitQueryParam;
import com.njcn.harmonic.pojo.po.day.RStatLimitRateDPO;
import com.njcn.supervision.pojo.vo.user.NewUserReportVO;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.enums.DicDataTypeEnum;
import com.njcn.system.pojo.po.DictData;
import com.njcn.user.api.DeptFeignClient;
import com.njcn.user.pojo.po.Dept;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author wr
 * @description
 * @date 2025/5/8 13:45
 */
@Service
@RequiredArgsConstructor
public class DeviceRunEvaluateServiceImpl implements DeviceRunEvaluateService {

    private final GeneralDeviceService generalDeviceService;
    private final RStatLimitRateDClient rStatLimitRateDClient;
    private final RStatOnlinerateDMapper onLineRateDMapper;
    private final RStatIntegrityDMapper integrityDMapper;
    private final LineMapper lineMapper;
    private final UserLedgerService userLedgerService;
    private final DeptLineService deptLineService;
    private final GeneralDeviceService deviceService;
    private final OnLineRateMapper onLineRateMapper;
    private final DicDataFeignClient dicDataFeignClient;
    private final DeptFeignClient deptFeignClient;
    private final IPqDataVerifyCountService pqDataVerifyCountService;
    /**
     * 数据完整性:50%
     */
    private static final BigDecimal ONINTEGRITY = new BigDecimal("0.5");
    /**
     * 数据合格率:30%
     */
    private static final BigDecimal ONLINERATE = new BigDecimal("0.2");
    /**
     * 终端在线率:20%
     */
    private static final BigDecimal LIMITRATE = new BigDecimal("0.3");


    @Override
    public List<DeviceRunEvaluateVO.Info> getRunEvaluate(DeviceInfoParam.CompareBusinessParam param) {
        List<DeviceRunEvaluateVO.Info> info = new ArrayList<>();
        List<GeneralDeviceDTO> deptDeviceInfos = generalDeviceService.getDeviceInfo(param, Arrays.asList(0), Arrays.asList(1));
        //监测点id集合
        List<String> lineIds = deptDeviceInfos.stream().flatMap(x -> x.getLineIndexes().stream()).distinct().collect(Collectors.toList());
        //终端id集合
        List<String> devIds = deptDeviceInfos.stream().flatMap(x -> x.getDeviceIndexes().stream()).distinct().collect(Collectors.toList());
        List<RStatLimitRateDPO> limitRateList = new ArrayList<>();
        List<RStatOnlinerateD> onlineRateList = new ArrayList<>();
        List<RStatIntegrityD> onIntegrityList = new ArrayList<>();

        if (CollUtil.isNotEmpty(lineIds)) {
            setList(param.getSearchBeginTime(), param.getSearchEndTime(), devIds, lineIds, limitRateList, onIntegrityList, onlineRateList);
        }

        DeviceRunEvaluateVO.Info evaluateVO;
        for (GeneralDeviceDTO deptDeviceInfo : deptDeviceInfos) {
            List<String> lineIndexes = deptDeviceInfo.getLineIndexes();
            List<String> devIndexes = deptDeviceInfo.getDeviceIndexes();
            if (CollUtil.isNotEmpty(lineIndexes)) {
                evaluateVO = new DeviceRunEvaluateVO.Info();
                evaluateVO.setName(deptDeviceInfo.getName());
                evaluateVO.setDevIds(deptDeviceInfo.getDeviceIndexes());
                setEvaluate(devIndexes, lineIndexes, onIntegrityList, evaluateVO, onlineRateList, limitRateList);
                info.add(evaluateVO);
            }

        }

        return info.stream().sorted(Comparator.comparing(DeviceRunEvaluateVO.Info::getEvaluate, Comparator.reverseOrder())).collect(Collectors.toList());
    }

    private void setEvaluate(List<String> devIds, List<String> lineIds, List<RStatIntegrityD> onIntegrityList, DeviceRunEvaluateVO evaluateVO, List<RStatOnlinerateD> onlineRateList, List<RStatLimitRateDPO> limitRateList) {
        //监测完整率
        List<RStatIntegrityD> integrityDS = onIntegrityList.stream().filter(x -> lineIds.contains(x.getLineIndex())).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(integrityDS)) {
            double realTime = integrityDS.stream().mapToDouble(RStatIntegrityD::getRealTime).sum();
            double dueTime = integrityDS.stream().mapToDouble(RStatIntegrityD::getDueTime).sum();
            evaluateVO.setIntegrityRate(NumberUtil.round(Math.min(realTime * 100 / dueTime, 100), 2));
        } else {
            evaluateVO.setIntegrityRate(new BigDecimal(0));
        }
        //终端在线率
        List<RStatOnlinerateD> onlineRateDS = onlineRateList.stream().filter(x -> devIds.contains(x.getDevIndex())).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(onlineRateDS)) {
            double onlineTime = onlineRateDS.stream().mapToDouble(RStatOnlinerateD::getOnlineMin).sum();
            double offlineTime = onlineRateDS.stream().mapToDouble(RStatOnlinerateD::getOfflineMin).sum();
            evaluateVO.setOnLineRate(NumberUtil.round(Math.min(onlineTime * 100.0 / (onlineTime + offlineTime), 100), 2));
        } else {
            evaluateVO.setOnLineRate(new BigDecimal(0));
        }
        //超标信息
        List<RStatLimitRateDPO> limitRateDPOS = limitRateList.stream().filter(x -> lineIds.contains(x.getLineId())).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(limitRateDPOS)) {
            double overTime = limitRateDPOS.stream().mapToDouble(x -> (x.getUaberranceOvertime() +
                    x.getUharm2Overtime() + x.getUharm3Overtime() + x.getUharm4Overtime() + x.getUharm5Overtime() +
                    x.getUharm6Overtime() + x.getUharm7Overtime() + x.getUharm8Overtime() + x.getUharm9Overtime() +
                    x.getUharm10Overtime() + x.getUharm11Overtime() + x.getUharm12Overtime() + x.getUharm13Overtime() + x.getUharm14Overtime() +
                    x.getUharm15Overtime() + x.getUharm16Overtime() + x.getUharm17Overtime() + x.getUharm18Overtime() + x.getUharm19Overtime() +
                    x.getUharm20Overtime() + x.getUharm21Overtime() + x.getUharm22Overtime() + x.getUharm23Overtime() + x.getUharm24Overtime() +
                    x.getUharm25Overtime())).sum();
            double allTime = limitRateDPOS.stream().mapToDouble(x -> x.getAllTime() * 25.0).sum();
            if (allTime == 0) {
                evaluateVO.setPassRate(new BigDecimal(0));
            } else {
                evaluateVO.setPassRate(NumberUtil.round(Math.min((1 - (overTime * 1.0 / allTime)) * 100, 100), 2));
            }
        } else {
            evaluateVO.setPassRate(new BigDecimal(0));
        }
        evaluateVO.setEvaluate(
                ONINTEGRITY.multiply(evaluateVO.getIntegrityRate())
                        .add(ONLINERATE.multiply(evaluateVO.getOnLineRate())
                                .add(LIMITRATE.multiply(evaluateVO.getPassRate()))).stripTrailingZeros()
        );
    }

    private void setList(String beginTime, String endTime, List<String> devIds, List<String> lineIds, List<RStatLimitRateDPO> limitRateList, List<RStatIntegrityD> onIntegrityList, List<RStatOnlinerateD> onlineRateList) {
        RStatLimitQueryParam limitQueryParam = new RStatLimitQueryParam();
        limitQueryParam.setIds(lineIds);
        limitQueryParam.setDate(beginTime);
        limitQueryParam.setEndDate(endTime);
        limitRateList.addAll(rStatLimitRateDClient.monitorIdsGetLimitInfo(limitQueryParam).getData());
        //监测点完整性
        onIntegrityList.addAll(integrityDMapper.selectList(new QueryWrapper<RStatIntegrityD>()
                .select("sum(real_time) as realTime,sum(due_time) as dueTime,line_index as lineIndex")
                .in(CollUtil.isNotEmpty(lineIds), "line_index", lineIds)
                .ge(StrUtil.isNotBlank(beginTime), "time_id", DateUtil.beginOfDay(DateUtil.parse(beginTime)))
                .le(StrUtil.isNotBlank(endTime), "time_id", DateUtil.endOfDay(DateUtil.parse(endTime)))
                .groupBy("line_index")));
        //终端在线率
        onlineRateList.addAll(onLineRateDMapper.selectList(new QueryWrapper<RStatOnlinerateD>()
                .select("sum(online_min) as onlineMin,sum(offline_min) as offlineMin,dev_index as devIndex")
                .in(CollUtil.isNotEmpty(devIds), "dev_index", devIds)
                .ge(StrUtil.isNotBlank(beginTime), "time_id", DateUtil.beginOfDay(DateUtil.parse(beginTime)))
                .le(StrUtil.isNotBlank(endTime), "time_id", DateUtil.endOfDay(DateUtil.parse(endTime)))
                .groupBy("dev_index")));
    }


    @Override
    public List<DeviceRunEvaluateVO> getRunEvaluateDetail(DevRunEvaluateParam param) {
        List<DeviceRunEvaluateVO> info = new ArrayList<>();
        List<DevDetailVO> devDetailVOList = deptLineService.getLineDetailByDeptIdAndDevIds(param.getDeptIndex(), param.getPowerFlag(), param.getIds());
        if (CollUtil.isNotEmpty(devDetailVOList)) {
            List<RStatLimitRateDPO> limitRateList = new ArrayList<>();
            List<RStatOnlinerateD> onlineRateList = new ArrayList<>();
            List<RStatIntegrityD> onIntegrityList = new ArrayList<>();
            List<String> devIds = devDetailVOList.stream().map(DevDetailVO::getDevId).distinct().collect(Collectors.toList());
            List<String> lineIds = devDetailVOList.stream().map(DevDetailVO::getLineId).distinct().collect(Collectors.toList());
            setList(param.getStartTime(), param.getEndTime(), devIds, lineIds, limitRateList, onIntegrityList, onlineRateList);
            Map<String, List<DevDetailVO>> devDetailMap = devDetailVOList.stream()
                    .collect(Collectors.groupingBy(x -> x.getDevId() + "_" + x.getDevName() + "_" + x.getSubName()));
            devDetailMap.forEach((key, value) -> {
                String[] split = key.split("_");
                DeviceRunEvaluateVO vo = new DeviceRunEvaluateVO();
                vo.setName(split[1]);
                vo.setSubName(split[2]);
                vo.setIp(value.get(0).getIp());
                setEvaluate(Arrays.asList(split[0]),
                        value.stream().map(DevDetailVO::getLineId).distinct().collect(Collectors.toList()),
                        onIntegrityList, vo, onlineRateList, limitRateList);
                info.add(vo);
            });
        }
        return info;
    }


    @Override
    public List<TerminalEvaluateAreaVO> areaTerminalStatistic(DeviceInfoParam.BusinessParam businessParam) {
        List<TerminalEvaluateAreaVO> result = new ArrayList<>();
        List<GeneralDeviceDTO> generalDeviceDTOList = generalDeviceService.getDeviceInfo(businessParam, Stream.of(RunFlagEnum.RUNNING.getStatus()).collect(Collectors.toList()), Stream.of(PowerFlagEnum.REAL_DEVICE.getCode()).collect(Collectors.toList()));
        if (CollectionUtil.isNotEmpty(generalDeviceDTOList)) {
            if (generalDeviceDTOList.size() == 1 && generalDeviceDTOList.get(0).getIndex().equals(businessParam.getDeptIndex())) {
                if (CollUtil.isNotEmpty(generalDeviceDTOList.get(0).getLineIndexes())) {
                    //已经最底层，展示电站和用户场站
                    List<MonitorInfoDTO> lineDetailList = lineMapper.getLineListByIds(generalDeviceDTOList.get(0).getLineIndexes());
                    List<String> ids = lineDetailList.stream().map(MonitorInfoDTO::getId).distinct().collect(Collectors.toList());
                    List<String> devIds = lineDetailList.stream().map(it -> it.getPids().split(StrUtil.COMMA)[LineBaseEnum.DEVICE_LEVEL.getCode()]).distinct().collect(Collectors.toList());
                    List<RStatIntegrityD> rStatIntegrityDList = new ArrayList<>();
                    List<RStatOnlinerateD> rStatOnlinerateDList = new ArrayList<>();
                    List<RStatLimitRateDPO> rStatLimitRateDPOList = new ArrayList<>();
                    getData(rStatIntegrityDList, rStatOnlinerateDList, rStatLimitRateDPOList, ids, devIds, businessParam.getSearchBeginTime(), businessParam.getSearchEndTime());
                    List<MonitorInfoDTO> detailList = lineDetailList.stream().filter(it -> StrUtil.isNotBlank(it.getObjId())).collect(Collectors.toList());
                    if (CollUtil.isNotEmpty(detailList)) {
                        List<String> objIds = detailList.stream().map(MonitorInfoDTO::getObjId).distinct().collect(Collectors.toList());
                        Map<String, NewUserReportVO> userReportVOMap = getUserLedgerByObjIds(objIds);
                        Map<String, List<MonitorInfoDTO>> map = detailList.stream().collect(Collectors.groupingBy(MonitorInfoDTO::getObjId));
                        map.forEach((objId, list) -> {
                            NewUserReportVO userLedgerVO = userReportVOMap.get(objId);
                            commDataCat(list, rStatIntegrityDList, rStatOnlinerateDList, rStatLimitRateDPOList, result, userLedgerVO.getProjectName());
                        });
                    }
                    List<MonitorInfoDTO> otherDetailList = lineDetailList.stream().filter(it -> StrUtil.isBlank(it.getObjId())).collect(Collectors.toList());
                    if (CollUtil.isNotEmpty(otherDetailList)) {
                        List<String> subIds = otherDetailList.stream().map(it -> it.getPids().split(StrUtil.COMMA)[LineBaseEnum.SUB_LEVEL.getCode()]).collect(Collectors.toList());
                        List<Line> subList = lineMapper.selectList(new LambdaQueryWrapper<Line>().in(Line::getId, subIds));
                        Map<String, Line> subMap = subList.stream().collect(Collectors.toMap(Line::getId, Function.identity()));
                        Map<String, List<MonitorInfoDTO>> map = otherDetailList.stream().collect(Collectors.groupingBy(it -> it.getPids().split(StrUtil.COMMA)[LineBaseEnum.SUB_LEVEL.getCode()]));
                        map.forEach((subId, list) -> {
                            String name = subMap.get(subId).getName();
                            commDataCat(list, rStatIntegrityDList, rStatOnlinerateDList, rStatLimitRateDPOList, result, name);
                        });
                    }
                }
            } else {
                for (GeneralDeviceDTO generalDeviceDTO : generalDeviceDTOList) {
                    if (CollUtil.isEmpty(generalDeviceDTO.getDeviceIndexes())) {
                        continue;
                    }
                    List<RStatIntegrityD> rStatIntegrityDList = new ArrayList<>();
                    List<RStatOnlinerateD> rStatOnlinerateDList = new ArrayList<>();
                    List<RStatLimitRateDPO> rStatLimitRateDPOList = new ArrayList<>();
                    getData(rStatIntegrityDList, rStatOnlinerateDList, rStatLimitRateDPOList, generalDeviceDTO.getLineIndexes(), generalDeviceDTO.getDeviceIndexes(), businessParam.getSearchBeginTime(), businessParam.getSearchEndTime());
                    result.add(getScoreData(generalDeviceDTO.getName(), generalDeviceDTO.getDeviceIndexes(), rStatIntegrityDList, rStatOnlinerateDList, rStatLimitRateDPOList));
                }
            }
        }

        return result.stream().sorted(Comparator.comparing(TerminalEvaluateAreaVO::getScore, Comparator.reverseOrder())).collect(Collectors.toList());
    }

    @Override
    public TerminalEvaluateAreaVO.lastWeekTrendVO lastWeekTrend(DeviceInfoParam.BusinessParam businessParam) {
        TerminalEvaluateAreaVO.lastWeekTrendVO lastWeekTrendVO = new TerminalEvaluateAreaVO.lastWeekTrendVO();
        List<String> nameList = new ArrayList<>();
        List<List<Double>> scoreList = new ArrayList<>();
        List<String> dateList = new ArrayList<>();
        List<GeneralDeviceDTO> generalDeviceDTOList = generalDeviceService.getDeviceInfo(businessParam, Stream.of(RunFlagEnum.RUNNING.getStatus()).collect(Collectors.toList()), Stream.of(PowerFlagEnum.REAL_DEVICE.getCode()).collect(Collectors.toList()));
        if (CollectionUtil.isNotEmpty(generalDeviceDTOList)) {
            DateTime end = DateUtil.parse(businessParam.getSearchBeginTime(), DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN));
            DateTime start = DateUtil.offsetDay(end, -7);
            List<DateTime> dateRange = DateUtil.rangeToList(start, end, DateField.DAY_OF_MONTH);
            for (DateTime dateTime : dateRange) {
                dateList.add(DateUtil.format(dateTime, DatePattern.NORM_DATE_PATTERN));
            }
            if (generalDeviceDTOList.size() == 1 && generalDeviceDTOList.get(0).getIndex().equals(businessParam.getDeptIndex())) {
                if (CollUtil.isNotEmpty(generalDeviceDTOList.get(0).getLineIndexes())) {
                    List<MonitorInfoDTO> lineDetailList = lineMapper.getLineListByIds(generalDeviceDTOList.get(0).getLineIndexes());
                    List<RStatIntegrityD> rStatIntegrityDList = new ArrayList<>();
                    List<RStatOnlinerateD> rStatOnlinerateDList = new ArrayList<>();
                    List<RStatLimitRateDPO> rStatLimitRateDPOList = new ArrayList<>();
                    getRangeData2(rStatIntegrityDList, rStatOnlinerateDList, rStatLimitRateDPOList, generalDeviceDTOList.get(0).getLineIndexes(), generalDeviceDTOList.get(0).getDeviceIndexes(), DateUtil.format(start, DatePattern.NORM_DATE_PATTERN), DateUtil.format(end, DatePattern.NORM_DATE_PATTERN));
                    Map<String, List<MonitorInfoDTO>> lineMap = lineDetailList.stream().collect(Collectors.groupingBy(MonitorInfoDTO::getObjId));
                    lineMap.forEach((key, detailList) -> {
                        if (StrUtil.isNotBlank(key)) {
                            List<String> objIds = detailList.stream().map(MonitorInfoDTO::getObjId).distinct().collect(Collectors.toList());
                            Map<String, NewUserReportVO> userReportVOMap = getUserLedgerByObjIds(objIds);
                            Map<String, List<MonitorInfoDTO>> map = detailList.stream().collect(Collectors.groupingBy(MonitorInfoDTO::getObjId));
                            map.forEach((objId, list) -> {
                                NewUserReportVO userLedgerVO = userReportVOMap.get(objId);
                                nameList.add(userLedgerVO.getProjectName());
                                rangeCatData(list, dateRange, rStatIntegrityDList, rStatOnlinerateDList, rStatLimitRateDPOList, scoreList);
                            });
                        } else {
                            List<String> subIds = detailList.stream().map(it -> it.getPids().split(StrUtil.COMMA)[LineBaseEnum.SUB_LEVEL.getCode()]).collect(Collectors.toList());
                            List<Line> subList = lineMapper.selectList(new LambdaQueryWrapper<Line>().in(Line::getId, subIds));
                            Map<String, Line> subMap = subList.stream().collect(Collectors.toMap(Line::getId, Function.identity()));
                            Map<String, List<MonitorInfoDTO>> map = detailList.stream().collect(Collectors.groupingBy(it -> it.getPids().split(StrUtil.COMMA)[LineBaseEnum.SUB_LEVEL.getCode()]));
                            map.forEach((subId, list) -> {
                                String name = subMap.get(subId).getName();
                                nameList.add(name);
                                rangeCatData(list, dateRange, rStatIntegrityDList, rStatOnlinerateDList, rStatLimitRateDPOList, scoreList);
                            });
                        }
                    });
                }
            } else {
                for (GeneralDeviceDTO generalDeviceDTO : generalDeviceDTOList) {
                    if (CollUtil.isEmpty(generalDeviceDTO.getLineIndexes())) {
                        continue;
                    }
                    List<RStatIntegrityD> rStatIntegrityDList = new ArrayList<>();
                    List<RStatOnlinerateD> rStatOnlinerateDList = new ArrayList<>();
                    List<RStatLimitRateDPO> rStatLimitRateDPOList = new ArrayList<>();
                    getRangeData(rStatIntegrityDList, rStatOnlinerateDList, rStatLimitRateDPOList, generalDeviceDTO.getLineIndexes(), generalDeviceDTO.getDeviceIndexes(), DateUtil.format(start, DatePattern.NORM_DATE_PATTERN), DateUtil.format(end, DatePattern.NORM_DATE_PATTERN));
                    nameList.add(generalDeviceDTO.getName());
                    List<Double> scoreDetailList = new ArrayList<>();
                    for (DateTime day : dateRange) {
                        List<RStatIntegrityD> temIntegrityList = rStatIntegrityDList.stream().filter(it -> it.getTimeId().equals(day.toLocalDateTime().toLocalDate())).collect(Collectors.toList());
                        List<RStatOnlinerateD> temOnlinerateList = rStatOnlinerateDList.stream().filter(it -> it.getTimeId().equals(day.toLocalDateTime().toLocalDate())).collect(Collectors.toList());
                        List<RStatLimitRateDPO> temLimitRateList = rStatLimitRateDPOList.stream().filter(it -> it.getTime().equals(day.toLocalDateTime().toLocalDate())).collect(Collectors.toList());
                        TerminalEvaluateAreaVO terminalEvaluateAreaVO = getScoreData("", generalDeviceDTO.getDeviceIndexes(), temIntegrityList, temOnlinerateList, temLimitRateList);
                        scoreDetailList.add(terminalEvaluateAreaVO.getScore());
                    }
                    scoreList.add(scoreDetailList);
                }
            }
        }
        lastWeekTrendVO.setDate(dateList);
        lastWeekTrendVO.setScore(scoreList);
        lastWeekTrendVO.setName(nameList);
        return lastWeekTrendVO;
    }

    @Override
    public List<DeviceRunEvaluateVO.Detail> getRunEvaluate(DeviceInfoParam.BusinessParam param) {
        List<DictData> manufacturerList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.DEV_MANUFACTURER.getCode()).getData();
        Map<String, String> manufacturerMap = manufacturerList.stream().collect(Collectors.toMap(DictData::getId, DictData::getName));
        List<Dept> deptList = deptFeignClient.getAllDept().getData();
        Map<String, String> deptMap = deptList.stream().collect(Collectors.toMap(Dept::getId, Dept::getName));

        List<DeviceRunEvaluateVO.Detail> info = new ArrayList<>();
        List<Integer> devRun=ObjectUtil.isNull(param.getLineRunFlag()) ? null : Arrays.asList(param.getLineRunFlag());
        param.setLineRunFlag(null);
        //获取终端台账类信息
        List<GeneralDeviceDTO> deviceInfo = deviceService.getDeviceInfo(param, devRun, Arrays.asList(1));
        if (CollUtil.isNotEmpty(deviceInfo)) {
            List<String> deviceIds = deviceInfo.stream()
                    .flatMap(x -> x.getDeviceIndexes().stream()).collect(Collectors.toList())
                    .stream()
                    .distinct()
                    .collect(Collectors.toList());
            List<String> lineIds = deviceInfo.stream()
                    .flatMap(x -> x.getLineIndexes().stream()).collect(Collectors.toList())
                    .stream()
                    .distinct()
                    .collect(Collectors.toList());
            //获取所有监测点信息信息
            List<DevDetailVO> lineDeviceByDevIds = lineMapper.getLineDeviceByDevIds(param.getPowerFlag(), lineIds, deviceIds);
            RStatLimitQueryParam rStatLimitQueryParam = new RStatLimitQueryParam();
            rStatLimitQueryParam.setIds(lineIds);
            rStatLimitQueryParam.setDate(param.getSearchBeginTime());
            rStatLimitQueryParam.setEndDate(param.getSearchEndTime());
            OnlineRateParam onlineRateParam = new OnlineRateParam();
            onlineRateParam.setIds(deviceIds);
            onlineRateParam.setStartTime(param.getSearchBeginTime());
            onlineRateParam.setEndTime(param.getSearchEndTime());
            DeviceRunEvaluateVO.Detail detail;
            //完整率
            List<RStatIntegrityVO> integrityList = integrityDMapper.getLineIntegrityRateInfo(lineIds, param.getSearchBeginTime(), param.getSearchEndTime());
            //获取所有终端在线率
            List<RStatOnlineRateVO> onlineRateByDev = onLineRateMapper.getOnlineRateByDevIds(onlineRateParam);
            //异常信息
            onlineRateParam.setIds(lineIds);
            List<PqDataVerifyCount> sumVerify = pqDataVerifyCountService.getSumVerify(onlineRateParam);


            for (GeneralDeviceDTO dto : deviceInfo) {
                detail = new DeviceRunEvaluateVO.Detail();
                detail.setName(dto.getName());
                detail.setCount(dto.getDeviceIndexes().size());
                detail.setOnline(onLineRate(onlineRateByDev, dto.getDeviceIndexes()));
                detail.setIntegrity(integrity(integrityList, dto.getLineIndexes()));
                detail.setQualified(verifyDev(sumVerify, dto.getLineIndexes(), dto.getDeviceIndexes()));
                detail.setScore(ONINTEGRITY.multiply(detail.getIntegrity())
                        .add(ONLINERATE.multiply(detail.getOnline())
                                .add(LIMITRATE.multiply(detail.getQualified()))).stripTrailingZeros().setScale(2, RoundingMode.HALF_UP));
                Map<String, List<DevDetailVO>> dev = lineDeviceByDevIds
                        .stream()
                        .filter(x -> dto.getDeviceIndexes().contains(x.getDevId()))
                        .collect(Collectors.groupingBy(DevDetailVO::getDevId));
                List<DeviceRunEvaluateVO> deviceDetail = new ArrayList<>();
                if (CollUtil.isNotEmpty(dev)) {
                    dev.forEach((key, value) -> {
                        List<String> ids = value.stream().map(DevDetailVO::getLineId).distinct().collect(Collectors.toList());
                        DeviceRunEvaluateVO evaluateVO = new DeviceRunEvaluateVO();
                        evaluateVO.setId(value.get(0).getDevId());
                        evaluateVO.setName(value.get(0).getDevName());
                        evaluateVO.setSubName(value.get(0).getSubName());
                        evaluateVO.setIp(value.get(0).getIp());
                        evaluateVO.setCompany(value.get(0).getCompany());
                        evaluateVO.setRunFlag(RunFlagEnum.getRunFlagRemarkByStatus(value.get(0).getRunFlag()));
                        //部门
                        if (deptMap.containsKey(value.get(0).getCit())) {
                            evaluateVO.setCit(deptMap.get(value.get(0).getCit()));
                        }
                        //终端厂商
                        if (manufacturerMap.containsKey(value.get(0).getManufacturer())) {
                            evaluateVO.setManufacturer(manufacturerMap.get(value.get(0).getManufacturer()));
                        }
                        evaluateVO.setOnLineRate(onLineRate(onlineRateByDev, Arrays.asList(key)));
                        evaluateVO.setIntegrityRate(integrity(integrityList, ids));
                        evaluateVO.setPassRate(verify(sumVerify, ids));
                        evaluateVO.setEvaluate(ONINTEGRITY.multiply(evaluateVO.getIntegrityRate())
                                .add(ONLINERATE.multiply(evaluateVO.getOnLineRate())
                                        .add(LIMITRATE.multiply(evaluateVO.getPassRate()))).stripTrailingZeros().setScale(2, RoundingMode.HALF_UP));
                        deviceDetail.add(evaluateVO);
                    });
                }
                detail.setList(deviceDetail);
                info.add(detail);
            }
        }
        return info;
    }

    private BigDecimal verifyDev(List<PqDataVerifyCount> sumVerify, List<String> lineIds, List<String> devIds) {
        //异常率
        List<PqDataVerifyCount> verifyList = sumVerify.stream().filter(x->x.getTotal()>0).filter(x -> lineIds.contains(x.getLineId())).collect(Collectors.toList());
        List<String> verifyLine = verifyList.stream().map(PqDataVerifyCount::getLineId).distinct().collect(Collectors.toList());
        if (CollUtil.isNotEmpty(verifyLine)) {
            List<String> devIdsLine = lineMapper.getDevIdsLine(verifyLine);
            if (CollUtil.isNotEmpty(devIdsLine)) {
                return NumberUtil.round(Math.min(devIdsLine.size() * 100.0 / devIds.size(), 100), 2);
            } else {
                return new BigDecimal(0);
            }
        } else {
            return new BigDecimal(0);
        }

    }

    private BigDecimal verify(List<PqDataVerifyCount> sumVerify, List<String> lineIds) {
        //异常率
        List<PqDataVerifyCount> verifyList = sumVerify.stream().filter(x -> lineIds.contains(x.getLineId())).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(verifyList)) {
            double total = verifyList.stream().mapToDouble(PqDataVerifyCount::getTotal).sum();
            double totalAll = verifyList.stream().mapToDouble(PqDataVerifyCount::getTotalAll).sum();
            if (totalAll  == 0) {
                return new BigDecimal(0);
            }
            return NumberUtil.round(Math.min(total  * 100.0 / totalAll, 100), 2);
        } else {
            return new BigDecimal(0);
        }
    }

    private BigDecimal integrity(List<RStatIntegrityVO> integrityList, List<String> lineIds) {
        //监测完整率
        List<RStatIntegrityVO> integrityDS = integrityList.stream().filter(x -> lineIds.contains(x.getLineIndex())).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(integrityDS)) {
            double realTime = integrityDS.stream().mapToDouble(RStatIntegrityVO::getRealTime).sum();
            double dueTime = integrityDS.stream().mapToDouble(RStatIntegrityVO::getDueTime).sum();
            if (dueTime == 0) {
                return new BigDecimal(0);
            }
            return NumberUtil.round(Math.min(realTime * 100.0 / dueTime, 100), 2);
        } else {
            return new BigDecimal(0);
        }
    }

    private BigDecimal onLineRate(List<RStatOnlineRateVO> onlineRateByDev, List<String> devIds) {
        //终端在线率
        List<RStatOnlineRateVO> onlineRateDS = onlineRateByDev.stream().filter(x -> devIds.contains(x.getDevIndex())).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(onlineRateDS)) {
            double onlineTime = onlineRateDS.stream().mapToDouble(RStatOnlineRateVO::getOnlineMin).sum();
            double offlineTime = onlineRateDS.stream().mapToDouble(RStatOnlineRateVO::getOfflineMin).sum();
            if ((onlineTime + offlineTime) == 0) {
                return new BigDecimal(0);
            }
            return NumberUtil.round(Math.min(onlineTime * 100.0 / (onlineTime + offlineTime), 100), 2);
        } else {
            return new BigDecimal(0);
        }
    }

    private BigDecimal limitRate(List<RStatLimitRateDPO> limitRatePOList, List<String> lineIds) {
        if (CollUtil.isEmpty(limitRatePOList)) {
            return new BigDecimal(0);
        }
        //超标信息
        List<RStatLimitRateDPO> limitRateDPOS = limitRatePOList.stream().filter(x -> lineIds.contains(x.getLineId())).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(limitRateDPOS)) {
            double overTime = limitRateDPOS.stream().mapToDouble(x -> (x.getUaberranceOvertime() +
                    x.getUharm2Overtime() + x.getUharm3Overtime() + x.getUharm4Overtime() + x.getUharm5Overtime() +
                    x.getUharm6Overtime() + x.getUharm7Overtime() + x.getUharm8Overtime() + x.getUharm9Overtime() +
                    x.getUharm10Overtime() + x.getUharm11Overtime() + x.getUharm12Overtime() + x.getUharm13Overtime() + x.getUharm14Overtime() +
                    x.getUharm15Overtime() + x.getUharm16Overtime() + x.getUharm17Overtime() + x.getUharm18Overtime() + x.getUharm19Overtime() +
                    x.getUharm20Overtime() + x.getUharm21Overtime() + x.getUharm22Overtime() + x.getUharm23Overtime() + x.getUharm24Overtime() +
                    x.getUharm25Overtime())).sum();
            double allTime = limitRateDPOS.stream().mapToDouble(x -> x.getAllTime() * 25.0).sum();
            if (allTime == 0) {
                return new BigDecimal(0);
            } else {
                return NumberUtil.round(Math.min((1 - (overTime * 1.0 / allTime)) * 100, 100), 2);
            }
        } else {
            return new BigDecimal(0);
        }
    }


    private Map<String, NewUserReportVO> getUserLedgerByObjIds(List<String> objIds) {
        List<NewUserReportVO> userReportVOList = userLedgerService.getUserReportByIds(objIds);
        return userReportVOList.stream().collect(Collectors.toMap(NewUserReportVO::getId, Function.identity()));
    }

    private void commDataCat(List<MonitorInfoDTO> list, List<RStatIntegrityD> rStatIntegrityDList, List<RStatOnlinerateD> rStatOnlinerateDList, List<RStatLimitRateDPO> rStatLimitRateDPOList, List<TerminalEvaluateAreaVO> result, String name) {
        List<String> lineIds = list.stream().map(MonitorInfoDTO::getId).collect(Collectors.toList());
        List<String> devList = list.stream().map(it -> it.getPids().split(StrUtil.COMMA)[LineBaseEnum.DEVICE_LEVEL.getCode()]).collect(Collectors.toList());
        List<RStatIntegrityD> temIntegrityList = rStatIntegrityDList.stream().filter(it -> lineIds.contains(it.getLineIndex())).collect(Collectors.toList());
        List<RStatLimitRateDPO> temlimitList = rStatLimitRateDPOList.stream().filter(it -> lineIds.contains(it.getLineId())).collect(Collectors.toList());
        List<RStatOnlinerateD> onlineList = rStatOnlinerateDList.stream().filter(it -> devList.contains(it.getDevIndex())).collect(Collectors.toList());
        result.add(getScoreData(name, devList, temIntegrityList, onlineList, temlimitList));
    }

    private TerminalEvaluateAreaVO getScoreData(String name, List<String> devIds, List<RStatIntegrityD> rStatIntegrityDList, List<RStatOnlinerateD> rStatOnlinerateDList, List<RStatLimitRateDPO> rStatLimitRateDPOList) {
        double integrityRate = 0;
        double onlineRate = 0;
        double qualifiedRate = 0;
        double pingFen;
        TerminalEvaluateAreaVO terminalEvaluateAreaVO = new TerminalEvaluateAreaVO();
        terminalEvaluateAreaVO.setName(name);
        terminalEvaluateAreaVO.setCount(devIds.size());
        if (CollectionUtil.isNotEmpty(rStatIntegrityDList)) {
            integrityRate = rStatIntegrityDList.stream().mapToDouble(it -> (double) it.getRealTime() / it.getDueTime()).average().orElse(0);
            terminalEvaluateAreaVO.setIntegrity(NumberUtil.round(integrityRate * 100, 2).doubleValue());
        }
        if (CollectionUtil.isNotEmpty(rStatOnlinerateDList)) {
            onlineRate = rStatOnlinerateDList.stream().mapToDouble(it -> (double) it.getOnlineMin() / (it.getOnlineMin() + it.getOfflineMin())).average().orElse(0);
            terminalEvaluateAreaVO.setOnline(NumberUtil.round(onlineRate * 100, 2).doubleValue());
        }
        if (CollectionUtil.isNotEmpty(rStatLimitRateDPOList)) {
            qualifiedRate = rStatLimitRateDPOList.stream().mapToDouble(it -> {
                if (it.getAllTime() == 0) {
                    return 0;
                } else {
                    int limit = it.getUharm2Overtime() + it.getUharm3Overtime() + it.getUharm4Overtime() + it.getUharm5Overtime() + it.getUharm6Overtime() +
                            it.getUharm7Overtime() + it.getUharm8Overtime() + it.getUharm9Overtime() + it.getUharm10Overtime() + it.getUharm11Overtime() +
                            it.getUharm12Overtime() + it.getUharm13Overtime() + it.getUharm14Overtime() + it.getUharm15Overtime() + it.getUharm16Overtime() +
                            it.getUharm17Overtime() + it.getUharm18Overtime() + it.getUharm19Overtime() + it.getUharm20Overtime() + it.getUharm21Overtime() +
                            it.getUharm22Overtime() + it.getUharm23Overtime() + it.getUharm24Overtime() + it.getUharm25Overtime() + it.getUaberranceOvertime();
                    return 1 - ((double) (limit) / it.getAllTime() * 25);
                }
            }).average().orElse(0);
            terminalEvaluateAreaVO.setQualified(NumberUtil.round(qualifiedRate * 100, 2).doubleValue());
        }
        pingFen = integrityRate * 0.5 + onlineRate * 0.2 + qualifiedRate * 0.3;
        terminalEvaluateAreaVO.setScore(BigDecimal.valueOf(pingFen * 100).setScale(2, RoundingMode.HALF_UP).doubleValue());
        return terminalEvaluateAreaVO;
    }

    private void rangeCatData(List<MonitorInfoDTO> list, List<DateTime> dateRange, List<RStatIntegrityD> rStatIntegrityDList, List<RStatOnlinerateD> rStatOnlinerateDList, List<RStatLimitRateDPO> rStatLimitRateDPOList, List<List<Double>> scoreList) {
        List<String> lineIds = list.stream().map(MonitorInfoDTO::getId).collect(Collectors.toList());
        List<String> devList = list.stream().map(it -> it.getPids().split(StrUtil.COMMA)[LineBaseEnum.DEVICE_LEVEL.getCode()]).collect(Collectors.toList());
        List<Double> scoreDetailList = new ArrayList<>();
        for (DateTime day : dateRange) {
            List<RStatIntegrityD> temIntegrityList = rStatIntegrityDList.stream().filter(it -> it.getTimeId().equals(day.toLocalDateTime().toLocalDate()) && lineIds.contains(it.getLineIndex())).collect(Collectors.toList());
            List<RStatOnlinerateD> temOnlinerateList = rStatOnlinerateDList.stream().filter(it -> it.getTimeId().equals(day.toLocalDateTime().toLocalDate()) && devList.contains(it.getDevIndex())).collect(Collectors.toList());
            List<RStatLimitRateDPO> temLimitRateList = rStatLimitRateDPOList.stream().filter(it -> it.getTime().equals(day.toLocalDateTime().toLocalDate()) && lineIds.contains(it.getLineId())).collect(Collectors.toList());
            TerminalEvaluateAreaVO terminalEvaluateAreaVO = getScoreData("", new ArrayList<>(), temIntegrityList, temOnlinerateList, temLimitRateList);
            scoreDetailList.add(terminalEvaluateAreaVO.getScore());
        }
        scoreList.add(scoreDetailList);
    }


    private void getData(List<RStatIntegrityD> rStatIntegrityDList, List<RStatOnlinerateD> rStatOnlinerateDList, List<RStatLimitRateDPO> rStatLimitRateDPOList, List<String> lineIds, List<String> devIds, String startTime, String endTime) {
        if (CollUtil.isNotEmpty(lineIds)) {
            rStatIntegrityDList.addAll(integrityDMapper.selectList(new QueryWrapper<RStatIntegrityD>()
                    .select("sum(real_time) as realTime,sum(due_time) as dueTime,line_index as lineIndex")
                    .in("line_index", lineIds)
                    .between("time_id", startTime, endTime)
                    .groupBy("line_index")));
            RStatLimitQueryParam rStatLimitQueryParam = new RStatLimitQueryParam();
            rStatLimitQueryParam.setIds(lineIds);
            rStatLimitQueryParam.setDate(startTime);
            rStatLimitQueryParam.setEndDate(endTime);
            rStatLimitRateDPOList.addAll(rStatLimitRateDClient.monitorIdsGetLimitInfo(rStatLimitQueryParam).getData());
        }
        if (CollectionUtil.isNotEmpty(devIds)) {
            rStatOnlinerateDList.addAll(onLineRateDMapper.selectList(new QueryWrapper<RStatOnlinerateD>()
                    .select("sum(online_min) as onlineMin,sum(offline_min) as offlineMin,dev_index as devIndex")
                    .in("dev_index", devIds)
                    .between("time_id", startTime, endTime)
                    .groupBy("dev_index")));
        }
    }


    private void getRangeData(List<RStatIntegrityD> rStatIntegrityDList, List<RStatOnlinerateD> rStatOnlinerateDList, List<RStatLimitRateDPO> rStatLimitRateDPOList, List<String> lineIds, List<String> devIds, String startTime, String endTime) {
        if (CollUtil.isNotEmpty(lineIds)) {
            rStatIntegrityDList.addAll(integrityDMapper.selectList(new QueryWrapper<RStatIntegrityD>()
                    .select("time_id as timeId,sum(real_time) as realTime,sum(due_time) as dueTime")
                    .in("line_index", lineIds)
                    .between("time_id", startTime, endTime)
                    .groupBy("time_id")));

            RStatLimitQueryParam rStatLimitQueryParam = new RStatLimitQueryParam();
            rStatLimitQueryParam.setIds(lineIds);
            rStatLimitQueryParam.setDate(startTime);
            rStatLimitQueryParam.setEndDate(endTime);
            rStatLimitRateDPOList.addAll(rStatLimitRateDClient.monitorIdsGetLimitInfo(rStatLimitQueryParam).getData());
        }
        if (CollectionUtil.isNotEmpty(devIds)) {
            rStatOnlinerateDList.addAll(onLineRateDMapper.selectList(new QueryWrapper<RStatOnlinerateD>()
                    .select("time_id as timeId,sum(online_min) as onlineMin,sum(offline_min) as offlineMin")
                    .in("dev_index", devIds)
                    .between("time_id", startTime, endTime)
                    .groupBy("time_id")));
        }
    }

    private void getRangeData2(List<RStatIntegrityD> rStatIntegrityDList, List<RStatOnlinerateD> rStatOnlinerateDList, List<RStatLimitRateDPO> rStatLimitRateDPOList, List<String> lineIds, List<String> devIds, String startTime, String endTime) {
        if (CollUtil.isNotEmpty(lineIds)) {
            rStatIntegrityDList.addAll(integrityDMapper.selectList(new QueryWrapper<RStatIntegrityD>()
                    .select("time_id as timeId,line_index as lineIndex,sum(real_time) as realTime,sum(due_time) as dueTime")
                    .in("line_index", lineIds)
                    .between("time_id", startTime, endTime)
                    .groupBy("time_id,line_index")));

            RStatLimitQueryParam rStatLimitQueryParam = new RStatLimitQueryParam();
            rStatLimitQueryParam.setIds(lineIds);
            rStatLimitQueryParam.setDate(startTime);
            rStatLimitQueryParam.setEndDate(endTime);
            rStatLimitRateDPOList.addAll(rStatLimitRateDClient.monitorIdsGetLimitInfo(rStatLimitQueryParam).getData());
        }
        if (CollectionUtil.isNotEmpty(devIds)) {
            rStatOnlinerateDList.addAll(onLineRateDMapper.selectList(new QueryWrapper<RStatOnlinerateD>()
                    .select("time_id as timeId,dev_index as devIndex,sum(online_min) as onlineMin,sum(offline_min) as offlineMin")
                    .in("dev_index", devIds)
                    .between("time_id", startTime, endTime)
                    .groupBy("time_id,dev_index")));
        }
    }

}
