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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.njcn.common.pojo.enums.common.ServerEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.utils.EnumUtils;
import com.njcn.device.biz.pojo.dto.*;
import com.njcn.device.biz.pojo.param.DeptGetLineParam;
import com.njcn.device.biz.pojo.param.SubstationParam;
import com.njcn.device.line.mapper.DeptLineMapper;
import com.njcn.device.line.mapper.LineMapper;
import com.njcn.device.line.service.DeptLineService;
import com.njcn.device.biz.pojo.dto.MonitorCommLedgerInfoDTO;
import com.njcn.device.pq.pojo.param.dataClean.MonitorBaseParam;
import com.njcn.device.pq.service.CommTerminalService;
import com.njcn.redis.utils.RedisUtil;
import com.njcn.user.api.DeptFeignClient;
import com.njcn.user.pojo.dto.DeptDTO;
import com.njcn.user.pojo.po.Dept;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

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

import static com.njcn.device.pq.enums.LineBaseEnum.DEV_DATA_TYPE_ALL;

/**
 * pqs
 *
 * @author cdf
 * @date 2023/5/10
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class CommTerminalServiceImpl implements CommTerminalService {

    //redis前缀
    private final String commTerminal = "commTerminal#";

    private final DeptLineService deptLineService;

    private final DeptFeignClient deptFeignClient;

    private final RedisUtil redisUtil;

    private final LineMapper lineMapper;
    private final DeptLineMapper deptLineMapper;


    /**
     * 基础获取单位信息
     *
     * @author cdf
     * @date 2023/5/10
     */
    @Override
    public List<DeptGetBase> getDeptChildrenByParent(DeptGetLineParam deptGetLineParam) {
        List<DeptGetBase> result = new ArrayList<>();
        List<DeptDTO> deptDTOList = deptFeignClient.getDeptDescendantIndexes(deptGetLineParam.getDeptId(), Stream.of(0, 1).collect(Collectors.toList())).getData();
        deptDTOList.forEach(it -> {
            DeptGetBase deptGetBase = new DeptGetBase();
            deptGetBase.setUnitId(it.getId());
            deptGetBase.setUnitName(it.getName());
            deptGetBase.setDeptLevel(getDeptLevel(it.getPids()));
            List<String> deptChildren = deptDTOList.stream().filter(deptDTO -> deptDTO.getPids().contains(it.getId())).map(DeptDTO::getId).collect(Collectors.toList());
            deptChildren.add(it.getId());
            deptGetBase.setUnitChildrenList(deptChildren);
            result.add(deptGetBase);
        });
        redisUtil.saveByKey(commTerminal + deptGetLineParam.getDeptId(), result);
        return result;
    }


    @Override
    public List<DeptGetChildrenMoreDTO> deptGetLine(DeptGetLineParam deptGetLineParam) {
        List<DeptGetChildrenMoreDTO> result = new ArrayList<>();
        List<DeptGetBase> temDept = getDeptChildrenByParent(deptGetLineParam);
        Map<String, String> deptMap = temDept.stream().collect(Collectors.toMap(DeptGetBase::getUnitId, DeptGetBase::getUnitName));
        Map<String, List<LineDevGetDTO>> map = deptLineService.lineDevGet(filterDataTypeNew(deptGetLineParam.getServerName()),
                1, deptGetLineParam.getLineRunFlag());
        temDept.forEach(item -> {
            DeptGetChildrenMoreDTO deptGetChildrenMoreDTO = new DeptGetChildrenMoreDTO();
            deptGetChildrenMoreDTO.setUnitId(item.getUnitId());
            deptGetChildrenMoreDTO.setUnitName(item.getUnitName());
            deptGetChildrenMoreDTO.setUnitChildrenList(item.getUnitChildrenList());
            deptGetChildrenMoreDTO.setDeptLevel(item.getDeptLevel());
            List<String> deptIds = item.getUnitChildrenList();
            if (CollectionUtil.isNotEmpty(deptIds)) {
                List<LineDevGetDTO> lineList = new ArrayList<>();
                deptIds.forEach(i -> {
                    if (map.containsKey(i)) {
                        map.get(i).forEach(x -> {
                            if (deptMap.containsKey(x.getUnitId())) {
                                x.setUnitName(deptMap.get(x.getUnitId()));
                            }
                        });
                        lineList.addAll(map.get(i));
                    }
                });

                //去重
                ArrayList<LineDevGetDTO> collect = lineList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(
                        Comparator.comparing(LineDevGetDTO::getPointId)
                )), ArrayList::new));

                deptGetChildrenMoreDTO.setLineBaseList(collect);
            }
            result.add(deptGetChildrenMoreDTO);
        });
        return result;
    }

    @Override
    public List<MonitorCommLedgerInfoDTO> deptGetLineInfo(DeptGetLineParam deptGetLineParam) {
        List<String> deptIds = deptFeignClient.getDepSonIdtByDeptId(deptGetLineParam.getDeptId()).getData();
        List<MonitorCommLedgerInfoDTO> ledgerList = deptLineMapper.getMonitorByDeptIds(Stream.of(DEV_DATA_TYPE_ALL.getCode()).collect(Collectors.toList()),deptIds);
        return ledgerList;
    }

    @Override
    public List<DeptGetChildrenMoreDTO> deptGetAllLine(DeptGetLineParam deptGetLineParam) {
        List<DeptGetChildrenMoreDTO> result = new ArrayList<>();
        List<DeptGetBase> temDept = getDeptChildrenByParent(deptGetLineParam);
        Map<String, String> deptMap = temDept.stream().collect(Collectors.toMap(DeptGetBase::getUnitId, DeptGetBase::getUnitName));
        Map<String, List<LineDevGetDTO>> map = deptLineService.lineDevAllGet(filterDataTypeNew(deptGetLineParam.getServerName()),
                1, deptGetLineParam.getLineRunFlag(), deptGetLineParam.getIsUpToGrid());
        temDept.forEach(item -> {
            DeptGetChildrenMoreDTO deptGetChildrenMoreDTO = new DeptGetChildrenMoreDTO();
            deptGetChildrenMoreDTO.setUnitId(item.getUnitId());
            deptGetChildrenMoreDTO.setUnitName(item.getUnitName());
            deptGetChildrenMoreDTO.setUnitChildrenList(item.getUnitChildrenList());
            deptGetChildrenMoreDTO.setDeptLevel(item.getDeptLevel());
            List<String> deptIds = item.getUnitChildrenList();
            if (CollectionUtil.isNotEmpty(deptIds)) {
                List<LineDevGetDTO> lineList = new ArrayList<>();
                deptIds.forEach(i -> {
                    if (map.containsKey(i)) {
                        map.get(i).forEach(x -> {
                            if (deptMap.containsKey(x.getUnitId())) {
                                x.setUnitName(deptMap.get(x.getUnitId()));
                            }
                        });
                        lineList.addAll(map.get(i));
                    }
                });

                //去重
                ArrayList<LineDevGetDTO> collect = lineList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(
                        Comparator.comparing(LineDevGetDTO::getPointId)
                )), ArrayList::new));

                deptGetChildrenMoreDTO.setLineBaseList(collect);
            }
            result.add(deptGetChildrenMoreDTO);
        });
        return result;
    }

    @Override
    public List<LineDevGetDTO> deptGetLineByIdList(List<String> monitorIds) {
        return lineMapper.getMonitorListDetail(monitorIds);
    }


    @Override
    public List<DeptGetSubStationDTO> deptSubStation(DeptGetLineParam deptGetLineParam) {
        List<DeptGetSubStationDTO> result = new ArrayList<>();
        List<DeptGetBase> temDept = getDeptChildrenByParent(deptGetLineParam);
        Map<String, List<TerminalGetBase>> map = deptLineService.orgSubStationGet(filterDataTypeNew(deptGetLineParam.getServerName()));
        temDept.forEach(item -> {
            DeptGetSubStationDTO deptGetSubStationDTO = new DeptGetSubStationDTO();
            deptGetSubStationDTO.setUnitId(item.getUnitId());
            deptGetSubStationDTO.setUnitName(item.getUnitName());
            deptGetSubStationDTO.setUnitChildrenList(item.getUnitChildrenList());
            deptGetSubStationDTO.setDeptLevel(item.getDeptLevel());
            List<String> deptIds = item.getUnitChildrenList();
            if (CollectionUtil.isNotEmpty(deptIds)) {
                List<String> subList = new ArrayList<>();
                List<String> lineList = new ArrayList<>();
                deptIds.forEach(i -> {
                    if (map.containsKey(i)) {
                        subList.addAll(map.get(i).stream().map(TerminalGetBase::getLedgerId).distinct().collect(Collectors.toList()));
                        subList.addAll(map.get(i).stream().filter(x -> StrUtil.isNotBlank(x.getObjId())).map(TerminalGetBase::getObjId).distinct().collect(Collectors.toList()));
                        lineList.addAll(map.get(i).stream().map(TerminalGetBase::getLineId).distinct().collect(Collectors.toList()));
                    }
                });
                deptGetSubStationDTO.setStationIds(subList);
                deptGetSubStationDTO.setStationAndMonitorIDs(lineList);
            }
            result.add(deptGetSubStationDTO);
        });
        return result;
    }

    @Override
    public List<DeptGetBusBarDTO> deptBusBar(DeptGetLineParam deptGetLineParam) {
        List<DeptGetBusBarDTO> result = new ArrayList<>();
        List<DeptGetBase> temDept = getDeptChildrenByParent(deptGetLineParam);
        Map<String, List<LineDevGetDTO>> map = deptLineService.lineDevGet(filterDataTypeNew(deptGetLineParam.getServerName()), 2, deptGetLineParam.getLineRunFlag());
        temDept.forEach(item -> {
            DeptGetBusBarDTO deptGetBusBarDTO = new DeptGetBusBarDTO();
            deptGetBusBarDTO.setUnitId(item.getUnitId());
            deptGetBusBarDTO.setUnitName(item.getUnitName());
            deptGetBusBarDTO.setUnitChildrenList(item.getUnitChildrenList());
            List<String> deptIds = item.getUnitChildrenList();
            if (CollectionUtil.isNotEmpty(deptIds)) {
                List<String> busBarList = new ArrayList<>();
                List<String> lineList = new ArrayList<>();
                deptIds.forEach(i -> {
                    if (map.containsKey(i)) {
                        busBarList.addAll(map.get(i).stream().map(LineDevGetDTO::getPointId).collect(Collectors.toList()));
                        lineList.addAll(map.get(i).stream().map(LineDevGetDTO::getDevId).collect(Collectors.toList()));
                    }
                });
                deptGetBusBarDTO.setBusBarIds(busBarList);
                deptGetBusBarDTO.setBusBarAndMonitorIDs(lineList);
            }
            result.add(deptGetBusBarDTO);
        });
        return result;
    }

    @Override
    public List<DeptGetDeviceDTO> deptGetDevice(DeptGetLineParam deptGetLineParam, Integer type) {
        List<DeptGetDeviceDTO> result = new ArrayList<>();
        List<DeptGetBase> temDept = getDeptChildrenByParent(deptGetLineParam);
        Map<String, List<LineDevGetDTO>> map = deptLineService.lineDevGet(filterDataTypeNew(deptGetLineParam.getServerName()), type, deptGetLineParam.getLineRunFlag());
        temDept.forEach(item -> {
            DeptGetDeviceDTO deptGetDeviceDTO = new DeptGetDeviceDTO();
            deptGetDeviceDTO.setUnitId(item.getUnitId());
            deptGetDeviceDTO.setUnitName(item.getUnitName());
            deptGetDeviceDTO.setUnitChildrenList(item.getUnitChildrenList());
            List<String> deptIds = item.getUnitChildrenList();
            if (CollectionUtil.isNotEmpty(deptIds)) {
                List<LineDevGetDTO> devGetDTOList = new ArrayList<>();
                deptIds.forEach(i -> {
                    if (map.containsKey(i)) {
                        devGetDTOList.addAll(map.get(i));
                    }
                });
                deptGetDeviceDTO.setDeviceList(devGetDTOList);
            }
            result.add(deptGetDeviceDTO);
        });
        return result;
    }

    @Override
    public LineDevGetBandDTO substationGetLine(String substationId) {
        LineDevGetBandDTO lineDevGetBandDTO = new LineDevGetBandDTO();
        List<LineDevGetDTO> subList = lineMapper.getLineBySubStation(substationId);
        lineDevGetBandDTO.setZwList(subList);
        return lineDevGetBandDTO;
    }

    @Override
    public Map<String, String> getCustomDetailByLineId(String id) {
        return lineMapper.getCustomDetailByLineId(id);
    }

    @Override
    public List<DeptGetSubStationDTO.Info> deptSubStationInfo(DeptGetLineParam deptGetLineParam) {
        List<DeptGetSubStationDTO.Info> result = new ArrayList<>();
        List<DeptGetBase> temDept = getDeptChildrenByParent(deptGetLineParam);
        List<TerminalGetBase.Extend> anExtends = deptLineService.orgSubStationInfoGet(filterDataTypeNew(deptGetLineParam.getServerName()),
                                                                                        deptGetLineParam.getPowerFlag(),
                                                                                        deptGetLineParam.getLineRunFlag(),
                                                                                        deptGetLineParam.getIsUpToGrid(),
                                                                                        deptGetLineParam.getSearchValue());
        Map<String, List<TerminalGetBase.Extend>> orgSub = anExtends.stream().collect(Collectors.groupingBy(TerminalGetBase::getUnitId));
        Map<String, String> deptNameMap = temDept.stream().collect(Collectors.toMap(DeptGetBase::getUnitId, DeptGetBase::getUnitName));
        temDept.forEach(item -> {
            DeptGetSubStationDTO.Info deptGetSubStationDTO = new DeptGetSubStationDTO.Info();
            deptGetSubStationDTO.setUnitId(item.getUnitId());
            deptGetSubStationDTO.setUnitName(item.getUnitName());
            deptGetSubStationDTO.setUnitChildrenList(item.getUnitChildrenList());
            deptGetSubStationDTO.setDeptLevel(item.getDeptLevel());
            List<String> deptIds = item.getUnitChildrenList();
            if (CollectionUtil.isNotEmpty(deptIds)) {
                List<SubGetBase> subList = new ArrayList<>();
                SubGetBase subGetBase;
                for (String deptId : deptIds) {
                    if (orgSub.containsKey(deptId)) {
                        //获取部门下变电信息
                        List<TerminalGetBase.Extend> sub = orgSub.get(deptId);
                        Map<String, List<TerminalGetBase.Extend>> subMap = sub.stream()
                                .collect(Collectors.groupingBy(x -> x.getLedgerId() + "_" + x.getSubName() + "_" + x.getVoltageLevel()));
                        for (Map.Entry<String, List<TerminalGetBase.Extend>> stringListEntry : subMap.entrySet()) {
                            String[] split = stringListEntry.getKey().split("_");
                            subGetBase = new SubGetBase();
                            subGetBase.setId(split[0]);
                            subGetBase.setName(split[1]);
                            subGetBase.setVoltageLevel(split[2]);
                            subGetBase.setOrgId(deptId);
                            if (deptNameMap.containsKey(deptId)) {
                                subGetBase.setOrgName(deptNameMap.get(deptId));
                            }
                            //国网监测点
                            List<String> gwMonitor = stringListEntry.getValue().stream().filter(x -> 1 == x.getMonitorFlag())
                                    .map(TerminalGetBase.Extend::getLineId)
                                    .distinct().collect(Collectors.toList());
                            subGetBase.setIsUpToGrid(gwMonitor.size() > 0 ? 1 : 0);
                            List<String> monitorIds = stringListEntry.getValue().stream().map(TerminalGetBase.Extend::getLineId).distinct().collect(Collectors.toList());
                            subGetBase.setUnitChildrenList(monitorIds);
                            subGetBase.setGwUnitChildrenList(gwMonitor);
                            subList.add(subGetBase);
                        }
                    }

                }
                deptGetSubStationDTO.setStationIds(subList);
            }
            result.add(deptGetSubStationDTO);
        });
        return result;
    }

    @Override
    public List<SubGetBase> tagOrIdGetSub(SubstationParam substationParam) {
        List<SubGetBase> subStationList = deptLineService.getSubStationList(substationParam);
        if (CollUtil.isNotEmpty(subStationList)) {
            List<String> ids = subStationList.stream().map(SubGetBase::getOrgId).collect(Collectors.toList());
            List<Dept> data = deptFeignClient.getDeptInfoListByIds(ids).getData();
            Map<String, String> deptMap = data.stream().collect(Collectors.toMap(Dept::getId, Dept::getName));
            subStationList.stream().forEach(x -> {
                if (deptMap.containsKey(x.getOrgId())) {
                    x.setOrgName(deptMap.get(x.getOrgId()));
                }
            });
        }
        return subStationList;
    }

    @Override
    public List<String> getRunMonitorByDept(MonitorBaseParam monitorBaseParam) {
        List<String> ids = deptFeignClient.getDepSonIdtByDeptId(monitorBaseParam.getDeptId()).getData();
        List<String> monitorIds = deptLineService.getLineByDeptIds(ids, monitorBaseParam.getManufacturer(),
                ObjectUtil.isNotNull(monitorBaseParam.getLineRunFlag())? Arrays.asList(monitorBaseParam.getLineRunFlag()):null,
                Stream.of(0, 1, 2).collect(Collectors.toList()), monitorBaseParam.getObjType());
        return monitorIds;
    }


    private List<Integer> filterDataTypeNew(String serverName) {
        List<Integer> devType = new ArrayList<>();
        devType.add(2);
        ServerEnum serverEnum = EnumUtils.getServerEnumByName(serverName);
        switch (serverEnum) {
            case EVENT:
                devType.add(0);
                break;
            case HARMONIC:
                devType.add(1);
                break;
            default:
                devType.add(0);
                devType.add(1);
                break;
        }
        return devType;
    }












    /*-------------------------------------------------------------------------------------*/

    /**
     * @author cdf
     * @date 2023/5/10
     */
    @Override
    public List<DeptGetChildrenDTO> deptGetLineList(DeptGetLineParam deptGetLineParam) {
        List<DeptGetChildrenDTO> all = new ArrayList<>();
        List<DeptDTO> deptDTOList = deptFeignClient.getDeptDescendantIndexes(deptGetLineParam.getDeptId(), Stream.of(0, 1).collect(Collectors.toList())).getData();
        getAllChildren(deptGetLineParam.getDeptId(), deptDTOList, all);
        Map<String, List<String>> map = deptLineService.getLineByDeptRelation(filterDataType(deptGetLineParam.getServerName()));
        all.forEach(item -> {
            List<String> itemDeptChildren = item.getDeptChildren();
            if (CollectionUtil.isNotEmpty(itemDeptChildren)) {
                List<String> lineIds = new ArrayList<>();
                itemDeptChildren.forEach(i -> {
                    if (map.containsKey(i)) {
                        lineIds.addAll(map.get(i));
                    }
                });
                item.setLineIds(lineIds);
            }
        });
        return all;
    }

    /**
     * 筛选数据类型
     */
    private Integer filterDataType(String serverName) {
        ServerEnum serverEnum = EnumUtils.getServerEnumByName(serverName);
        switch (serverEnum) {
            case EVENT:
                return 0;
            case HARMONIC:
                return 1;
            default:
                throw new BusinessException(CommonResponseEnum.INVALID_PARAMETER);
        }

    }


    /**
     * 获取指定部门所有子孙部门id
     *
     * @author cdf
     * @date 2023/4/24
     */
    private void getAllChildren(String deptId, List<DeptDTO> deptAllList, List<DeptGetChildrenDTO> res) {
        deptAllList.stream().filter(item -> item.getPid().equals(deptId)).forEach(it -> {
            List<String> deptChildren = deptAllList.stream().filter(deptDTO -> deptDTO.getPids().contains(it.getId())).map(DeptDTO::getId).collect(Collectors.toList());
            deptChildren.add(it.getId());
            DeptGetChildrenDTO generalDeviceDTO = new DeptGetChildrenDTO();
            generalDeviceDTO.setDeptId(it.getId());
            generalDeviceDTO.setDeptName(it.getName());
            generalDeviceDTO.setDeptChildren(deptChildren);
            res.add(generalDeviceDTO);
            getAllChildren(it.getId(), deptAllList, res);
        });
    }

    private Integer getDeptLevel(String pids) {
        List<String> list = Arrays.stream(pids.split(",")).map(String::trim).collect(Collectors.toList());
        return list.size();
    }

}
