package com.njcn.csdevice.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.njcn.access.utils.ChannelObjectUtil;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.csdevice.param.IcdBzParam;
import com.njcn.csdevice.param.IcdLedgerParam;
import com.njcn.csdevice.param.IcdParam;
import com.njcn.csdevice.pojo.param.AppProjectAddParm;
import com.njcn.csdevice.pojo.param.CsEquipmentDeliveryAddParm;
import com.njcn.csdevice.pojo.param.CsLineParam;
import com.njcn.csdevice.pojo.po.*;
import com.njcn.csdevice.pojo.vo.CldLedgerVo;
import com.njcn.csdevice.pojo.vo.DeviceInfo;
import com.njcn.csdevice.pojo.vo.ProjectVO;
import com.njcn.csdevice.service.*;
import com.njcn.csharmonic.api.EventFeignClient;
import com.njcn.csharmonic.pojo.po.CsEventPO;
import com.njcn.device.biz.mapper.OverLimitWlMapper;
import com.njcn.device.biz.pojo.po.Overlimit;
import com.njcn.device.biz.utils.COverlimitUtil;
import com.njcn.mq.message.BZEventMessage;
import com.njcn.mq.template.BZEventMessageTemplate;
import com.njcn.redis.pojo.enums.AppRedisKey;
import com.njcn.redis.utils.RedisUtil;
import com.njcn.system.api.DictTreeFeignClient;
import com.njcn.system.enums.DicDataEnum;
import com.njcn.system.pojo.po.SysDicTreePO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
class IcdServiceImpl implements IcdService {

    private final INodeService nodeService;
    private final ChannelObjectUtil channelObjectUtil;
    private final RedisUtil redisUtil;
    private final CsEngineeringService csEngineeringService;
    private final AppProjectService appProjectService;
    private final CsEquipmentDeliveryService csEquipmentDeliveryService;
    private final CsLinePOService csLinePOService;
    private final ICsLedgerService csLedgerService;
    private final BZEventMessageTemplate bzEventMessageTemplate;
    private final EventFeignClient eventFeignClient;
    private final ICsTerminalLogsService csTerminalLogsService;
    private final ICsTerminalReplyService csTerminalReplyService;
    private final OverLimitWlMapper overLimitWlMapper;
    private final DictTreeFeignClient dictTreeFeignClient;
    private final DateTimeFormatter microsecondFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS");
    private final AppTopologyDiagramService appTopologyDiagramService;

    @Override
    public List<DeviceInfo> getLedgerInfo(IcdParam param) {
        //获取装置型号
        Map<String,SysDicTreePO> sysDicTreeMap = new HashMap<>();
        List<SysDicTreePO> dictTreeList = channelObjectUtil.objectToList(redisUtil.getObjectByKey(AppRedisKey.DICT_TREE),SysDicTreePO.class);
        SysDicTreePO po = dictTreeList.stream().filter(item -> Objects.equals(item.getCode(), DicDataEnum.DEV_CLD.getCode())).findFirst().orElse(null);
        if (ObjectUtil.isNotNull(po)) {
            String id = po.getId();
            List<SysDicTreePO> cldDevType = dictTreeList.stream().filter(item->Objects.equals(item.getPid(),id)).collect(Collectors.toList());
            sysDicTreeMap = cldDevType.stream().collect(Collectors.toMap(SysDicTreePO::getId, Function.identity()));
        }

        List<DeviceInfo> result = new ArrayList<>();
        //根据ip获取前置机信息
        Node node = nodeService.getNodeById(param.getId());
        if (ObjectUtil.isNotNull(node)) {
            //根据前置机ip获取装置信息
            List<CsEquipmentDeliveryPO> poList = csEquipmentDeliveryService.getCldDevByIp(node.getId(),param.getRunFlag());
            if (CollectionUtil.isNotEmpty(poList)) {
                //获取监测点集合
                List<String> devList = poList.stream().map(CsEquipmentDeliveryPO::getId).collect(Collectors.toList());
                List<CsLinePO> lineList = csLinePOService.getLinesByDevList(devList);
                Map<String,List<CsLinePO>> lineMap = lineList.stream().collect(Collectors.groupingBy(CsLinePO::getDeviceId));
                //组装返回结构体
                Map<String, SysDicTreePO> finalSysDicTreeMap = sysDicTreeMap;
                poList.forEach(dev->{
                    DeviceInfo detail = new DeviceInfo();
                    detail.setId(dev.getId());
                    detail.setName(dev.getName());
                    detail.setIp(dev.getMac());
                    detail.setDevType(Objects.isNull(finalSysDicTreeMap.get(dev.getDevModel())) ? "/":finalSysDicTreeMap.get(dev.getDevModel()).getCode());
                    detail.setNode(dev.getNodeProcess());
                    detail.setMaxProcessNum(node.getMaxProcessNum());
                    detail.setDevLogLevel(dev.getDevLogLevel());

                    // 只获取当前设备的监测点数据
                    List<CsLinePO> lines = lineMap.get(dev.getId());
                    if (CollectionUtil.isNotEmpty(lines)) {
                        List<DeviceInfo.MonitorInfo> monitorInfos = new ArrayList<>();
                        lines.forEach(line->{
                            DeviceInfo.MonitorInfo monitorInfo = new DeviceInfo.MonitorInfo();
                            monitorInfo.setDeviceId(dev.getId());
                            monitorInfo.setId(line.getLineId());
                            monitorInfo.setName(line.getName());
                            monitorInfo.setLineNo(String.valueOf(line.getLineNo()));
                            monitorInfo.setVoltageLevel(line.getVolGrade() + "kV");
                            monitorInfo.setStatus(line.getRunStatus());
                            monitorInfo.setPtType(String.valueOf(line.getConType()));
                            monitorInfo.setPt1(line.getPtRatio());
                            monitorInfo.setPt2(line.getPt2Ratio());
                            monitorInfo.setCt1(line.getCtRatio());
                            monitorInfo.setCt2(line.getCt2Ratio());
                            monitorInfo.setLineLogLevel(line.getLineLogLevel());
                            monitorInfos.add(monitorInfo);
                        });
                        detail.setMonitorData(monitorInfos);
                    }
                    result.add(detail);
                });
            }
        }
        return result;
    }

