package com.njcn.device.common.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.njcn.common.pojo.dto.SimpleDTO;
import com.njcn.common.pojo.enums.common.ServerEnum;
import com.njcn.common.utils.EnumUtils;
import com.njcn.device.common.mapper.TopMsgMapper;
import com.njcn.device.device.mapper.DeviceMapper;
import com.njcn.device.line.mapper.LineMapper;
import com.njcn.device.line.service.DeptLineService;
import com.njcn.device.pq.enums.JbPowerFlagEnum;
import com.njcn.device.pq.enums.LineBaseEnum;
import com.njcn.device.pq.enums.PowerFlagEnum;
import com.njcn.device.pq.pojo.bo.DeviceType;
import com.njcn.device.pq.pojo.dto.GeneralDeviceDTO;
import com.njcn.device.pq.pojo.param.DeviceInfoParam;
import com.njcn.device.pq.pojo.param.OnlineRateParam;
import com.njcn.device.pq.pojo.po.DeptLine;
import com.njcn.device.pq.pojo.po.Device;
import com.njcn.device.pq.pojo.po.Line;
import com.njcn.device.pq.pojo.po.TopMsgPO;
import com.njcn.device.pq.pojo.vo.DeptDeviceDetailVO;
import com.njcn.device.pq.pojo.vo.DeptSubstationDetailVO;
import com.njcn.device.pq.pojo.vo.DevDetail;
import com.njcn.device.pq.pojo.vo.ExceptionDeviceInfoVO;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.enums.DicDataEnum;
import com.njcn.system.enums.DicDataTypeEnum;
import com.njcn.system.pojo.enums.StatisticsEnum;
import com.njcn.system.pojo.po.DictData;
import com.njcn.user.api.DeptFeignClient;
import com.njcn.user.pojo.dto.DeptDTO;
import com.njcn.user.pojo.po.Dept;
import com.njcn.web.utils.WebUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

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

