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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.njcn.common.config.GeneralInfo;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.device.common.service.GeneralDeviceService;
import com.njcn.device.pq.api.AlarmClient;
import com.njcn.device.biz.enums.DeviceResponseEnum;
import com.njcn.device.pq.enums.LineBaseEnum;
import com.njcn.device.pq.mapper.*;
import com.njcn.device.pq.pojo.dto.GeneralDeviceDTO;
import com.njcn.device.pq.pojo.dto.PublicDTO;
import com.njcn.device.pq.pojo.param.DeviceInfoParam;
import com.njcn.device.pq.pojo.param.OnlineRateParam;
import com.njcn.device.pq.pojo.param.TerminalOnlineRateDataParam;

import com.njcn.device.pq.pojo.po.TerminalOnlineRateData;
import com.njcn.device.pq.pojo.vo.AlarmStrategyVO;
import com.njcn.device.pq.pojo.vo.OnlineRateCensusVO;
import com.njcn.device.pq.pojo.vo.RStatOnlineRateVO;
import com.njcn.device.pq.pojo.vo.TerminalOnlineRateDataVO;
import com.njcn.device.pq.service.TerminalOnlineRateDataService;
import com.njcn.device.pq.utils.DataStatisticsUtil;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.enums.DicDataTypeEnum;
import com.njcn.system.pojo.enums.StatisticsEnum;
import com.njcn.system.pojo.po.DictData;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 终端在线率列表
 *
 * @author yzh
 * @date 2022/9/19
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TerminalOnlineRateDataServiceImpl implements TerminalOnlineRateDataService {

    private final TerminalOnlineRateDataMapper terminalOnlineRateDataMapper;

    private final GeneralInfo generalInfo;

    private final GeneralDeviceService generalDeviceService;

    private final AlarmClient alarmClient;

    private final DicDataFeignClient dicDataFeignClient;

    private final RStatOnlinerateDMapper onlineRateMapper;





    /**
     * 终端在线率列表
     *
     * @param terminalOnlineRateDataParam
     * @return
     */
    @Override
    public List<TerminalOnlineRateDataVO> getOnlineRateData (TerminalOnlineRateDataParam terminalOnlineRateDataParam,Integer nodeType) {

        // 获取所有数据
        List<GeneralDeviceDTO> generalDeviceDTOList = generalDeviceService.getDeviceInfo(terminalOnlineRateDataParam, Stream.of(0).collect(Collectors.toList()), Stream.of(1).collect(Collectors.toList()));

        // 判断所有数据集合状态
        if (CollectionUtil.isNotEmpty(generalDeviceDTOList)) {

            // 创建集合返回数据
            List<TerminalOnlineRateDataVO> pro = new ArrayList<>();

            List<AlarmStrategyVO> alarmStrategyVos = new ArrayList<>();
            if (terminalOnlineRateDataParam.getServerName().equals("deviceBoot")) {
                // 获取告警策略列表
                alarmStrategyVos = alarmClient.getAlarmStrategyData().getData();
                // 判断告警策略数据状态
                if (CollectionUtil.isEmpty(alarmStrategyVos)) {
                    throw new BusinessException(DeviceResponseEnum.QUERY_ALARMSTRATEGY_DATA_EMPTY);
                }
            }

            // 遍历集合
            for (GeneralDeviceDTO generalDeviceDTO : generalDeviceDTOList) {
                // 判断监测点索引集合状态
                if (CollectionUtils.isEmpty(generalDeviceDTO.getLineIndexes())) {
                    continue;
                }
                // 创建实体类
                TerminalOnlineRateDataVO terminalOnlineRateDataVO = new TerminalOnlineRateDataVO();
                // 通过部分终端等级信息查询终端信息
                List<TerminalOnlineRateDataVO> deviceList = terminalOnlineRateDataMapper.getDevice(generalDeviceDTO.getDeviceIndexes(), terminalOnlineRateDataParam.getLineGrade());
                if (CollectionUtil.isEmpty(deviceList)) {
                    continue;
                }
                List<String> devIds = deviceList.stream().map(TerminalOnlineRateDataVO::getId).collect(Collectors.toList());
                // 根据装置id获取装置在线率
                List<TerminalOnlineRateData> terminalOnlineRateList = terminalOnlineRateDataMapper.getDevOnlineByDevIds(devIds,terminalOnlineRateDataParam.getSearchBeginTime(),terminalOnlineRateDataParam.getSearchEndTime());
                // 处理终端在线率
                DataStatisticsUtil.getTerminalOnlineRateData(terminalOnlineRateList, deviceList);

                // 通过装置pid即供电站索引查询供电站信息
                List<String> subIds = deviceList.stream().map(TerminalOnlineRateDataVO::getPid).distinct().collect(Collectors.toList());
                List<TerminalOnlineRateDataVO> subList = terminalOnlineRateDataMapper.getSubList(subIds);

                // 通过供电站pid即供电公司索引查询供电公司信息
                List<String> gdIds = subList.stream().map(TerminalOnlineRateDataVO::getPid).distinct().collect(Collectors.toList());
                List<TerminalOnlineRateDataVO> gdList = terminalOnlineRateDataMapper.getGdList(gdIds);

                // 通过供电公司索引查询省会
                List<TerminalOnlineRateDataVO> proList = terminalOnlineRateDataMapper.getProvinceList(gdIds);

                //处理变电站
                dealChildrenData(subList, deviceList, false);
                //处理供电公司
                dealChildrenData(gdList, subList, false);
                // 数据封装
                terminalOnlineRateDataVO.setId(generalDeviceDTO.getIndex());
                terminalOnlineRateDataVO.setName(generalDeviceDTO.getName());
                terminalOnlineRateDataVO.setLevel(0);
                if (terminalOnlineRateDataParam.getStatisticalType().getCode().equalsIgnoreCase(StatisticsEnum.POWER_NETWORK.getCode())) {
                    TerminalOnlineRateDataVO temp = gdList.stream()
                            .filter(t -> t.getAlgoDescribe() != null)
                            .min(Comparator.comparing(TerminalOnlineRateDataVO::getAlgoDescribe))
                            .orElseGet(TerminalOnlineRateDataVO::new);
                    terminalOnlineRateDataVO.setAlgoDescribe(temp.getAlgoDescribe());
                    terminalOnlineRateDataVO.setChildren(gdList);
                } else {
                    // 还需要额外处理省会
                    dealChildrenData(proList, gdList, false);
                    terminalOnlineRateDataVO.setChildren(proList);
                }
                pro.add(terminalOnlineRateDataVO);

            }
            getAreaOnlineRateData(pro, alarmStrategyVos, terminalOnlineRateDataParam.getLineGrade(),terminalOnlineRateDataParam.getServerName());
            if(nodeType==1){
                pro.stream().forEach(data->{
                    if(CollUtil.isNotEmpty(data.getChildren())){
                        //市
                        List<TerminalOnlineRateDataVO> sub = data.getChildren().stream().flatMap(dto -> dto.getChildren().stream()).collect(Collectors.toList());
                        sub.stream().forEach(x->{
                            x.setChildren(new ArrayList<>());
                        });
                        data.setChildren(sub);
                    }
                });
            }
            return pro;
        } else {
            return new ArrayList<>();
        }

    }
    @Override
    public OnlineRateCensusVO getOnlineRateDataCensus(DeviceInfoParam.CompareBusinessParam onlineRateCensusParam) {
        OnlineRateCensusVO onlineRateCensusVO = new OnlineRateCensusVO();
        onlineRateCensusParam.setServerName(generalInfo.getMicroServiceName());
        List<GeneralDeviceDTO> generalDeviceDTOList = generalDeviceService.getDeviceInfo(onlineRateCensusParam,Stream.of(0).collect(Collectors.toList()), Stream.of(1).collect(Collectors.toList()));
        List<String> type = new ArrayList<>();
        List<Double> single = new ArrayList<>(), ratio = new ArrayList<>();
        if (!CollectionUtils.isEmpty(generalDeviceDTOList)) {
            for (GeneralDeviceDTO generalDeviceDTO: generalDeviceDTOList){
                List<String> deviceIndexes = generalDeviceDTO.getDeviceIndexes();
                if (CollectionUtils.isEmpty(deviceIndexes)) {
                    continue;
                }
                type.add(generalDeviceDTO.getName()+"\n("+generalDeviceDTO.getLineIndexes().size()+")");
                //根据终端索引集查询在线率
                List<PublicDTO> onlineRateList = getCondition(deviceIndexes, onlineRateCensusParam.getSearchBeginTime(), onlineRateCensusParam.getSearchEndTime());
                // 汇总所有设备的在线分钟和离线分钟，再计算总在线率
                int totalOnlineMin = (int) onlineRateList.stream().mapToLong(PublicDTO::getOnlineMin).sum();
                int totalOfflineMin = (int) onlineRateList.stream().mapToLong(PublicDTO::getOfflineMin).sum();
                single.add(DataStatisticsUtil.calculateOnlineRate(totalOnlineMin, totalOfflineMin));
                //如果存在需要比较的时间，再获取对应数据
                if(StrUtil.isNotBlank(onlineRateCensusParam.getPeriodBeginTime()) && StrUtil.isNotBlank(onlineRateCensusParam.getPeriodEndTime())){
                    List<PublicDTO> compareData = getCondition(deviceIndexes, onlineRateCensusParam.getPeriodBeginTime(), onlineRateCensusParam.getPeriodEndTime());
                    // 汇总所有设备的在线分钟和离线分钟，再计算总在线率
                    int compareOnlineMin = (int) compareData.stream().mapToLong(PublicDTO::getOnlineMin).sum();
                    int compareOfflineMin = (int) compareData.stream().mapToLong(PublicDTO::getOfflineMin).sum();
                    ratio.add(DataStatisticsUtil.calculateOnlineRate(compareOnlineMin, compareOfflineMin));
                }
            }
        }
        onlineRateCensusVO.setType(type);
        onlineRateCensusVO.setSingle(single);
        onlineRateCensusVO.setRatio(ratio);


        return onlineRateCensusVO;
    }



    private List<PublicDTO> getCondition(List<String> deviceIndexes, String searchBeginTime, String searchEndTime) {
        List<PublicDTO> publicDTOList = new ArrayList<>();
        OnlineRateParam param=new OnlineRateParam();
        param.setIds(deviceIndexes);
        param.setStartTime( DateUtil.beginOfDay(DateUtil.parse(searchBeginTime)).toString());
        param.setEndTime( DateUtil.endOfDay(DateUtil.parse(searchEndTime)).toString());
        List<RStatOnlineRateVO> data = onlineRateMapper.getOnlineRateByDevIds(param);
        if (CollUtil.isNotEmpty(data)) {
            data.forEach(po -> {
                PublicDTO publicDTO = new PublicDTO();
                publicDTO.setId(po.getDevIndex());
                publicDTO.setOnlineMin(po.getOnlineMin() == null ? 0 : po.getOnlineMin().intValue());
                publicDTO.setOfflineMin(po.getOfflineMin() == null ? 0 : po.getOfflineMin().intValue());
                // 计算在线率
                Double onlineRate = DataStatisticsUtil.calculateOnlineRate(publicDTO.getOnlineMin(), publicDTO.getOfflineMin());
                publicDTO.setData(onlineRate);
                publicDTOList.add(publicDTO);
            });
        }
        return publicDTOList;
    }

    /**
     * 处理变电站
     *
     * @param targetData   父集合
     * @param childrenData 子集合
     * @param isLine       处理策略
     */
    private void dealChildrenData(List<TerminalOnlineRateDataVO> targetData, List<TerminalOnlineRateDataVO> childrenData, boolean isLine) {
        // 创建一个map集合，用于封装对象
        Map<String, List<TerminalOnlineRateDataVO>> groupLine;
        if (isLine) {
            // 通过stream流分组
            groupLine = childrenData.stream().collect(Collectors.groupingBy(terminalOnlineRateDataVO -> {
                // 获取父id字符串，通过 逗号 分割 成一个数组
                String[] pid = terminalOnlineRateDataVO.getPids().split(",");
                // 判断集合索引为3的元素
                return pid[LineBaseEnum.SUB_LEVEL.getCode()];
            }));
        } else {
            groupLine = childrenData.stream().collect(Collectors.groupingBy(TerminalOnlineRateDataVO::getPid));
        }
        targetData = targetData.stream().peek(terminalOnlineRateDataVO -> {
            Set<String> pids = groupLine.keySet();
            for (String pid : pids) {
                if (terminalOnlineRateDataVO.getId().equals(pid)) {
                    List<TerminalOnlineRateDataVO> list = groupLine.get(pid);
                    TerminalOnlineRateDataVO temp = list.stream().filter(t -> t.getAlgoDescribe() != null).min(Comparator.comparing(TerminalOnlineRateDataVO::getAlgoDescribe)).orElse(new TerminalOnlineRateDataVO());
                    terminalOnlineRateDataVO.setAlgoDescribe(temp.getAlgoDescribe());
                    terminalOnlineRateDataVO.setChildren(list);
                }
            }
        }).collect(Collectors.toList());
    }



    /**
     * 获取区域终端在线率
     *
     * @param terminalOnlineRateData
     * @param serverName
     */
    public void getAreaOnlineRateData(List<TerminalOnlineRateDataVO> terminalOnlineRateData, List<AlarmStrategyVO> alarmStrategyVos, String lineGrade, String serverName) {

        Map<Integer, Integer> mapAlarm = new HashMap<>();
        Map<String, AlarmStrategyVO> map = alarmStrategyVos.stream().collect(Collectors.toMap(AlarmStrategyVO::getId, Function.identity()));

        if (serverName.equals("deviceBoot")) {
            if (StrUtil.isNotBlank(lineGrade)) {
                // 根据入参终端等级查字典表
                DictData dictData = dicDataFeignClient.getDicDataById(lineGrade).getData();
                if (map.containsKey(dictData.getId())) {
                    // key:监测点等级AlgoDescribe value:监测点对应在线率告警阈值
                    mapAlarm.put(dictData.getAlgoDescribe(), map.get(dictData.getId()).getOnlineValue());
                } else {
                    throw new BusinessException(DeviceResponseEnum.QUERY_ALARMSTRATEGY_DATA_EMPTY);
                }
            } else {
                List<DictData> dictDataList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.DEV_LEVEL.getCode()).getData();
                dictDataList.forEach(it -> {
                    if (map.containsKey(it.getId())) {
                        mapAlarm.put(it.getAlgoDescribe(), map.get(it.getId()).getOnlineValue());
                    } else {
                        throw new BusinessException(DeviceResponseEnum.QUERY_ALARMSTRATEGY_DATA_EMPTY);
                    }
                });
            }
        } else {
            mapAlarm.put(0,0);
        }

        for (TerminalOnlineRateDataVO proItem : terminalOnlineRateData) {
            List<TerminalOnlineRateDataVO> gds = proItem.getChildren();
            if (CollectionUtil.isNotEmpty(gds)) {
                for (TerminalOnlineRateDataVO gdItem : gds) {
                    List<TerminalOnlineRateDataVO> subs = gdItem.getChildren();
                    if (CollectionUtil.isNotEmpty(subs)) {
                        for (TerminalOnlineRateDataVO subItem : subs) {
                            // 装置集合
                            List<TerminalOnlineRateDataVO> devs = subItem.getChildren();
                            if (CollectionUtil.isNotEmpty(devs)) {
                                for (TerminalOnlineRateDataVO devItem : devs) {
                                    if (devItem.getChildren().size()==0) {
                                        if (mapAlarm.containsKey(devItem.getAlgoDescribe())) {
                                            if (devItem.getOnlineRate() != 3.14159  && devItem.getOnlineRate() > mapAlarm.get(devItem.getAlgoDescribe())) {
                                                devItem.setValueOver(1);
                                            } else {
                                                devItem.setValueOver(0);
                                            }
                                        }
                                    } else {
                                        List<TerminalOnlineRateDataVO> children = devItem.getChildren();
                                        for (TerminalOnlineRateDataVO child : children) {
                                            if (mapAlarm.containsKey(child.getAlgoDescribe())) {
                                                if (child.getOnlineRate() != 3.14159 && child.getOnlineRate() > mapAlarm.get(child.getAlgoDescribe())) {
                                                    child.setValueOver(1);
                                                } else {
                                                    child.setValueOver(0);
                                                }
                                            }
                                        }
                                        // 汇总子节点的在线分钟和离线分钟，重新计算在线率
                                        int totalOnlineMin = (int) children.stream().filter(item -> item.getOnlineRate() != 3.14159).mapToLong(TerminalOnlineRateDataVO::getOnlineMin).sum();
                                        int totalOfflineMin = (int) children.stream().filter(item -> item.getOnlineRate() != 3.14159).mapToLong(TerminalOnlineRateDataVO::getOfflineMin).sum();
                                        devItem.setOnlineMin(totalOnlineMin);
                                        devItem.setOfflineMin(totalOfflineMin);
                                        devItem.setOnlineRate(DataStatisticsUtil.calculateOnlineRate(totalOnlineMin, totalOfflineMin));
                                    }
                                }
                                // 汇总设备的在线分钟和离线分钟，重新计算变电站在线率
                                int totalOnlineMin = (int)devs.stream().filter(item -> item.getOnlineRate() != 3.14159).mapToLong(TerminalOnlineRateDataVO::getOnlineMin).sum();
                                int totalOfflineMin = (int)devs.stream().filter(item -> item.getOnlineRate() != 3.14159).mapToLong(TerminalOnlineRateDataVO::getOfflineMin).sum();
                                subItem.setOnlineMin(totalOnlineMin);
                                subItem.setOfflineMin(totalOfflineMin);
                                subItem.setOnlineRate(DataStatisticsUtil.calculateOnlineRate(totalOnlineMin, totalOfflineMin));
                            } else {
                                subItem.setOnlineRate(3.14159);
                                subItem.setOnlineMin(0);
                                subItem.setOfflineMin(0);
                            }
                            if (Objects.nonNull(subItem.getAlgoDescribe())) {
                                if (mapAlarm.containsKey(subItem.getAlgoDescribe())) {
                                    if (subItem.getOnlineRate() != 3.14159 && subItem.getOnlineRate() > mapAlarm.get(subItem.getAlgoDescribe())) {
                                        subItem.setValueOver(1);
                                    } else {
                                        subItem.setValueOver(0);
                                    }
                                }
                            }
                        }
                        // 汇总变电站的在线分钟和离线分钟，重新计算供电公司在线率
                        int totalOnlineMin = (int) subs.stream().filter(item -> item.getOnlineRate() != 3.14159).mapToLong(TerminalOnlineRateDataVO::getOnlineMin).sum();
                        int totalOfflineMin = (int) subs.stream().filter(item -> item.getOnlineRate() != 3.14159).mapToLong(TerminalOnlineRateDataVO::getOfflineMin).sum();
                        gdItem.setOnlineMin(totalOnlineMin);
                        gdItem.setOfflineMin(totalOfflineMin);
                        gdItem.setOnlineRate(DataStatisticsUtil.calculateOnlineRate(totalOnlineMin, totalOfflineMin));
                    } else {
                        gdItem.setOnlineRate(3.14159);
                        gdItem.setOnlineMin(0);
                        gdItem.setOfflineMin(0);
                    }
                    if (Objects.nonNull(gdItem.getAlgoDescribe())) {
                        if (mapAlarm.containsKey(gdItem.getAlgoDescribe())) {
                            if (gdItem.getOnlineRate() != 3.14159 && gdItem.getOnlineRate() > mapAlarm.get(gdItem.getAlgoDescribe())) {
                                gdItem.setValueOver(1);
                            } else {
                                gdItem.setValueOver(0);
                            }
                        }
                    }
                }
                // 汇总供电公司的在线分钟和离线分钟，重新计算省会在线率
                int totalOnlineMin = (int) gds.stream().filter(item -> item.getOnlineRate() != 3.14159).mapToLong(TerminalOnlineRateDataVO::getOnlineMin).sum();
                int totalOfflineMin = (int) gds.stream().filter(item -> item.getOnlineRate() != 3.14159).mapToLong(TerminalOnlineRateDataVO::getOfflineMin).sum();
                proItem.setOnlineMin(totalOnlineMin);
                proItem.setOfflineMin(totalOfflineMin);
                proItem.setOnlineRate(DataStatisticsUtil.calculateOnlineRate(totalOnlineMin, totalOfflineMin));
            } else {
                proItem.setOnlineRate(3.14159);
                proItem.setOnlineMin(0);
                proItem.setOfflineMin(0);
            }
            if (Objects.nonNull(proItem.getAlgoDescribe())) {
                if (mapAlarm.containsKey(proItem.getAlgoDescribe()))
                if (proItem.getOnlineRate() != 3.14159 && proItem.getOnlineRate() > mapAlarm.get(proItem.getAlgoDescribe())){
                    proItem.setValueOver(1);
                } else {
                    proItem.setValueOver(0);
                }
            }
        }
    }

}