    @Override
    @DSTransactional
    public void addLedgerInfo(IcdLedgerParam param) {
        // 第一种：全流程创建
        if (isAllIndicesNull(param)) {
            handleFullProcessCreation(param);
        }
        // 第二种：从工程创建
        else if (ObjectUtil.isNotNull(param.getEngineeringIndex())) {
            handleFromEngineeringCreation(param);
        }
        // 第三种：从项目创建
        else if (ObjectUtil.isNotNull(param.getProjectIndex())) {
            handleFromProjectCreation(param);
        }
        // 第四种：从设备创建
        else if (ObjectUtil.isNotNull(param.getDevIndex())) {
            handleFromDeviceCreation(param);
        }
    }

    @Override
    public CldLedgerVo getLedgerById(String id) {
        CldLedgerVo vo = new CldLedgerVo();
        CsLedger csLedger = csLedgerService.findDataById(id);
        if (ObjectUtil.isNull(csLedger)) {
            return vo;
        }
        Integer level = csLedger.getLevel();
        String[] pids = csLedger.getPids().split(StrUtil.COMMA);
        // 设置工程信息（所有级别都需要）
        setEngineeringInfo(vo, level, pids, id);
        // 根据级别设置不同的业务数据
        switch (level) {
            case 0:
                handleLevel0(vo, id);
                break;
            case 1:
                handleLevel1(vo, id, pids);
                break;
            case 2:
                handleLevel2(vo, id, pids);
                break;
            case 3:
                handleLevel3(vo, id, pids);
                break;
            default:
                log.warn("Unknown ledger level: {}", level);
        }
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bzFileByEventId(String eventId) {
        CsEventPO po = eventFeignClient.queryById(eventId).getData();
        if (ObjectUtil.isNull(po)) {
            throw new BusinessException("事件缺失");
        }
        //获取设备信息
        CsEquipmentDeliveryPO dev = csEquipmentDeliveryService.getDevByLineId(po.getLineId());
        BZEventMessage.Event file = new BZEventMessage.Event();
        file.setGuid(po.getId());
        file.setTerminalId(po.getDeviceId());
        file.setMonitorIdList(Collections.singletonList(po.getLineId()));
        file.setTimeInterval(Collections.singletonList(po.getStartTime().format(microsecondFormatter)));
        file.setDataType(2);
        //记录发送日志
        CsTerminalLogs csTerminalLogs = new CsTerminalLogs();
        csTerminalLogs.setId(po.getId());
        csTerminalLogs.setDeviceId(dev.getId());
        csTerminalLogs.setLineId(po.getLineId());
        csTerminalLogs.setOperateType(3);
        csTerminalLogs.setNodeId(dev.getNodeId());
        csTerminalLogs.setNodeProcess(dev.getNodeProcess());
        csTerminalLogs.setIsPush(1);
        csTerminalLogsService.saveOrUpdate(csTerminalLogs);
        //记录响应日志
        CsTerminalReply csTerminalReply = new CsTerminalReply();
        csTerminalReply.setId(IdUtil.simpleUUID());
        csTerminalReply.setReplyId(po.getId());
        csTerminalReply.setNodeId(dev.getNodeId());
        csTerminalReply.setProcessNo(dev.getNodeProcess());
        csTerminalReply.setDeviceId(dev.getId());
        csTerminalReply.setLineId(po.getLineId());
        csTerminalReply.setIsReceived(0);
        csTerminalReply.setCode("oneFile");
        csTerminalReplyService.saveOrUpdate(csTerminalReply);
        //发送消息
        bzEventMessageTemplate.sendMember(Collections.singletonList(file),dev.getNodeId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bzEvent(IcdBzParam param) {
        // 参数校验
        if (StrUtil.isBlank(param.getStartTime()) || StrUtil.isBlank(param.getEndTime())) {
            throw new BusinessException("开始时间和结束时间不能为空");
        }
        LocalDateTime startLocalDate;
        LocalDateTime endLocalDate;
        try {
            startLocalDate = LocalDateTimeUtil.parse(param.getStartTime(), DatePattern.NORM_DATE_PATTERN);
            endLocalDate = LocalDateTimeUtil.parse(param.getEndTime(), DatePattern.NORM_DATE_PATTERN);
        } catch (Exception e) {
            throw new BusinessException("时间格式不正确，请使用 yyyy-MM-dd 格式");
        }
        String beginDay = LocalDateTimeUtil.format(
                LocalDateTimeUtil.beginOfDay(startLocalDate),
                DatePattern.NORM_DATETIME_PATTERN
        );
        String endDay = LocalDateTimeUtil.format(
                LocalDateTimeUtil.endOfDay(endLocalDate),
                DatePattern.NORM_DATETIME_PATTERN
        );
        if (CollectionUtil.isNotEmpty(param.getLineList())) {
            processWithLineIds(param.getLineList(), beginDay, endDay, param.getBzType());
        } else {
            processWithoutLineIds(beginDay, endDay, param.getBzType());
        }
    }

    private void processWithLineIds(List<String> lineList, String beginDay, String endDay, Integer bzType) {
        List<CsLinePO> csLineList = csLinePOService.listByIds(lineList);
        List<String> deviceIdList = csLineList.stream()
                .map(CsLinePO::getDeviceId)
                .distinct()
                .collect(Collectors.toList());

        List<CsEquipmentDeliveryPO> equipmentList = csEquipmentDeliveryService.listByIds(deviceIdList);
        Map<String, List<CsEquipmentDeliveryPO>> devMap = equipmentList.stream()
                .collect(Collectors.groupingBy(CsEquipmentDeliveryPO::getNodeId));

        handleEventsAndLogs(devMap, csLineList, beginDay, endDay, bzType);
    }

    private void processWithoutLineIds(String beginDay, String endDay, Integer bzType) {
        List<CsEquipmentDeliveryPO> devList = csEquipmentDeliveryService.getAllOnline();
        if (CollectionUtil.isEmpty(devList)) return;

        List<String> deviceIds = devList.stream()
                .map(CsEquipmentDeliveryPO::getId)
                .collect(Collectors.toList());

        List<CsLinePO> csLineList = csLinePOService.getLinesByDevList(deviceIds);
        Map<String, List<CsEquipmentDeliveryPO>> devMap = devList.stream()
                .collect(Collectors.groupingBy(CsEquipmentDeliveryPO::getNodeId));

        handleEventsAndLogs(devMap, csLineList, beginDay, endDay, bzType);
    }

    private void handleEventsAndLogs(
            Map<String, List<CsEquipmentDeliveryPO>> devMap,
            List<CsLinePO> csLineList,
            String beginDay,
            String endDay,
            Integer bzType
    ) {
        devMap.forEach((nodeId, devices) -> {
            List<BZEventMessage.Event> events = new ArrayList<>();
            List<CsTerminalLogs> logsToSave = new ArrayList<>();
            List<CsTerminalReply> repliesToSave = new ArrayList<>();

            for (CsEquipmentDeliveryPO device : devices) {
                String uuid = IdUtil.simpleUUID();

                BZEventMessage.Event event = buildEvent(uuid, device, csLineList, beginDay, endDay, bzType);
                events.add(event);

                CsTerminalLogs log = buildTerminalLog(uuid, device, csLineList);
                logsToSave.add(log);

                List<CsTerminalReply> reply = buildTerminalReply(uuid, device, csLineList, bzType);
                repliesToSave.addAll(reply);
            }
            csTerminalLogsService.saveBatch(logsToSave);
            csTerminalReplyService.saveBatch(repliesToSave);
            bzEventMessageTemplate.sendMember(events, nodeId);
        });
    }

    private BZEventMessage.Event buildEvent(String guid, CsEquipmentDeliveryPO device,
                                            List<CsLinePO> csLineList, String beginDay, String endDay, Integer bzType) {
        BZEventMessage.Event event = new BZEventMessage.Event();
        event.setGuid(guid);
        event.setTerminalId(device.getId());

        List<String> monitorIds = csLineList.stream()
                .filter(line -> Objects.equals(line.getDeviceId(), device.getId()))
                .map(CsLinePO::getLineId)
                .collect(Collectors.toList());

        event.setMonitorIdList(monitorIds);
        if (!Objects.isNull(bzType) && bzType == 0) {
            event.setDataType(0);
        } else {
            event.setDataType(1);
        }
        event.setTimeInterval(Collections.singletonList(beginDay + "~" + endDay));
        return event;
    }

    private CsTerminalLogs buildTerminalLog(String id, CsEquipmentDeliveryPO device,
                                            List<CsLinePO> csLineList) {
        List<String> lineIds = csLineList.stream()
                .filter(line -> Objects.equals(line.getDeviceId(), device.getId()))
                .map(CsLinePO::getLineId)
                .collect(Collectors.toList());

        CsTerminalLogs log = new CsTerminalLogs();
        log.setId(id);
        log.setDeviceId(device.getId());
        log.setLineId(String.join(",", lineIds));
        log.setOperateType(3);
        log.setNodeId(device.getNodeId());
        log.setNodeProcess(device.getNodeProcess());
        log.setIsPush(1);
        return log;
    }

    private List<CsTerminalReply> buildTerminalReply(String replyId, CsEquipmentDeliveryPO device,
                                               List<CsLinePO> csLineList, Integer bzType) {
        List<CsTerminalReply> replies = new ArrayList<>();
        List<String> lineIds = csLineList.stream()
                .filter(line -> Objects.equals(line.getDeviceId(), device.getId()))
                .map(CsLinePO::getLineId)
                .collect(Collectors.toList());
        lineIds.forEach(lineId -> {
            CsTerminalReply reply = new CsTerminalReply();
            reply.setId(IdUtil.simpleUUID());
            reply.setReplyId(replyId);
            reply.setNodeId(device.getNodeId());
            reply.setProcessNo(device.getNodeProcess());
            reply.setDeviceId(device.getId());
            reply.setLineId(lineId);
            reply.setIsReceived(0);
            if (!Objects.isNull(bzType) && bzType == 0) {
                reply.setCode("harmonic");
            } else {
                reply.setCode("allEvent");
            }
            replies.add(reply);
        });
        return replies;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bzFile(IcdBzParam param) {
        String beginDay = LocalDateTimeUtil.format(
                LocalDateTimeUtil.beginOfDay(LocalDateTimeUtil.parse(param.getStartTime(), DatePattern.NORM_DATE_PATTERN)),
                DatePattern.NORM_DATETIME_PATTERN
        );
        String endDay = LocalDateTimeUtil.format(
                LocalDateTimeUtil.endOfDay(LocalDateTimeUtil.parse(param.getEndTime(), DatePattern.NORM_DATE_PATTERN)),
                DatePattern.NORM_DATETIME_PATTERN
        );

        // 获取监测点没有波形的事件信息
        List<CsEventPO> eventList = eventFeignClient.getEventByTime(param.getLineList(), beginDay, endDay).getData();
        if (CollUtil.isEmpty(eventList)) {
            return;
        }

        // 获取装置信息，用于区分不同服务器
        List<String> deviceIds = eventList.stream()
                .map(CsEventPO::getDeviceId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());

        if (CollUtil.isEmpty(deviceIds)) {
            return;
        }

        List<CsEquipmentDeliveryPO> equipmentList = csEquipmentDeliveryService.listByIds(deviceIds);
        if (CollUtil.isEmpty(equipmentList)) {
            return;
        }

        Map<String, List<CsEquipmentDeliveryPO>> nodeToDeviceMap = equipmentList.stream()
                .collect(Collectors.groupingBy(CsEquipmentDeliveryPO::getNodeId));

        // 构建 deviceId -> CsEventPO 映射，避免重复 filter
        Map<String, List<CsEventPO>> deviceToEventMap = eventList.stream()
                .filter(event -> event.getDeviceId() != null)
                .collect(Collectors.groupingBy(CsEventPO::getDeviceId));

        nodeToDeviceMap.forEach((nodeId, deviceList) -> {
            List<BZEventMessage.Event> msgList = new ArrayList<>();
            List<CsTerminalLogs> logList = new ArrayList<>();
            List<CsTerminalReply> replyList = new ArrayList<>();

            for (CsEquipmentDeliveryPO device : deviceList) {
                String deviceId = device.getId();
                List<CsEventPO> eventsForDevice = deviceToEventMap.getOrDefault(deviceId, Collections.emptyList());

                Map<String, List<CsEventPO>> lineToEventMap = eventsForDevice.stream()
                        .filter(event -> event.getLineId() != null)
                        .collect(Collectors.groupingBy(CsEventPO::getLineId));

                lineToEventMap.forEach((lineId, eventGroup) -> {
                    BZEventMessage.Event event = new BZEventMessage.Event();
                    String guid = IdUtil.simpleUUID();
                    event.setGuid(guid);
                    event.setTerminalId(deviceId);
                    event.setMonitorIdList(Collections.singletonList(lineId));
                    event.setDataType(2);

                    List<String> timeList = eventGroup.stream()
                            .map(CsEventPO::getStartTime)
                            .filter(Objects::nonNull)
                            .map(dt -> dt.format(microsecondFormatter))
                            .collect(Collectors.toList());

                    event.setTimeInterval(timeList);
                    msgList.add(event);

                    // 记录发送日志
                    CsTerminalLogs log = new CsTerminalLogs();
                    log.setId(guid);
                    log.setDeviceId(deviceId);
                    log.setLineId(lineId);
                    log.setOperateType(3);
                    log.setNodeId(device.getNodeId());
                    log.setNodeProcess(device.getNodeProcess());
                    log.setIsPush(1);
                    logList.add(log);

                    // 记录响应日志
                    CsTerminalReply reply = new CsTerminalReply();
                    reply.setId(IdUtil.simpleUUID());
                    reply.setReplyId(guid);
                    reply.setNodeId(device.getNodeId());
                    reply.setProcessNo(device.getNodeProcess());
                    reply.setDeviceId(deviceId);
                    reply.setLineId(lineId);
                    reply.setIsReceived(0);
                    reply.setCode("allFile");
                    replyList.add(reply);
                });
            }

            if (CollUtil.isNotEmpty(logList)) {
                csTerminalLogsService.saveBatch(logList);
            }
            if (CollUtil.isNotEmpty(replyList)) {
                csTerminalReplyService.saveBatch(replyList);
            }
            if (CollUtil.isNotEmpty(msgList)) {
                bzEventMessageTemplate.sendMember(msgList, nodeId);
            }
        });
    }

    /**
     * 设置工程信息
     */
    private void setEngineeringInfo(CldLedgerVo vo, Integer level, String[] pids, String id) {
        String engineeringId;

        if (level == 0) {
            // 0级本身就是工程
            engineeringId = id;
        } else if (level >= 1 && pids.length > 1) {
            // 1-3级的工程ID在pids[1]位置
            engineeringId = pids[1];
        } else {
            return;
        }
        CsEngineeringPO po = csEngineeringService.queryEngineeringById(engineeringId);
        if (po != null) {
            vo.setEngineeringId(po.getId());
            vo.setEngineeringName(po.getName());
            vo.setProvince(po.getProvince());
            vo.setCity(po.getCity());
            vo.setEngineeringDescription(po.getDescription());
            vo.setSort(po.getSort());
        }
    }

    /**
     * 处理0级数据（工程级别）
     */
    private void handleLevel0(CldLedgerVo vo, String id) {
        List<ProjectVO> result = new ArrayList<>();
        List<AppProjectPO> projectInfoList = appProjectService.getProjectByEngineering(Collections.singletonList(id));
        if (CollectionUtil.isNotEmpty(projectInfoList)) {
            List<String> projectIds = projectInfoList.stream().map(AppProjectPO::getId).collect(Collectors.toList());
            LambdaQueryWrapper<AppTopologyDiagramPO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(AppTopologyDiagramPO::getProjectId,projectIds).eq(AppTopologyDiagramPO::getStatus,1);
            List<AppTopologyDiagramPO> appTopologyDiagramPOList = appTopologyDiagramService.list(queryWrapper);
            Map<String, AppTopologyDiagramPO> appTopologyDiagramPOMap = appTopologyDiagramPOList.stream().collect(Collectors.toMap(AppTopologyDiagramPO::getProjectId, item -> item));
            projectInfoList.forEach(item->{
                ProjectVO vo1 = new ProjectVO();
                BeanUtils.copyProperties(item,vo1);
                vo1.setTopoId(Objects.isNull(appTopologyDiagramPOMap.get(item.getId()))?null:appTopologyDiagramPOMap.get(item.getId()).getTopoId());
                result.add(vo1);
            });
            result.sort(Comparator.comparingInt(ProjectVO::getSort));
        }
        vo.setProjectInfoList(result);
    }

    /**
     * 处理1级数据（项目级别）
     */
    private void handleLevel1(CldLedgerVo vo, String id, String[] pids) {
        // 设置项目信息
        List<ProjectVO> result = new ArrayList<>();
        List<AppProjectPO> appProjectPOS = appProjectService.listByIds(Collections.singletonList(id));
        if (CollectionUtil.isNotEmpty(appProjectPOS)) {
            List<String> projectIds = appProjectPOS.stream().map(AppProjectPO::getId).collect(Collectors.toList());
            LambdaQueryWrapper<AppTopologyDiagramPO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(AppTopologyDiagramPO::getProjectId,projectIds).eq(AppTopologyDiagramPO::getStatus,1);
            List<AppTopologyDiagramPO> appTopologyDiagramPOList = appTopologyDiagramService.list(queryWrapper);
            Map<String, AppTopologyDiagramPO> appTopologyDiagramPOMap = appTopologyDiagramPOList.stream().collect(Collectors.toMap(AppTopologyDiagramPO::getProjectId, item -> item));
            appProjectPOS.forEach(item->{
                ProjectVO vo1 = new ProjectVO();
                BeanUtils.copyProperties(item,vo1);
                vo1.setTopoId(Objects.isNull(appTopologyDiagramPOMap.get(item.getId()))?null:appTopologyDiagramPOMap.get(item.getId()).getTopoId());
                result.add(vo1);
            });
            result.sort(Comparator.comparingInt(ProjectVO::getSort));
        }
        vo.setProjectInfoList(result);
        // 设置设备信息
        List<CsEquipmentDeliveryPO> devList = csEquipmentDeliveryService.getDevListByProjectId(id);
        devList.sort(Comparator.comparingInt(CsEquipmentDeliveryPO::getSort));
        vo.setDeviceInfoList(devList);
    }

    /**
     * 处理2级数据（设备级别）
     */
    private void handleLevel2(CldLedgerVo vo, String id, String[] pids) {
        // 设置项目信息（项目ID在pids[2]位置）
        if (pids.length > 2) {
            String projectId = pids[2];
            List<AppProjectPO> project = appProjectService.listByIds(Collections.singletonList(projectId));
            List<ProjectVO> result = new ArrayList<>();
            if (CollectionUtil.isNotEmpty(project)) {
                List<String> projectIds = project.stream().map(AppProjectPO::getId).collect(Collectors.toList());
                LambdaQueryWrapper<AppTopologyDiagramPO> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.in(AppTopologyDiagramPO::getProjectId,projectIds).eq(AppTopologyDiagramPO::getStatus,1);
                List<AppTopologyDiagramPO> appTopologyDiagramPOList = appTopologyDiagramService.list(queryWrapper);
                Map<String, AppTopologyDiagramPO> appTopologyDiagramPOMap = appTopologyDiagramPOList.stream().collect(Collectors.toMap(AppTopologyDiagramPO::getProjectId, item -> item));
                project.forEach(item->{
                    ProjectVO vo1 = new ProjectVO();
                    BeanUtils.copyProperties(item,vo1);
                    vo1.setTopoId(Objects.isNull(appTopologyDiagramPOMap.get(item.getId()))?null:appTopologyDiagramPOMap.get(item.getId()).getTopoId());
                    result.add(vo1);
                });
                result.sort(Comparator.comparingInt(ProjectVO::getSort));
            }
            vo.setProjectInfoList(result);
        }
        // 设置设备信息
        List<CsEquipmentDeliveryPO> csEquipmentDeliveryPOS = csEquipmentDeliveryService.listByIds(Collections.singletonList(id));
        csEquipmentDeliveryPOS.sort(Comparator.comparingInt(CsEquipmentDeliveryPO::getSort));
        vo.setDeviceInfoList(csEquipmentDeliveryPOS);
        // 设置线路信息
        List<CsLinePO> list = csLinePOService.queryByDevId(id);
        if (CollectionUtil.isNotEmpty(list)) {
            list.forEach(item->{
                if (Objects.isNull(item.getPt2Ratio())) {
                    item.setPt2Ratio(1.0);
                }
                if (Objects.isNull(item.getCt2Ratio())) {
                    item.setCt2Ratio(1.0);
                }
                if (Objects.isNull(item.getLineNo())) {
                    item.setLineNo(item.getClDid() == 0 ? 0:item.getClDid());
                }
                if (Objects.isNull(item.getRunStatus())) {
                    item.setRunStatus(csEquipmentDeliveryPOS.get(0).getRunStatus());
                }
            });
        }
        list.sort(Comparator.comparingInt((CsLinePO cs) -> cs.getClDid() == null ? Integer.MAX_VALUE : cs.getClDid())
                .thenComparingInt(cs -> cs.getLineNo() == null ? Integer.MAX_VALUE : cs.getLineNo()));
        vo.setLineInfoList(list);
    }

    /**
     * 处理3级数据（线路级别）
     */
    private void handleLevel3(CldLedgerVo vo, String id, String[] pids) {
        // 设置项目信息（项目ID在pids[2]位置）
        if (pids.length > 2) {
            List<ProjectVO> result = new ArrayList<>();
            String projectId = pids[2];
            List<AppProjectPO> appProjectPOS = appProjectService.listByIds(Collections.singletonList(projectId));
            if (CollectionUtil.isNotEmpty(appProjectPOS)) {
                List<String> projectIds = appProjectPOS.stream().map(AppProjectPO::getId).collect(Collectors.toList());
                LambdaQueryWrapper<AppTopologyDiagramPO> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.in(AppTopologyDiagramPO::getProjectId,projectIds).eq(AppTopologyDiagramPO::getStatus,1);
                List<AppTopologyDiagramPO> appTopologyDiagramPOList = appTopologyDiagramService.list(queryWrapper);
                Map<String, AppTopologyDiagramPO> appTopologyDiagramPOMap = appTopologyDiagramPOList.stream().collect(Collectors.toMap(AppTopologyDiagramPO::getProjectId, item -> item));
                appProjectPOS.forEach(item->{
                    ProjectVO vo1 = new ProjectVO();
                    BeanUtils.copyProperties(item,vo1);
                    vo1.setTopoId(Objects.isNull(appTopologyDiagramPOMap.get(item.getId()))?null:appTopologyDiagramPOMap.get(item.getId()).getTopoId());
                    result.add(vo1);
                });
                result.sort(Comparator.comparingInt(ProjectVO::getSort));
            }
            vo.setProjectInfoList(result);
        }
        // 设置设备信息（设备ID在pids[3]位置）
        List<CsEquipmentDeliveryPO> csEquipmentDeliveryPOS;
        if (pids.length > 3) {
            String deviceId = pids[3];
            csEquipmentDeliveryPOS = csEquipmentDeliveryService.listByIds(Collections.singletonList(deviceId));
            csEquipmentDeliveryPOS.sort(Comparator.comparingInt(CsEquipmentDeliveryPO::getSort));
            vo.setDeviceInfoList(csEquipmentDeliveryPOS);
        } else {
            csEquipmentDeliveryPOS = new ArrayList<>();
        }
        // 设置线路信息
        List<CsLinePO> line = csLinePOService.listByIds(Collections.singletonList(id));
        if (CollectionUtil.isNotEmpty(line)) {
            for (CsLinePO item : line) {
                if (item.getPt2Ratio() == null) {
                    item.setPt2Ratio(1.0);
                }
                if (item.getCt2Ratio() == null) {
                    item.setCt2Ratio(1.0);
                }
                item.setLineNo(item.getClDid());
            }
            line.sort(Comparator.comparingInt((CsLinePO cs) -> cs.getClDid() == null ? Integer.MAX_VALUE : cs.getClDid())
                    .thenComparingInt(cs -> cs.getLineNo() == null ? Integer.MAX_VALUE : cs.getLineNo()));
        }
        vo.setLineInfoList(line);
    }

    private boolean isAllIndicesNull(IcdLedgerParam param) {
        return ObjectUtil.isNull(param.getEngineeringIndex())
                && ObjectUtil.isNull(param.getProjectIndex())
                && ObjectUtil.isNull(param.getDevIndex());
    }

    public void handleFullProcessCreation(@NotNull IcdLedgerParam param) {
        if (ObjectUtil.isNotNull(param.getEngineering())) {
            CsEngineeringPO po1 = csEngineeringService.addEngineering(param.getEngineering());
            param.setEngineeringIndex(po1.getId());
            createProjectAndDevices(param);
        }
    }

    public void handleFromEngineeringCreation(IcdLedgerParam param) {
        createProjectAndDevices(param);
    }

    public void handleFromProjectCreation(IcdLedgerParam param) {
        saveDevicesAndLines(param);
    }

    public void handleFromDeviceCreation(IcdLedgerParam param) {
        saveLines(param);
    }

    private void createProjectAndDevices(IcdLedgerParam param) {
        AppProjectAddParm project = param.getProject();
        if (ObjectUtil.isNotNull(project)) {
            project.setEngineeringId(param.getEngineeringIndex());
            project.setIcdEngineeringId(param.getEngineeringIndex());
            AppProjectPO po2 = appProjectService.addAppProject(project);
            param.setProjectIndex(po2.getId());
        }
        saveDevicesAndLines(param);
    }

    private void saveDevicesAndLines(IcdLedgerParam param) {
        List<CsEquipmentDeliveryAddParm> devList = param.getDevice();
        if (CollectionUtil.isNotEmpty(devList)) {
            Map<String,String> devMacMap = new HashMap<>();
            Map<String, CsEquipmentDeliveryPO> devMap = new HashMap<>();
            for (CsEquipmentDeliveryAddParm dev : devList) {
                dev.setEngineeringId(param.getEngineeringIndex());
                dev.setProjectId(param.getProjectIndex());
                CsEquipmentDeliveryPO po3 = csEquipmentDeliveryService.saveCld(dev);
                devMacMap.put(dev.getMac(),po3.getId());
                devMap.put(dev.getMac(),po3);
            }
            param.setDevMacMap(devMacMap);
            param.setDevMap(devMap);
        }
        saveLines(param);
    }

    public void saveLines(IcdLedgerParam param) {
        List<CsLineParam> lineList = param.getLine();
        if (CollectionUtil.isNotEmpty(lineList)) {
            boolean result = checkAndAlertDuplicates(lineList);
            if (result) {
                throw new BusinessException("监测点线路号重复,请调整!");
            }
            for (CsLineParam line : lineList) {
                line.setEngineeringId(param.getEngineeringIndex());
                line.setProjectId(param.getProjectIndex());
                if (Objects.isNull(param.getDevIndex())) {
                    line.setDevId(param.getDevMacMap().get(line.getDevMac()));
                } else {
                    LambdaQueryWrapper<CsLinePO> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(CsLinePO::getDeviceId,param.getDevIndex()).eq(CsLinePO::getLineNo,line.getLineNo()).eq(CsLinePO::getStatus,1);
                    CsLinePO po4 = csLinePOService.getOne(wrapper);
                    if (ObjectUtil.isNotNull(po4)) {
                        throw new BusinessException("监测点线路号重复,请调整!");
                    }
                    line.setDevId(param.getDevIndex());
                }
                CsLinePO po = csLinePOService.addCldLine(line);
                //新增监测点限值
                Overlimit overlimit = COverlimitUtil.globalAssemble(line.getVolGrade().floatValue(), line.getProtocolCapacity().floatValue(),line.getDevCapacity().floatValue(),line.getShortCircuitCapacity().floatValue(),0,0);
                overlimit.setId(po.getLineId());
                overLimitWlMapper.insert(overlimit);
            }

            //新增台账日志
            CsTerminalLogs csTerminalLogs = new CsTerminalLogs();
            if (ObjectUtil.isNotNull(param.getDevIndex()) && StringUtil.isNotBlank(param.getDevIndex())) {
                csTerminalLogs.setDeviceId(param.getDevIndex());
            } else {
                csTerminalLogs.setDeviceId(param.getDevMacMap().get(lineList.get(0).getDevMac()));
            }
            csTerminalLogs.setOperateType(0);
            csTerminalLogs.setIsPush(0);
            csTerminalLogsService.save(csTerminalLogs);
        }
    }

    //判断相同设备不能存在相同的线路号监测点
    public boolean checkAndAlertDuplicates(List<CsLineParam> devices) {
        // 使用Set来记录已经出现过的devMac+clDid组合
        Set<String> seenCombinations = new HashSet<>();
        List<CsLineParam> duplicates = new ArrayList<>();

        for (CsLineParam device : devices) {
            String combination = device.getDevMac() + "-" + device.getLineNo();
            if (seenCombinations.contains(combination)) {
                // 发现重复，添加到重复列表
                duplicates.add(device);
            } else {
                seenCombinations.add(combination);
            }
        }
        return !duplicates.isEmpty();
    }

}