/**
 * 终端信息处理器，根据需求返回笼统的台账信息。
 * ii * 包括：类别名称、类别索引、监测点索引集合、终端索引集合、变电站索引集bb合、供电公司索引集合。
 * PS:若后期需要比如：省会、项目时再动态添加。
 *
 * @author hongawen
 * @version 1.0.0
 * @date 2022年02月11日 09:29
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class GeneralDeviceService {

    private final DeptFeignClient deptFeignClient;

    private final DeptLineService deptLineService;

    private final TerminalBaseService terminalBaseService;

    private final DicDataFeignClient dicDataFeignClient;

    private final DeviceMapper deviceMapper;

    private final LineMapper lineMapper;

    private final TopMsgMapper topMsgMapper;


    /**
     * 根据部门id、远程服务名、远程客户端类型，以部门的方式
     *
     * @param runFlag  终端状态
     * @param devModel 终端模型
     * @return 部门分类终端信息
     */
    @Deprecated
    public List<GeneralDeviceDTO> getDeviceInfoAsDept(DeviceInfoParam deviceInfoParam, List<Integer> runFlag, List<Integer> devModel) {
        List<GeneralDeviceDTO> deviceInfos = new ArrayList<>();
        List<Integer> deptType = WebUtil.filterDeptType();
        //获取包括当前部门的后代所有部门信息
        List<DeptDTO> deptInfos = deptFeignClient.getDeptDescendantIndexes(deviceInfoParam.getDeptIndex(), deptType).getData();

        DeviceType deviceType = new DeviceType();
        if (CollectionUtil.isEmpty(devModel)) {
            deviceType.setDevModel(null);
        } else {
            deviceType.setDevModel(devModel);
        }
        if (CollectionUtil.isEmpty(runFlag)) {
            deviceType.setRunFlag(null);
        } else {
            deviceType.setRunFlag(runFlag);
        }
        filterDataType(deviceType, deviceInfoParam.getServerName());

        List<DeptDTO> directDeptInfos = deptInfos.stream()
                .filter(deptDTO -> deptDTO.getPid().equals(deviceInfoParam.getDeptIndex()))
                .collect(Collectors.toList());
        if (CollectionUtil.isEmpty(directDeptInfos)) {
            //没有直接子部门，获取当前部门所有信息
            List<DeptDTO> dept = deptInfos.stream()
                    .filter(deptDTO -> deptDTO.getId().equals(deviceInfoParam.getDeptIndex()))
                    .collect(Collectors.toList());
            deviceInfos.add(getGeneralDeviceInfoAsDept(dept.get(0), deviceType, Collections.singletonList(deviceInfoParam.getDeptIndex()), deviceInfoParam));
        } else {
            for (DeptDTO deptDTO : directDeptInfos) {
                //筛选上级部门pids包含该id的所有部门
                List<DeptDTO> descendantDeptDTO = deptInfos.stream()
                        .filter(d -> d.getPids().contains(deptDTO.getId()))
                        .collect(Collectors.toList());
                //形成需要查询监测点的部门索引
                List<String> indexes = descendantDeptDTO.stream()
                        .map(DeptDTO::getId)
                        .distinct()
                        .collect(Collectors.toList());
                indexes.add(deptDTO.getId());
                deviceInfos.add(getGeneralDeviceInfoAsDept(deptDTO, deviceType, indexes, deviceInfoParam));
            }
        }
        return deviceInfos;

    }

    private GeneralDeviceDTO getGeneralDeviceInfoAsDept(DeptDTO deptDTO, DeviceType deviceType, List<String> ids, DeviceInfoParam deviceInfoParam) {
        GeneralDeviceDTO generalDeviceDTO = new GeneralDeviceDTO();
        generalDeviceDTO.setIndex(deptDTO.getId());
        if (deptDTO.getType() == 0) {
            generalDeviceDTO.setName(deptDTO.getArea());
        } else {
            generalDeviceDTO.setName(deptDTO.getName());
        }
        List<DeptLine> deptLines = deptLineService.selectDeptBindLines(ids);
        //返回空数据
        if (CollectionUtil.isEmpty(deptLines)) {
            return generalDeviceDTO;
        }
        //获取line详细数据
        List<Line> lines = terminalBaseService.getLineByCondition(deptLines.stream().map(DeptLine::getLineId).collect(Collectors.toList()), deviceInfoParam);
        //返回空数据
        if (CollectionUtil.isEmpty(lines)) {
            return generalDeviceDTO;
        }
        //筛选出终端id，理论上监测点的pids中第五个id为终端id
        List<String> devIds = lines.stream().map(line -> {
            String[] idsArray = line.getPids().split(",");
            return idsArray[4];
        }).collect(Collectors.toList());
        //再根据终端条件筛选合法终端信息
        List<Line> devices = terminalBaseService.getDeviceById(devIds, deviceType);
        //筛选最终的数据
        dealDeviceData(generalDeviceDTO, lines, devices);
        return generalDeviceDTO;
    }

    /**
     * 处理各节点索引集合
     *
     * @param generalDeviceDTO 终端信息综合体
     * @param lines            监测点信息
     * @param devices          终端信息
     */
    private void dealDeviceData(GeneralDeviceDTO generalDeviceDTO, List<Line> lines, List<Line> devices) {
        List<String> gdIndexes = new ArrayList<>(), subIndexes = new ArrayList<>(), deviceIndexes = new ArrayList<>(), voltageIndexes = new ArrayList<>(), lineIndexes = new ArrayList<>();
        //筛选出供电公司、变电站、终端索引集合
        for (Line device : devices) {
            String[] ids = device.getPids().split(",");
            gdIndexes.add(ids[2]);
            subIndexes.add(ids[3]);
            deviceIndexes.add(device.getId());
        }
        //筛选出母线、监测点集合
        for (Line line : lines) {
            String[] ids = line.getPids().split(",");
            if (deviceIndexes.contains(ids[4])) {
                lineIndexes.add(line.getId());
                voltageIndexes.add(ids[5]);
            }
        }
        //排重，入参到终端综合体
        generalDeviceDTO.setGdIndexes(gdIndexes.stream().distinct().collect(Collectors.toList()));
        generalDeviceDTO.setSubIndexes(subIndexes.stream().distinct().collect(Collectors.toList()));
        generalDeviceDTO.setDeviceIndexes(deviceIndexes.stream().distinct().collect(Collectors.toList()));
        generalDeviceDTO.setVoltageIndexes(voltageIndexes.stream().distinct().collect(Collectors.toList()));
        generalDeviceDTO.setLineIndexes(lineIndexes.stream().distinct().collect(Collectors.toList()));

    }

    /**
     * 根据条件获取按变电站分类的终端信息
     *
     * @param deviceInfoParam 终端查询条件
     * @param runFlag         终端状态
     * @param devModel        终端模型
     * @return 终端信息
     */
    public List<GeneralDeviceDTO> getDeviceInfoAsSubstation(DeviceInfoParam deviceInfoParam, List<Integer> runFlag, List<Integer> devModel) {
        List<GeneralDeviceDTO> deviceInfoAsSubstation = new ArrayList<>();
        List<String> scale = new ArrayList<>();
        if (CollUtil.isNotEmpty(deviceInfoParam.getScale())) {
            scale = deviceInfoParam.getScale().stream().map(SimpleDTO::getId).collect(Collectors.toList());
            deviceInfoParam.setScale(new ArrayList<>());
        }

        List<GeneralDeviceDTO> deviceInfoAsDept = getDeviceInfo(deviceInfoParam, runFlag, devModel);
        List<String> substationIds = new ArrayList<>();
        List<String> lineIds = new ArrayList<>();
        if (!CollectionUtil.isEmpty(deviceInfoAsDept)) {
            for (GeneralDeviceDTO generalDeviceDTO : deviceInfoAsDept) {
                substationIds.addAll(generalDeviceDTO.getSubIndexes());
                lineIds.addAll(generalDeviceDTO.getLineIndexes());
            }
        } else {
            return deviceInfoAsSubstation;
        }
        substationIds = substationIds.stream().distinct().collect(Collectors.toList());
        lineIds = lineIds.stream().distinct().collect(Collectors.toList());
        if (!CollectionUtil.isEmpty(substationIds)) {
            List<Line> substations = terminalBaseService.getSubstationByIds(substationIds, scale);
            List<Line> lines = terminalBaseService.getLineById(lineIds);
            for (Line substation : substations) {
                deviceInfoAsSubstation.add(mergeDeviceInfoAsSubstation(substation, lines));
            }
        }
        return deviceInfoAsSubstation;
    }

    /**
     * 根据变电站筛选数据
     *
     * @param substation 变电站
     * @param lines      监测点信息
     * @return 按变电站分类的终端信息
     */
    private GeneralDeviceDTO mergeDeviceInfoAsSubstation(Line substation, List<Line> lines) {
        List<String> gdIndexes = new ArrayList<>(), subIndexes = new ArrayList<>(), deviceIndexes = new ArrayList<>(), voltageIndexes = new ArrayList<>(), lineIndexes = new ArrayList<>();
        GeneralDeviceDTO generalDeviceDTO = new GeneralDeviceDTO();
        generalDeviceDTO.setName(substation.getName());
        generalDeviceDTO.setIndex(substation.getId());
        gdIndexes.add(substation.getPid());
        subIndexes.add(substation.getId());
        generalDeviceDTO.setGdIndexes(gdIndexes);
        generalDeviceDTO.setSubIndexes(subIndexes);
        //筛选终端、母线、监测点索引
        for (Line line : lines) {
            String[] ids = line.getPids().split(",");
            if (ids[3].equals(substation.getId())) {
                deviceIndexes.add(ids[4]);
                voltageIndexes.add(ids[5]);
                lineIndexes.add(line.getId());
            }
        }
        generalDeviceDTO.setDeviceIndexes(deviceIndexes.stream().distinct().collect(Collectors.toList()));
        generalDeviceDTO.setVoltageIndexes(voltageIndexes.stream().distinct().collect(Collectors.toList()));
        generalDeviceDTO.setLineIndexes(lineIndexes.stream().distinct().collect(Collectors.toList()));
        return generalDeviceDTO;
    }


    /**
     * 筛选数据类型
     */
    private void filterDataType(DeviceType deviceType, String serverName) {
        ServerEnum serverEnum = EnumUtils.getServerEnumByName(serverName);
        List<Integer> dataType = new ArrayList<>();
        dataType.add(2);
        switch (serverEnum) {
            case EVENT:
                dataType.add(0);
                break;
            case HARMONIC:
                dataType.add(1);
                break;
            default:
                dataType.add(0);
                dataType.add(1);
                break;
        }
        /**
         * 数据类型（0：暂态系统；1：稳态系统；2：两个系统）
         */
        deviceType.setDataType(dataType);
    }

    /**
     * 根据部门id、远程服务名、远程客户端类型，以部门的方式
     *
     * @param deviceInfoParam 终端查询条件
     * @param runFlag         终端状态
     * @param devModel        终端模型
     * @return 部门分类终端信息
     */
    public List<GeneralDeviceDTO> getDeviceInfo(DeviceInfoParam deviceInfoParam,
                                                List<Integer> runFlag,
                                                List<Integer> devModel) {
        //定义待返回终端信息
        List<GeneralDeviceDTO> deviceInfos = new ArrayList<>();
        //初始化终端查询条件
        DeviceType deviceType = new DeviceType();
        if (CollectionUtil.isEmpty(devModel)) {
            /**
             * 终端模型（0：虚拟设备；1：实际设备；2：离线设备；）默认是实际设备
             */
            deviceType.setDevModel(null);
        } else {
            deviceType.setDevModel(devModel);
        }
        if (CollectionUtil.isEmpty(runFlag)) {
            /**
             * 终端状态（0：投运；1：热备用；2：停运）
             */
            deviceType.setRunFlag(null);
        } else {
            deviceType.setRunFlag(runFlag);
        }
        if (ObjectUtil.isNotNull(deviceInfoParam.getComFlagStatus())) {
            deviceType.setComFlag(Arrays.asList(deviceInfoParam.getComFlagStatus()));
        }
        filterDataType(deviceType, deviceInfoParam.getServerName());

        // 初始化部门筛选条件
        List<Integer> deptType = WebUtil.filterDeptType();
        // 获取包括当前部门的后代所有部门信息
        List<DeptDTO> deptInfos = deptFeignClient.getDeptDescendantIndexes(deviceInfoParam.getDeptIndex(), deptType).getData();
        // 过滤非直接后代部门，集合直接子部门
        List<DeptDTO> directDeptInfos = deptInfos.stream()
                .filter(deptDTO -> deptDTO.getPid().equals(deviceInfoParam.getDeptIndex())).sorted(Comparator.comparing(DeptDTO::getSort))
                .collect(Collectors.toList());
        if (CollectionUtil.isEmpty(directDeptInfos)) {
            // 没有直接子部门（树的最底层），获取当前部门所有信息
            List<DeptDTO> dept = deptInfos.stream()
                    .filter(deptDTO -> deptDTO.getId().equals(deviceInfoParam.getDeptIndex()))
                    .collect(Collectors.toList());
            deviceInfos.add(getGeneralDeviceInfo(
                    dept.get(0),
                    deviceType,
                    Collections.singletonList(deviceInfoParam.getDeptIndex()),
                    deviceInfoParam));
        } else {
            for (DeptDTO directDeptDTO : directDeptInfos) {
                //筛选pids包含该id的所有部门 直接子部门下属所有部门
                List<DeptDTO> descendantDeptDTO = deptInfos.stream()
                        .filter(d -> d.getPids().contains(directDeptDTO.getId()))
                        .collect(Collectors.toList());
                //形成需要查询监测点的部门索引
                List<String> indexes = descendantDeptDTO.stream()
                        .map(DeptDTO::getId)
                        .distinct()
                        .collect(Collectors.toList());
                indexes.add(directDeptDTO.getId());
                GeneralDeviceDTO generalDeviceInfo = getGeneralDeviceInfo(directDeptDTO, deviceType, indexes, deviceInfoParam);
                deviceInfos.add(generalDeviceInfo);
            }
        }


        //判断统计类型
        if (deviceInfoParam.getStatisticalType() == null) {
            deviceInfoParam.setStatisticalType(new SimpleDTO());
        }
        StatisticsEnum statisticsEnum = StatisticsEnum.getStatisticsEnumByCode(deviceInfoParam.getStatisticalType().getCode());
        switch (statisticsEnum) {
            case VOLTAGE_LEVEL:
                return filterDataByScale(deviceInfos, deviceInfoParam.getScale(),deviceInfoParam.getLineOrDevice());
            case LOAD_TYPE:
                return filterDataByLoadType(deviceInfos, deviceInfoParam.getLoadType());
            case MANUFACTURER:
                return filterDataByManufacturer(deviceInfos, deviceInfoParam.getManufacturer());
            case POWER_FLAG:
                return filterDataByPowerFlag(deviceInfos, deviceInfoParam.getManufacturer());
            case JB_POWER_FLAG:
                return filterDataByJbPowerFlag(deviceInfos, deviceInfoParam.getManufacturer());
            default:
                return deviceInfos;
        }
    }


    /**
     * 根据部门id集合获取监测点信息
     *
     * @param directDeptDTO   入参deptIndex的直接子部门
     * @param deviceType
     * @param ids             直接子部门以及后代部门id集合
     * @param deviceInfoParam
     * @return
     */
    private GeneralDeviceDTO getGeneralDeviceInfo(DeptDTO directDeptDTO,
                                                  DeviceType deviceType,
                                                  List<String> ids,
                                                  DeviceInfoParam deviceInfoParam) {
        GeneralDeviceDTO generalDeviceDTO = new GeneralDeviceDTO();
        generalDeviceDTO.setIndex(directDeptDTO.getId());
        // type:部门类型 0-非自定义；1-web自定义；2-App自定义；3-web测试
        if (directDeptDTO.getType() == 0) {
            generalDeviceDTO.setName(directDeptDTO.getArea());
        } else {
            generalDeviceDTO.setName(directDeptDTO.getName());
        }
        // 根据部门ids集合查询是否绑定监测点 部门和监测点关联关系中间表：pq_dept_line 可以一对多
        List<DeptLine> deptLines = deptLineService.selectDeptBindLines(ids);
        // 返回空数据
        if (CollectionUtil.isEmpty(deptLines)) {
            return generalDeviceDTO;
        }
        // 提取该部门及其子部门所有监测点id
        List<String> lineIds = deptLines.stream().map(DeptLine::getLineId).distinct().collect(Collectors.toList());
        // 获取line详细数据 ：根据监测点id，获取所有监测点 联查 pq_line、pq_line_detail
        List<Line> lines = terminalBaseService.getLineByCondition(lineIds, deviceInfoParam);
        // 返回空数据
        if (CollectionUtil.isEmpty(lines)) {
            return generalDeviceDTO;
        }

        //1.筛选出母线id，理论上监测点的pids中第六个id为母线id 联查： pq_line t1 ,pq_voltage t2
        List<String> voltageIds = lines.stream().map(Line::getPid).distinct().collect(Collectors.toList());
        //再根据电压等级筛选合法母线信息
        List<Line> voltages = terminalBaseService.getVoltageByCondition(voltageIds, deviceInfoParam.getScale());

        //2.筛选出终端id，理论上监测点的pids中第五个id为终端id
        List<String> devIds = voltages.stream().map(Line::getPid).distinct().collect(Collectors.toList());
        // 再根据终端条件筛选合法终端信息 联查：pq_line t1,pq_device t2
        List<Line> devices = terminalBaseService.getDeviceByCondition(devIds, deviceType, deviceInfoParam);

        //3.筛选出变电站id，理论上监测点的pids中第四个id为变电站id 联查： pq_line t1 ,pq_substation t2
        List<String> subIds = devices.stream().map(Line::getPid).distinct().collect(Collectors.toList());
        List<Line> sub = terminalBaseService.getSubByCondition(subIds, new ArrayList<>());

        //筛选最终的数据
        dealDeviceData(generalDeviceDTO, lines, devices, voltages, sub);
        return generalDeviceDTO;
    }

    /**
     * 取多条件筛选后的交集索引，填充到部门统计中
     *
     * @param generalDeviceDTO 部门信息
     * @param lines            筛选后的监测点信息
     * @param devices          筛选后的终端信息
     * @param voltages         筛选后的母线信息
     */
    private void dealDeviceData(GeneralDeviceDTO generalDeviceDTO, List<Line> lines, List<Line> devices, List<Line> voltages, List<Line> sub) {
        List<String> gdIndexes = new ArrayList<>(), subIndexes = new ArrayList<>(), deviceIndexes = new ArrayList<>(), voltageIndexes = new ArrayList<>(), lineIndexes = new ArrayList<>();
        List<String> devIds = devices.stream().map(Line::getId).distinct().collect(Collectors.toList());
        List<String> volIds = voltages.stream().map(Line::getId).distinct().collect(Collectors.toList());
        List<String> subIds = sub.stream().map(Line::getId).distinct().collect(Collectors.toList());
        for (Line line : lines) {
            String[] idsArray = line.getPids().split(",");
            //监测点同时满足条件筛选后的终端、母线信息，才是最终的结果
            if (devIds.contains(idsArray[LineBaseEnum.DEVICE_LEVEL.getCode()]) &&
                    volIds.contains(idsArray[LineBaseEnum.SUB_V_LEVEL.getCode()]) &&
                    subIds.contains(idsArray[LineBaseEnum.SUB_LEVEL.getCode()])
            ) {
                gdIndexes.add(idsArray[LineBaseEnum.GD_LEVEL.getCode()]);
                subIndexes.add(idsArray[LineBaseEnum.SUB_LEVEL.getCode()]);
                deviceIndexes.add(idsArray[LineBaseEnum.DEVICE_LEVEL.getCode()]);
                voltageIndexes.add(idsArray[LineBaseEnum.SUB_V_LEVEL.getCode()]);
                lineIndexes.add(line.getId());
            }
        }
        //排重，入参到终端综合体
        generalDeviceDTO.setGdIndexes(gdIndexes.stream().distinct().collect(Collectors.toList()));
        generalDeviceDTO.setSubIndexes(subIndexes.stream().distinct().collect(Collectors.toList()));
        generalDeviceDTO.setDeviceIndexes(deviceIndexes.stream().distinct().collect(Collectors.toList()));
        generalDeviceDTO.setVoltageIndexes(voltageIndexes.stream().distinct().collect(Collectors.toList()));
        generalDeviceDTO.setLineIndexes(lineIndexes.stream().distinct().collect(Collectors.toList()));
    }

    private List<GeneralDeviceDTO> filterDataByScale(List<GeneralDeviceDTO> deviceInfos, List<SimpleDTO> scales,Integer type) {
        List<GeneralDeviceDTO> generalDeviceDTOS = new ArrayList<>();
        List<String> subIds = new ArrayList<>(), subVIds = new ArrayList<>(),lineIds = new ArrayList<>();
        for (GeneralDeviceDTO generalDeviceDTO : deviceInfos) {
            subIds.addAll(generalDeviceDTO.getSubIndexes());
            subVIds.addAll(generalDeviceDTO.getVoltageIndexes());
            lineIds.addAll(generalDeviceDTO.getLineIndexes());
        }
        //如果电压等级集合为空，则查询所有的电压等级
        if (CollectionUtil.isEmpty(scales)) {
            List<DictData> scaleDictData = dicDataFeignClient.getDicDataByTypeName(DicDataTypeEnum.DEV_VOLTAGE_STAND.getName()).getData();
            scales = scaleDictData.stream().map(dictData -> {
                SimpleDTO simpleDTO = new SimpleDTO();
                BeanUtil.copyProperties(dictData, simpleDTO);
                return simpleDTO;
            }).collect(Collectors.toList());
        }
        //监测点为空，则返回空的分类数据
        if (CollectionUtil.isEmpty(lineIds)) {
            return assembleCommonData(scales);
        }
        List<Line> lines = terminalBaseService.getLineById(lineIds);
        for (SimpleDTO simpleDTO : scales) {
         /*   if(ObjectUtil.isNull(type)){
                List<String> voltageScaleIds = terminalBaseService.getSubIdByScale(subIds, simpleDTO.getId());
                generalDeviceDTOS.add(assembleDataByLine(simpleDTO, lines, voltageScaleIds, LineBaseEnum.SUB_LEVEL.getCode()));
            }else{*/
                List<String> voltageScaleIds = terminalBaseService.getVoltageIdByScale(subVIds, simpleDTO.getId());
                generalDeviceDTOS.add(assembleDataByLine(simpleDTO, lines, voltageScaleIds, LineBaseEnum.SUB_V_LEVEL.getCode()));
          //  }
        }
        return generalDeviceDTOS;
    }


    private List<GeneralDeviceDTO> filterDataByLoadType(List<GeneralDeviceDTO> deviceInfos, List<SimpleDTO> loadType) {
        List<GeneralDeviceDTO> generalDeviceDTOS = new ArrayList<>();
        List<String> lineIds = new ArrayList<>();
        for (GeneralDeviceDTO generalDeviceDTO : deviceInfos) {
            lineIds.addAll(generalDeviceDTO.getLineIndexes());
        }
        //如果干扰源集合为空，则查询所有的电压等级
        if (CollectionUtil.isEmpty(loadType)) {
            List<DictData> scaleDictData = dicDataFeignClient.getDicDataByTypeName(DicDataTypeEnum.INTERFERENCE_SOURCE_TYPE.getName()).getData();
            loadType = scaleDictData.stream().map(dictData -> {
                SimpleDTO simpleDTO = new SimpleDTO();
                BeanUtil.copyProperties(dictData, simpleDTO);
                return simpleDTO;
            }).collect(Collectors.toList());
        }
        //监测点为空，则返回空的分类数据
        if (CollectionUtil.isEmpty(lineIds)) {
            return assembleCommonData(loadType);
        }
        List<Line> lines = terminalBaseService.getLineById(lineIds);
        for (SimpleDTO simpleDTO : loadType) {
            List<String> lineLoadTypeIds = terminalBaseService.getLineIdByLoadType(lineIds, simpleDTO.getId());
            generalDeviceDTOS.add(assembleDataByLine(simpleDTO, lines, lineLoadTypeIds, LineBaseEnum.LINE_LEVEL.getCode()));
        }
        return generalDeviceDTOS;
    }

    private List<GeneralDeviceDTO> filterDataByManufacturer(List<GeneralDeviceDTO> deviceInfos, List<SimpleDTO> manufacturer) {
        List<GeneralDeviceDTO> generalDeviceDTOS = new ArrayList<>();
        List<String> deviceIds = new ArrayList<>(), lineIds = new ArrayList<>();
        for (GeneralDeviceDTO generalDeviceDTO : deviceInfos) {
            deviceIds.addAll(generalDeviceDTO.getDeviceIndexes());
            lineIds.addAll(generalDeviceDTO.getLineIndexes());
        }
        //如果终端厂家集合为空，则查询所有的电压等级
        if (CollectionUtil.isEmpty(manufacturer)) {
            List<DictData> scaleDictData = dicDataFeignClient.getDicDataByTypeName(DicDataTypeEnum.DEV_MANUFACTURER.getName()).getData();
            manufacturer = scaleDictData.stream().map(dictData -> {
                SimpleDTO simpleDTO = new SimpleDTO();
                BeanUtil.copyProperties(dictData, simpleDTO);
                return simpleDTO;
            }).collect(Collectors.toList());
        }
        //监测点为空，则返回空的分类数据
        if (CollectionUtil.isEmpty(lineIds)) {
            return assembleCommonData(manufacturer);
        }
        List<Line> lines = terminalBaseService.getLineById(lineIds);
        for (SimpleDTO simpleDTO : manufacturer) {
            List<String> voltageScaleIds = terminalBaseService.getDeviceIdByManufacturer(deviceIds, simpleDTO.getId());
            generalDeviceDTOS.add(assembleDataByLine(simpleDTO, lines, voltageScaleIds, LineBaseEnum.DEVICE_LEVEL.getCode()));
        }
        return generalDeviceDTOS;
    }

    private List<GeneralDeviceDTO> filterDataByPowerFlag(List<GeneralDeviceDTO> deviceInfos, List<SimpleDTO> manufacturer) {
        List<GeneralDeviceDTO> generalDeviceDTOS = new ArrayList<>();
        List<String> deviceIds = deviceInfos.stream().flatMap(x -> x.getLineIndexes().stream()).collect(Collectors.toList());
        List<String> lineIds = deviceInfos.stream().flatMap(x -> x.getLineIndexes().stream()).collect(Collectors.toList());
        //监测点为空，则返回空的分类数据
        if (CollectionUtil.isEmpty(lineIds)) {
            return assembleCommonData(manufacturer);
        }
        SimpleDTO dto;
        List<Line> lines = terminalBaseService.getLineById(lineIds);
        for (int i = 0; i < 6; i++) {
            List<String> powerFlagIds = terminalBaseService.getDeviceIdByPowerFlag(deviceIds, i);
            dto = new SimpleDTO();
            PowerFlagEnum enumByCode = PowerFlagEnum.getPowerFlagEnumByCode(i);
            dto.setId(enumByCode.getCode().toString());
            dto.setName(enumByCode.getMessage());
            generalDeviceDTOS.add(assembleDataByLine(dto, lines, powerFlagIds, LineBaseEnum.LINE_LEVEL.getCode()));
        }
        return generalDeviceDTOS;
    }

    private List<GeneralDeviceDTO> filterDataByJbPowerFlag(List<GeneralDeviceDTO> deviceInfos, List<SimpleDTO> manufacturer) {
        List<GeneralDeviceDTO> generalDeviceDTOS = new ArrayList<>();
        List<String> deviceIds = deviceInfos.stream().flatMap(x -> x.getLineIndexes().stream()).collect(Collectors.toList());
        List<String> lineIds = deviceInfos.stream().flatMap(x -> x.getLineIndexes().stream()).collect(Collectors.toList());
        //监测点为空，则返回空的分类数据
        if (CollectionUtil.isEmpty(lineIds)) {
            return assembleCommonData(manufacturer);
        }
        SimpleDTO dto;
        List<Line> lines = terminalBaseService.getLineById(lineIds);
        for (int i = 0; i < 4; i++) {
            List<String> powerFlagIds = terminalBaseService.getDeviceIdByJbPowerFlag(deviceIds, i);
            dto = new SimpleDTO();
            JbPowerFlagEnum enumByCode = JbPowerFlagEnum.getPowerFlagEnumByCode(i);
            dto.setId(enumByCode.getCode().toString());
            dto.setName(enumByCode.getMessage());
            generalDeviceDTOS.add(assembleDataByLine(dto, lines, powerFlagIds, LineBaseEnum.LINE_LEVEL.getCode()));
        }
        return generalDeviceDTOS;
    }

    /**
     * 当该部门不存在监测点时，返回空的分类数据
     *
     * @param simpleDTOS 分类类别
     * @return .
     */
    private List<GeneralDeviceDTO> assembleCommonData(List<SimpleDTO> simpleDTOS) {
        return simpleDTOS.stream().map(this::assembleData).collect(Collectors.toList());
    }

    /**
     * 当该部门不存在监测点时，返回空的分类数据
     *
     * @param simpleDTO 基础数据
     * @return .
     */
    private GeneralDeviceDTO assembleData(SimpleDTO simpleDTO) {
        GeneralDeviceDTO generalDeviceDTO = new GeneralDeviceDTO();
        generalDeviceDTO.setName(simpleDTO.getName());
        generalDeviceDTO.setIndex(simpleDTO.getId());
        return generalDeviceDTO;
    }

    /**
     * 筛选对应等级的id
     *
     * @param simpleDTO 分类信息
     * @param lines     所有监测点
     * @param keyIds    待筛选的id
     * @param level     待筛选的层级
     */
    private GeneralDeviceDTO assembleDataByLine(SimpleDTO simpleDTO, List<Line> lines, List<String> keyIds, Integer level) {
        GeneralDeviceDTO generalDeviceDTO = assembleData(simpleDTO);
        if (CollectionUtil.isNotEmpty(keyIds)) {
            List<Line> tempLines = lines.stream().filter(line -> {
                String[] idsArray = line.getPids().split(",");
                if (level.equals(LineBaseEnum.LINE_LEVEL.getCode())) {
                    return keyIds.contains(line.getId());
                } else {
                    return keyIds.contains(idsArray[level]);
                }
            }).collect(Collectors.toList());
            List<String> gdIndexes = new ArrayList<>(), subIndexes = new ArrayList<>(), deviceIndexes = new ArrayList<>(), voltageIndexes = new ArrayList<>(), lineIndexes = new ArrayList<>();
            for (Line line : tempLines) {
                String[] idsArray = line.getPids().split(",");
                gdIndexes.add(idsArray[LineBaseEnum.GD_LEVEL.getCode()]);
                subIndexes.add(idsArray[LineBaseEnum.SUB_LEVEL.getCode()]);
                deviceIndexes.add(idsArray[LineBaseEnum.DEVICE_LEVEL.getCode()]);
                voltageIndexes.add(idsArray[LineBaseEnum.SUB_V_LEVEL.getCode()]);
                lineIndexes.add(line.getId());
            }
            //排重，入参到终端综合体
            generalDeviceDTO.setGdIndexes(gdIndexes.stream().distinct().collect(Collectors.toList()));
            generalDeviceDTO.setSubIndexes(subIndexes.stream().distinct().collect(Collectors.toList()));
            generalDeviceDTO.setDeviceIndexes(deviceIndexes.stream().distinct().collect(Collectors.toList()));
            generalDeviceDTO.setVoltageIndexes(voltageIndexes.stream().distinct().collect(Collectors.toList()));
            generalDeviceDTO.setLineIndexes(lineIndexes.stream().distinct().collect(Collectors.toList()));
        }
        return generalDeviceDTO;
    }

    /**
     * @Description: 按部门分类获取通讯异常设备警告
     * @Param: [deviceInfoParam]
     * @return: java.util.List<com.njcn.device.pq.pojo.vo.ExceptionDeviceInfoVO>
     * @Author: clam
     * @Date: 2022/10/14
     */
    public List<ExceptionDeviceInfoVO> getExceptionDeviceInfoAsDept(DeviceInfoParam deviceInfoParam) {

        List<ExceptionDeviceInfoVO> exceptionDeviceInfoVOS = new ArrayList<>();
        List<GeneralDeviceDTO> deviceInfoAsSubstation = getDeviceInfoAsDept(deviceInfoParam, null, Stream.of(1).collect(Collectors.toList()));
        /*获取所有设备*/
        final List<String> deviceIndexes = deviceInfoAsSubstation.stream().map(GeneralDeviceDTO::getDeviceIndexes).flatMap(Collection::stream).distinct().collect(Collectors.toList());

        QueryWrapper<Device> wrapper = new QueryWrapper<>();


        wrapper.in("Id", deviceIndexes).
                eq("Com_Flag", 0).
                eq("Dev_Model", 1).
                eq("Dev_Data_Type", 2).
                eq("Run_Flag", 0);

        List<Device> deviceList = deviceMapper.selectList(wrapper);

        List<String> filterDevIndexs = deviceList.stream().map(Device::getId).collect(Collectors.toList());

        QueryWrapper<Line> lineQueryWrapper = new QueryWrapper<>();
        lineQueryWrapper.in("Id", filterDevIndexs).
                eq("Level", 4);
        /*终端*/
        List<Line> tempDevices = lineMapper.selectList(lineQueryWrapper);


        List<String> subIndexList = tempDevices.stream().map(Line::getPid).distinct().collect(Collectors.toList());
        /*变电站*/
        QueryWrapper<Line> substationQueryWrapper = new QueryWrapper<>();
        substationQueryWrapper.in("Id", subIndexList).
                eq("Level", 3);
        List<Line> tempSubstations = lineMapper.selectList(substationQueryWrapper);
        /* todo 设置警告类型*/
        DictData data = dicDataFeignClient.getDicDataByCode(DicDataEnum.COMM_ERR.getCode()).getData();
        deviceList.forEach(device -> {

            ExceptionDeviceInfoVO exceptionDeviceInfoVO = new ExceptionDeviceInfoVO();

            exceptionDeviceInfoVO.setIp(device.getIp());
            exceptionDeviceInfoVO.setUpdateTime(device.getUpdateTime());
            exceptionDeviceInfoVO.setDevIndex(device.getId());

            Line tempdevice = tempDevices.stream().filter(temp -> Objects.equals(temp.getId(), device.getId())).collect(Collectors.toList()).get(0);

            exceptionDeviceInfoVO.setDevName(tempdevice.getName());
            exceptionDeviceInfoVO.setSubIndex(tempdevice.getPid());
            Line substation = tempSubstations.stream().filter(temp -> Objects.equals(temp.getId(), tempdevice.getPid())).collect(Collectors.toList()).get(0);
            exceptionDeviceInfoVO.setSubName(substation.getName());


            exceptionDeviceInfoVO.setWarningId(data.getId());
            exceptionDeviceInfoVO.setWarningType(data.getName());
            String exceptionDescription = String.format("%s变电站,%s终端于%s通讯中断", substation.getName(), tempdevice.getName(), device.getUpdateTime());
            exceptionDeviceInfoVO.setExceptionDescription(exceptionDescription);
            exceptionDeviceInfoVOS.add(exceptionDeviceInfoVO);
        });


        return exceptionDeviceInfoVOS;
    }

    /**
     * @Description: getDeptDeviceDetail
     * @Param: [deviceInfoParam]
     * @return: com.njcn.device.pq.pojo.vo.DeptDeviceDetailVO
     * @Author: clam
     * @Date: 2022/11/4
     */
    public DeptDeviceDetailVO getDeptDeviceDetail(DeviceInfoParam deviceInfoParam) {


        DeptDeviceDetailVO deptDeviceDetailVO = new DeptDeviceDetailVO();
        /*总数*/
        List<GeneralDeviceDTO> deptDeviceInfos = this.getDeviceInfoAsDept(deviceInfoParam, Stream.of(0, 1).collect(Collectors.toList()), Stream.of(1).collect(Collectors.toList()));
        List<String> DeviceIds = deptDeviceInfos.stream().map(GeneralDeviceDTO::getDeviceIndexes).flatMap(Collection::stream).collect(Collectors.toList());
        Integer deviceCount = DeviceIds.size();

        /*实际运行*/
        QueryWrapper<Device> query = new QueryWrapper<>();
        query.in("Id", DeviceIds).
                eq("Run_Flag", 0).eq("Com_Flag", 1);
        Integer runDeviceCount = deviceMapper.selectCount(query);
        BigDecimal rate = BigDecimal.valueOf(runDeviceCount).divide(BigDecimal.valueOf(deviceCount), 4, BigDecimal.ROUND_HALF_UP);
        deptDeviceDetailVO.setDeviceCount(deviceCount);
        deptDeviceDetailVO.setRunDeviceCount(runDeviceCount);
        deptDeviceDetailVO.setOnLineRate(rate);
        return deptDeviceDetailVO;

    }

    public DeptSubstationDetailVO getDeptSubstationDetail(DeviceInfoParam deviceInfoParam) {

        DeptSubstationDetailVO deptSubstationDetailVO = new DeptSubstationDetailVO();

        List<GeneralDeviceDTO> deptDeviceInfos = this.getDeviceInfoAsDept(deviceInfoParam, Stream.of(0, 1).collect(Collectors.toList()), Stream.of(1).collect(Collectors.toList()));

        List<String> subIds = deptDeviceInfos.stream().map(GeneralDeviceDTO::getSubIndexes).flatMap(Collection::stream).collect(Collectors.toList());
        Integer substationCount = subIds.size();

        Integer count = lineMapper.queryOnlineSubstaion(subIds);
        deptSubstationDetailVO.setSubstationCount(substationCount);
        deptSubstationDetailVO.setRunsubstationCount(count);
        BigDecimal rate = BigDecimal.valueOf(count).divide(BigDecimal.valueOf(substationCount), 4, BigDecimal.ROUND_HALF_UP);
        deptSubstationDetailVO.setOnLineRate(rate);

        return deptSubstationDetailVO;


    }


    /**
     * @param deptId   部门id
     * @param runFlag  设备运行状态 0：投运 1.热备用 2.停运
     * @param dataType 系统 0：暂态系统；1：稳态系统；2：两个系统
     * @author cdf
     * @date 2023/7/20
     */
    public List<String> deptGetRunLine(String deptId, List<Integer> runFlag, List<Integer> dataType) {
        List<DeptDTO> deptDTOList = deptFeignClient.getDeptDescendantIndexes(deptId, Stream.of(0, 1).collect(Collectors.toList())).getData();
        if (CollUtil.isNotEmpty(deptDTOList)) {
            List<String> deptIds = deptDTOList.stream().map(DeptDTO::getId).distinct().collect(Collectors.toList());
            return deptLineService.getLineByDeptIds(deptIds, null, runFlag, dataType, null);
        }
        return new ArrayList<>();
    }


    /**
     * @param deptId 部门id
     * @author cdf
     * @date 2023/7/20
     */
    public List<String> deptGetRunDev(String deptId) {
        List<String> runLineIds = this.deptGetRunLine(deptId, Stream.of(0).collect(Collectors.toList()), Stream.of(0, 2).collect(Collectors.toList()));
        List<Line> lines = lineMapper.selectList(new LambdaQueryWrapper<Line>()
                .select(Line::getPids)
                .in(Line::getId, runLineIds)
        );
        if (CollUtil.isNotEmpty(lines)) {
            return lines.stream().map(line -> {
                String[] idsArray = line.getPids().split(",");
                return idsArray[4];
            }).distinct().collect(Collectors.toList());
        }
        return new ArrayList<>();
    }

    public List<DevDetail> getDevInfoByIds(List<String> devIds) {
        List<DictData> gradeType = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.DEV_GRADE.getCode()).getData();
        Map<String, Integer> gradeMap = gradeType.stream().collect(Collectors.toMap(DictData::getId, DictData::getAlgoDescribe));

        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<DevDetail> devDetails = deviceMapper.selectDevByIds(devIds);
        for (DevDetail devDetail : devDetails) {
            //终端等级
            if (gradeMap.containsKey(devDetail.getLineGrade())) {
                devDetail.setLineGrade(String.valueOf(gradeMap.get(devDetail.getLineGrade())));
            }
            //部门
            if (deptMap.containsKey(devDetail.getDeptName())) {
                devDetail.setDeptName(deptMap.get(devDetail.getDeptName()));
            }
            //终端厂商
            if (manufacturerMap.containsKey(devDetail.getManufacturer())) {
                devDetail.setManufacturer(manufacturerMap.get(devDetail.getManufacturer()));
            }
        }
        return devDetails;
    }

    public List<TopMsgPO> getTopMsgInfoByIds(OnlineRateParam param) {
        return topMsgMapper.selectByIds(param);
    }
}
