package com.njcn.gather.detection.handler;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.njcn.gather.detection.pojo.enums.SourceOperateCodeEnum;
import com.njcn.gather.detection.pojo.enums.SourceResponseCodeEnum;
import com.njcn.gather.detection.pojo.param.DevPhaseSequenceParam;
import com.njcn.gather.detection.pojo.param.PreDetectionParam;
import com.njcn.gather.detection.pojo.vo.DevLineTestResult;
import com.njcn.gather.detection.pojo.vo.SocketDataMsg;
import com.njcn.gather.detection.pojo.vo.SocketMsg;
import com.njcn.gather.detection.pojo.vo.WebSocketVO;
import com.njcn.gather.detection.util.socket.*;
import com.njcn.gather.detection.util.socket.websocket.WebServiceManager;
import com.njcn.gather.device.pojo.vo.PreDetection;
import com.njcn.gather.device.service.IPqDevService;
import com.njcn.gather.plan.pojo.po.AdPlanSource;
import com.njcn.gather.plan.service.IAdPlanSourceService;
import com.njcn.gather.report.pojo.enums.PowerIndexEnum;
import com.njcn.gather.script.pojo.po.SourceIssue;
import com.njcn.gather.source.pojo.po.SourceInitialize;
import com.njcn.gather.source.service.IPqSourceService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

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

/**
 * 程控源Socket响应处理服务
 * <p>
 * 该服务类负责处理来自程控源设备的Socket消息响应，包括：
 * - 源初始化响应处理
 * - 检测流程控制和状态管理
 * - 相序检测、系数校验等特定检测类型的响应处理
 * - WebSocket消息推送给前端用户
 * - 错误处理和连接管理
 * </p>
 * <p>
 * 主要处理的操作类型：
 * - YJC_YTXJY: 源通信校验/源初始化
 * - YJC_XUJY: 相序检测
 * - FORMAL_REAL: 正式检测
 * - Coefficient_Check: 系数校验
 * - QUITE_SOURCE: 退出源连接
 * </p>
 *
 * @author CN_Gather Detection Team
 * @version 1.0
 * @since 2023
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SocketSourceResponseService {

    /**
     * 设备信息服务，提供设备基础信息查询功能
     */
    private final IPqDevService iPqDevService;
    private final IAdPlanSourceService adPlanSourceService;
    private final IPqSourceService pqSourceService;

    /**
     * Socket连接管理器，负责管理设备和源的Socket连接
     */
    private final SocketManager socketManager;

    /**
     * 发送WebSocket消息到指定用户页面
     * <p>
     * 将数据对象转换为JSON字符串并通过WebSocket推送给前端用户，
     * 用于实时通知用户检测进度、状态变化或错误信息。
     * </p>
     *
     * @param userPageId 用户页面ID，用于标识消息接收方
     * @param data       要发送的数据对象，将被转换为JSON格式
     */
    private void sendWebSocketMessage(String userPageId, Object data) {
        WebServiceManager.sendMsg(userPageId, JSON.toJSONString(data));
    }

    /**
     * 发送错误消息并退出源连接
     * <p>
     * 当检测过程中发生错误时，执行以下操作：
     * 1. 主动断开与程控源的连接
     * 2. 构造包含错误信息的Socket消息
     * 3. 通过WebSocket将错误信息推送给前端用户
     * </p>
     *
     * @param param         检测参数，包含用户页面ID等信息
     * @param socketDataMsg 原始Socket消息，用于构造响应消息
     * @param errorMessage  具体的错误描述信息
     */
    private void sendErrorAndQuit(PreDetectionParam param, SocketDataMsg socketDataMsg, String errorMessage) {
        CnSocketUtil.quitSendSource(param);
        SocketMsg<String> socketMsg = new SocketMsg<>();
        socketMsg.setRequestId(socketDataMsg.getRequestId());
        socketMsg.setOperateCode(socketDataMsg.getOperateCode());
        socketMsg.setData(errorMessage);
        sendWebSocketMessage(param.getUserPageId(), socketMsg);
    }

    /**
     * 发送错误消息并退出源连接（使用枚举消息）
     * <p>
     * 重载方法，使用预定义的错误码枚举来获取标准化的错误消息。
     * 确保错误信息的一致性和规范性。
     * </p>
     *
     * @param param         检测参数
     * @param socketDataMsg 原始Socket消息
     * @param errorCode     错误码枚举，包含标准化的错误描述
     */
    private void sendErrorAndQuit(PreDetectionParam param, SocketDataMsg socketDataMsg, SourceResponseCodeEnum errorCode) {
        sendErrorAndQuit(param, socketDataMsg, errorCode.getMessage());
    }

    private void sendSimulateInitFailure(PreDetectionParam param, String errorMessage) {
        SocketDataMsg socketDataMsg = new SocketDataMsg();
        socketDataMsg.setRequestId(SourceOperateCodeEnum.YJC_YTXJY.getValue());
        socketDataMsg.setOperateCode(SourceOperateCodeEnum.INIT_GATHER.getValue());
        socketDataMsg.setCode(SourceResponseCodeEnum.UNKNOWN_ERROR.getCode());
        socketDataMsg.setData(errorMessage);
        sendWebSocketMessage(param.getUserPageId(), socketDataMsg);
    }


    /**
     * 当前检测会话中的设备列表
     * <p>
     * 存储正在进行检测的设备信息，包含设备基本信息和监测点配置。
     * 注意：该字段存在线程安全问题，建议后续重构为线程安全的设计。
     * </p>
     */
    private List<PreDetection> devList = new ArrayList<>();

    /**
     * 当前检测会话中的监测点ID列表
     * <p>
     * 从设备列表中提取的所有监测点ID集合，用于向设备发送数据请求时指定监测范围。
     * 与devList字段保持同步更新。
     * </p>
     */
    private List<String> monitorIdList = new ArrayList<>();

    /**
     * 程控源响应消息处理主入口
     * <p>
     * 根据消息中的操作码，分发到相应的处理方法：
     * - 解析Socket消息，提取操作码
     * - 根据操作码类型调用对应的处理方法
     * - 支持检测计划模式和模拟测试模式的区分处理
     * </p>
     * <p>
     * 支持的操作类型：
     * - YJC_YTXJY: 源通信校验/源初始化
     * - YJC_XUJY: 相序检测
     * - FORMAL_REAL: 正式检测
     * - Coefficient_Check: 系数校验
     * - QUITE_SOURCE: 退出源连接
     * </p>
     *
     * @param param 检测参数，包含用户ID、设备ID、计划ID等关键信息
     * @param msg   从程控源接收的原始Socket消息
     * @throws Exception 当消息解析失败或处理过程中发生异常时抛出
     */
    public void deal(PreDetectionParam param, String msg) throws Exception {
        // 解析接收到的Socket消息
        SocketDataMsg socketDataMsg = MsgUtil.socketDataMsg(msg);

        // 从requestId中提取操作码，requestId格式为：操作码_步骤标识
        String[] tem = socketDataMsg.getRequestId().split(CnSocketUtil.STEP_TAG);
        SourceOperateCodeEnum enumByCode = SourceOperateCodeEnum.getDictDataEnumByCode(tem[0]);

        if (ObjectUtil.isNotNull(enumByCode)) {
            switch (enumByCode) {
                // 源初始化处理：根据是否有计划ID判断是正式检测还是模拟检测
                case YJC_YTXJY:
                    if (ObjectUtil.isNotNull(param.getPlanId())) {
                        // 有计划ID：正式检测模式，源初始化成功后启动设备检测
                        detectionDev(param, socketDataMsg);
                    } else {
                        // 无计划ID：模拟检测模式，仅进行源通信校验
                        handleYtxjySimulate(param, socketDataMsg);
                    }
                    break;

                // 相序检测：检测设备的相序是否正确
                case YJC_XUJY:
                    phaseSequenceDev(param, socketDataMsg);
                    break;

                // 正式检测：根据是否有计划ID选择不同的处理方式
                case FORMAL_REAL:
                    if (ObjectUtil.isNotNull(param.getPlanId())) {
                        // 有计划ID：向设备发送检测参数
                        senParamToDev(param, socketDataMsg);
                    } else {
                        // 无计划ID：模拟测试模式
                        handleSimulateTest(param, socketDataMsg);
                    }
                    break;

                // 系数校验：验证设备的计量系数是否准确
                case Coefficient_Check:
                    coefficient(param, socketDataMsg);
                    break;

                // 退出源连接：清理资源并关闭连接
                case QUITE_SOURCE:
                    quitDeal(socketDataMsg, param);
                    break;

                // YXT操作：暂未实现具体功能
                case YXT:
                    // TODO: 实现YXT操作的具体逻辑
                    break;

                default:
                    sendSimulateInitFailure(param, "未知操作码");
                    break;
            }
        } else {
            log.error("程控源响应消息操作码解析失败，原始消息: {}, 解析结果: {}", msg, enumByCode);
            sendSimulateInitFailure(param, "未知操作码");
        }
    }

    /**
     * 处理模拟检测中的源通信校验响应
     * <p>
     * 在模拟检测模式下（非计划检测），处理程控源的通信校验响应：
     * - 成功时：根据参数决定是否向前端发送WebSocket消息
     * - 业务未处理：直接转发消息给前端
     * - 各种错误情况：统一处理为退出源连接并通知前端
     * </p>
     * <p>
     * 支持的错误类型包括：
     * - 源连接错误、程控源错误、测试项解析错误
     * - 源控制错误、目标源错误、未初始化错误
     * - 未知错误、无法响应错误
     * </p>
     *
     * @param param         检测参数，包含用户信息和WebSocket消息发送控制
     * @param socketDataMsg 程控源返回的响应消息
     */
    private void handleYtxjySimulate(PreDetectionParam param, SocketDataMsg socketDataMsg) {

        SourceResponseCodeEnum dictDataEnumByCode = SourceResponseCodeEnum.getDictDataEnumByCode(socketDataMsg.getCode());
        if (ObjectUtil.isNotNull(dictDataEnumByCode)) {
            switch (dictDataEnumByCode) {
                case SUCCESS:
                    // 源初始化成功：根据参数控制是否发送WebSocket消息
                    if (param.getSendWebMsg()) {
                        sendWebSocketMessage(param.getUserPageId(), socketDataMsg);
                    }
                    log.info("模拟检测源初始化成功，用户: {}, WebSocket发送: {}",
                            param.getUserPageId(), param.getSendWebMsg());
                    break;
                case UNPROCESSED_BUSINESS:
                    // 业务暂未处理：直接转发消息给前端等待处理
                    sendWebSocketMessage(param.getUserPageId(), socketDataMsg);
                    break;
                // 各种错误情况：源连接错误、程控源控制错误、测试项解析错误等
                case SOURCE_CONNECTION_ERROR:
                case CONTROLLED_SOURCE_ERROR:
                case TEST_ITEM_PARSING_ERROR:
                case SOURCE_CONTROL_ERROR:
                case TARGET_SOURCE_ERROR:
                case NOT_INITIALIZED:
                case UNKNOWN_ERROR:
                case UNABLE_TO_RESPOND:
                    // 所有错误情况统一处理：退出源连接并通知前端
                    CnSocketUtil.quitSendSource(param);
                    sendWebSocketMessage(param.getUserPageId(), socketDataMsg);
                    break;
                default:
                    sendSimulateInitFailure(param, "未知状态码");
                    break;
            }
        } else {
            sendSimulateInitFailure(param, "未知状态码");
        }
    }

    /**
     * 处理模拟检测时，通信模块返回报文
     *
     * @param param
     * @param socketDataMsg
     */
    private void handleSimulateTest(PreDetectionParam param, SocketDataMsg socketDataMsg) {
        SourceResponseCodeEnum dictDataEnumByCode = SourceResponseCodeEnum.getDictDataEnumByCode(socketDataMsg.getCode());
        if (ObjectUtil.isNotNull(dictDataEnumByCode)) {
            switch (dictDataEnumByCode) {
                case SUCCESS:
                    sendWebSocketMessage(param.getUserPageId(), socketDataMsg);
                    log.info("模拟检测源成功执行脚本，用户: {}, 响应消息: {}",
                            param.getUserPageId(), JSON.toJSONString(socketDataMsg));
                    break;
                case UNPROCESSED_BUSINESS:
                    sendWebSocketMessage(param.getUserPageId(), socketDataMsg);
                    break;
                default:
                    sendErrorAndQuit(param, socketDataMsg, dictDataEnumByCode);
                    break;
            }
        }
    }


    /**
     * 系数校验源数据返回处理
     * <p>
     * 处理系数校验阶段程控源的响应消息：
     * 1. 成功时：向前端推送响应信息，然后向设备发送数据请求
     * 2. 构造设备数据请求参数，包含监测点列表和数据类型
     * 3. 设置固定的读取参数：读取3次数据，忽略前4次
     * 4. 请求的数据类型：实时电压有效值(real$VRMS)和实时电流有效值(real$IRMS)
     * </p>
     * <p>
     * 数据请求配置：
     * - 监测点：使用当前会话的monitorIdList
     * - 数据类型：["real$VRMS", "real$IRMS"]
     * - 读取次数：3次
     * - 忽略次数：4次（预热数据）
     * </p>
     *
     * @param param         检测参数
     * @param socketDataMsg 程控源响应消息
     */
    private void coefficient(PreDetectionParam param, SocketDataMsg socketDataMsg) {
        SourceResponseCodeEnum dictDataEnumByCode = SourceResponseCodeEnum.getDictDataEnumByCode(socketDataMsg.getCode());
        if (ObjectUtil.isNotNull(dictDataEnumByCode)) {
            SocketMsg<String> socketMsg = new SocketMsg<>();
            switch (dictDataEnumByCode) {
                case SUCCESS:
                    //向前端推送信息
                    sendWebSocketMessage(param.getUserPageId(), socketDataMsg);

                    String s = param.getUserPageId() + CnSocketUtil.DEV_TAG;
                    socketMsg.setRequestId(SourceOperateCodeEnum.Coefficient_Check.getValue());
                    socketMsg.setOperateCode(SourceOperateCodeEnum.DEV_DATA_REQUEST_02.getValue());
                    DevPhaseSequenceParam phaseSequenceParam = new DevPhaseSequenceParam();
                    phaseSequenceParam.setMoniterIdList(monitorIdList);
                    // 系数校验固定检测项：实时电压有效值和实时电流有效值
                    phaseSequenceParam.setDataType(Arrays.asList("real$VRMS", "real$IRMS"));
                    // 读取3次数据用于系数计算
                    phaseSequenceParam.setReadCount(7); //3
                    // 忽略前4次数据，等待测量稳定
                    phaseSequenceParam.setIgnoreCount(3); //4
                    socketMsg.setData(JSON.toJSONString(phaseSequenceParam));
                    SocketManager.sendMsg(s, JSON.toJSONString(socketMsg));

                    break;
                case UNPROCESSED_BUSINESS:
                    sendWebSocketMessage(param.getUserPageId(), socketDataMsg);
                    break;
                default:
                    sendErrorAndQuit(param, socketDataMsg, dictDataEnumByCode);
                    break;
            }
        }
    }

    /**
     * 装置检测(当源初始化成功后，直接向装置通道向装置服务器发送，装置检测)
     *
     * @param param         参数
     * @param socketDataMsg 消息
     */
    private void detectionDev(PreDetectionParam param, SocketDataMsg socketDataMsg) {
        SourceResponseCodeEnum dictDataEnumByCode = SourceResponseCodeEnum.getDictDataEnumByCode(socketDataMsg.getCode());
        if (ObjectUtil.isNotNull(dictDataEnumByCode)) {
            SocketMsg<String> socketMsg = new SocketMsg<>();
            switch (dictDataEnumByCode) {
                case SUCCESS:
                    if (FormalTestManager.unknownError) {
                        FormalTestManager.unknownError = false;

                        //重新下发脚本
                        String type = FormalTestManager.currentIssue.getType();
                        if (PowerIndexEnum.P.getKey().equals(type)) {
                            FormalTestManager.currentIssue.setType(PowerIndexEnum.V.getKey());
                        }
                        socketMsg.setOperateCode(SourceOperateCodeEnum.OPER_GATHER.getValue());
                        socketMsg.setData(JSON.toJSONString(FormalTestManager.currentIssue));
                        socketMsg.setRequestId(SourceOperateCodeEnum.FORMAL_REAL.getValue() + CnSocketUtil.STEP_TAG + type);
                        SocketManager.sendMsg(param.getUserPageId() + CnSocketUtil.SOURCE_TAG, JSON.toJSONString(socketMsg));
                    } else {
                        // 推送过载测试结果
                        SocketDataMsg overloadSocketDataMsg = new SocketDataMsg();
                        overloadSocketDataMsg.setRequestId("overloadTest");
                        overloadSocketDataMsg.setCode(FormalTestManager.overload);
                        sendWebSocketMessage(param.getUserPageId(), overloadSocketDataMsg);
                        if (FormalTestManager.overload != 4) {
                            CnSocketUtil.quitSendSource(param);
                        } else {
                            //todo 前端推送收到的消息暂未处理好
                            sendWebSocketMessage(param.getUserPageId(), socketDataMsg);
                            //开始设备通讯检测(发送设备初始化)
                            Map<String, List<PreDetection>> map = new HashMap<>(1);
                            map.put("deviceList", FormalTestManager.devList);
                            String jsonString = JSON.toJSONString(map);
                            socketMsg.setRequestId(SourceOperateCodeEnum.YJC_SBTXJY.getValue());
                            socketMsg.setOperateCode(SourceOperateCodeEnum.DEV_INIT_GATHER_01.getValue());
                            socketMsg.setData(jsonString);
                            String json = JSON.toJSONString(socketMsg);
                            // 使用智能发送工具类，自动管理设备连接
                            socketManager.smartSendToDevice(param, json);
                        }
                    }
                    break;
                case UNPROCESSED_BUSINESS:
                    sendWebSocketMessage(param.getUserPageId(), socketDataMsg);
                    break;
                case SOURCE_CONNECTION_ERROR:
                case CONTROLLED_SOURCE_ERROR:
                case TEST_ITEM_PARSING_ERROR:
                case SOURCE_CONTROL_ERROR:
                case TARGET_SOURCE_ERROR:
                case NOT_INITIALIZED:
                case UNKNOWN_ERROR:
                case UNABLE_TO_RESPOND:
                    CnSocketUtil.quitSendSource(param);
                    sendWebSocketMessage(param.getUserPageId(), socketDataMsg);
                    break;
                default:
                    // todo... 这种情况是报文的状态码不一致，需要记录到日志表，以便问题追踪
                    WebServiceManager.sendUnknownErrorMessage(param.getUserPageId());
                    break;
            }
        } else {
            // todo... 这种情况是报文的状态码不一致，需要记录到日志表，以便问题追踪
        }
    }

    /**
     * 相序检测向装置发送（当装置初始成功后，会向源发送加量请求。收到加量请求成功后会向装置发送参数下发。）
     *
     * @param param
     * @param socketDataMsg
     */
    private void phaseSequenceDev(PreDetectionParam param, SocketDataMsg socketDataMsg) {
        SourceResponseCodeEnum dictDataEnumByCode = SourceResponseCodeEnum.getDictDataEnumByCode(socketDataMsg.getCode());
        if (ObjectUtil.isNotNull(dictDataEnumByCode)) {
            SocketMsg<String> socketMsg = new SocketMsg<>();
            switch (dictDataEnumByCode) {
                case SUCCESS:
                    //向前端推送信息
                    sendWebSocketMessage(param.getUserPageId(), socketDataMsg);

                    String s = param.getUserPageId() + CnSocketUtil.DEV_TAG;
                    socketMsg.setRequestId(SourceOperateCodeEnum.YJC_XUJY.getValue());
                    socketMsg.setOperateCode(SourceOperateCodeEnum.DEV_DATA_REQUEST_02.getValue());
                    List<PreDetection> pqDevList = iPqDevService.getDevInfo(param.getDevIds());
                    List<String> moniterIdList = pqDevList.stream().flatMap(x -> x.getMonitorList().stream())
                            .map(PreDetection.MonitorListDTO::getLineId)
                            .collect(Collectors.toList());

                    DevPhaseSequenceParam phaseSequenceParam = new DevPhaseSequenceParam();
                    phaseSequenceParam.setMoniterIdList(moniterIdList);
                    // 相序检测项：电压有效值、电压角度、电流有效值、电流角度
                    phaseSequenceParam.setDataType(Arrays.asList("real$VRMS", "real$VA", "real$IRMS", "real$IA"));
                    // 相序检测只需要读取1次数据
                    phaseSequenceParam.setReadCount(1);
                    // 忽略前10次数据，确保相序稳定
                    phaseSequenceParam.setIgnoreCount(10);
                    socketMsg.setData(JSON.toJSONString(phaseSequenceParam));
                    SocketManager.sendMsg(s, JSON.toJSONString(socketMsg));
                    break;
                case UNPROCESSED_BUSINESS:
                    sendWebSocketMessage(param.getUserPageId(), socketDataMsg);
                    break;
                case MESSAGE_PARSING_ERROR:
                    CnSocketUtil.quitSendSource(param);
                    break;
                default:
                    sendErrorAndQuit(param, socketDataMsg, dictDataEnumByCode);
                    break;
            }
        }
    }


    /**
     * 正式检测时向设备发送参数请求
     * <p>
     * 当程控源成功执行脚本后，根据检测项目类型向设备发送相应的数据请求：
     * 1. 获取源脚本信息，确定检测类型和数据类型
     * 2. 根据检测类型设置不同的读取参数：
     * - 闪变(F)：忽略1次，读取2次，使用DEV_DATA_REQUEST_01
     * - 暂态(VOLTAGE)：忽略5次，读取1次，使用DEV_DATA_REQUEST_03
     * - 其他类型：忽略5次，读取5次，根据数据类型选择操作码
     * 3. 构造设备数据请求并发送
     * 4. 向前端推送检测开始信息
     * </p>
     * <p>
     * 检测参数配置：
     * - 闪变检测：ignoreCount=1, readCount=2
     * - 暂态检测：ignoreCount=5, readCount=1
     * - 常规检测：ignoreCount=5, readCount=5
     * - 实时数据：使用DEV_DATA_REQUEST_02
     * - 分钟数据：使用DEV_DATA_REQUEST_01
     * </p>
     *
     * @param param         检测参数，包含用户和设备信息
     * @param socketDataMsg 程控源成功响应消息
     */
    private void senParamToDev(PreDetectionParam param, SocketDataMsg socketDataMsg) {
        SourceResponseCodeEnum dictDataEnumByCode = SourceResponseCodeEnum.getDictDataEnumByCode(socketDataMsg.getCode());
        if (ObjectUtil.isNotNull(dictDataEnumByCode)) {
            SocketMsg<String> socketMsg = new SocketMsg<>();
            switch (dictDataEnumByCode) {
                case SUCCESS:
                    //向前端推送信息
                    // webSocketHandler.sendMsgToUser(param.getUserPageId(), JSON.toJSONString(socketDataMsg));

                    // 构造设备通道标识：用户ID + 设备标签
                    String s = param.getUserPageId() + CnSocketUtil.DEV_TAG;

                    // 获取当前检测的源脚本信息，包含检测类型和数据要求
                    SourceIssue sourceIssue = SocketManager.getSourceList().get(0);
                    // 数据类型列表，格式：real$VRMS、real$IRMS
                    List<String> comm = sourceIssue.getDevValueTypeList();
                    log.debug("向设备下发检测参数，用户: {}, 数据类型: {}", param.getUserPageId(), comm);

                    // 设置请求ID：正式检测操作码 + 步骤标识 + 检测类型
                    socketMsg.setRequestId(socketDataMsg.getRequestId());

                    // 根据检测类型设置不同的读取参数和操作码
                    int ignoreCount;
                    int readData;

                    if (PowerIndexEnum.F.getKey().equals(sourceIssue.getType())) {
                        // 短时间闪变检测：数据变化较慢，只需少量预热和读取
                        // 短时间闪变测量稳定性好，预热1次即可
                        ignoreCount = 1;
                        // 读取2次数据计算闪变值
                        readData = 2;

                        if (PowerIndexEnum.LF.getKey().equals(sourceIssue.getOtherType())) {
                            FormalTestManager.longFlickerDataCount = 0;
                            // 长时间闪变检测
                            ignoreCount = 0;
                            readData = 0;
                        }
                        socketMsg.setOperateCode(SourceOperateCodeEnum.DEV_DATA_REQUEST_01.getValue());
                    } else if (PowerIndexEnum.VOLTAGE.getKey().equals(sourceIssue.getType())) {
                        // 暂态电压检测：需要更多预热时间，但只读取一次快照
                        // 暂态事件需要5次预热确保触发稳定
                        ignoreCount = 5;
                        // 暂态检测只需要捕获一次事件
                        readData = 1;
                        socketMsg.setOperateCode(SourceOperateCodeEnum.DEV_DATA_REQUEST_03.getValue());
                    } else {
                        // 常规检测（谐波、不平衡度等）：需要多次采样以提高精度
                        // 常规检测预热5次等待稳定
                        ignoreCount = 5;
                        // 读取5次数据进行统计分析
                        readData = 5;

                        // 根据数据类型选择相应的请求操作码
                        if ("real".equals(sourceIssue.getDataType())) {
                            // 实时数据：瞬时值或有效值
                            socketMsg.setOperateCode(SourceOperateCodeEnum.DEV_DATA_REQUEST_02.getValue());
                        } else {
                            // 分钟数据：统计周期内的平均值或累计值
                            socketMsg.setOperateCode(SourceOperateCodeEnum.DEV_DATA_REQUEST_01.getValue());
                        }
                    }
                    log.debug("检测设备列表状态检查，用户: {}, 设备列表为空: {}",
                            param.getUserPageId(), CollectionUtils.isEmpty(devList));

                    // 构造设备数据请求参数
                    DevPhaseSequenceParam phaseSequenceParam = new DevPhaseSequenceParam();
                    // 设置监测点ID列表
                    phaseSequenceParam.setMoniterIdList(monitorIdList);
                    // 设置数据类型列表
                    phaseSequenceParam.setDataType(comm);
                    // 设置读取次数
                    phaseSequenceParam.setReadCount(readData);
                    // 设置忽略次数
                    phaseSequenceParam.setIgnoreCount(ignoreCount);
                    socketMsg.setData(JSON.toJSONString(phaseSequenceParam));

                    // 向设备发送数据请求
                    SocketManager.sendMsg(s, JSON.toJSONString(socketMsg));

                    // 构造前端显示的设备列表，只包含设备ID和名称
                    List<DevLineTestResult> devListRes = new ArrayList<>();
                    devList.forEach(item -> {
                        DevLineTestResult devLineTestResult = new DevLineTestResult();
                        devLineTestResult.setDeviceId(item.getDevId());
                        devLineTestResult.setDeviceName(item.getDevName());
                        devListRes.add(devLineTestResult);
                    });

                    // 构造WebSocket消息并推送给前端，通知检测开始
                    WebSocketVO<Object> webSocketVO = new WebSocketVO<>();
                    // 设置请求ID：检测类型 + 开始标识
                    webSocketVO.setRequestId(socketDataMsg.getRequestId().split(CnSocketUtil.STEP_TAG)[1] + CnSocketUtil.START_TAG);
                    // 检测描述信息
                    webSocketVO.setDesc(SocketManager.getSourceList().get(0).getDesc());
                    // 参与检测的设备列表
                    webSocketVO.setData(devListRes);
                    sendWebSocketMessage(param.getUserPageId(), webSocketVO);
                    break;
                case UNPROCESSED_BUSINESS:
                    sendWebSocketMessage(param.getUserPageId(), socketDataMsg);
                    break;
                case UNKNOWN_ERROR: //-1源未知异常
                    CnSocketUtil.quitSendSource(param);
                    FormalTestManager.unknownError = true;
                    break;
                default:
                    sendErrorAndQuit(param, socketDataMsg, dictDataEnumByCode);
                    break;
            }
        }
    }


    /**
     * 处理退出检测的响应
     * <p>
     * 当用户主动退出检测或系统需要终止检测时，处理程控源的退出响应：
     * - 成功退出：移除Socket连接管理中的用户信息，向前端发送成功消息
     * - 业务未处理：不做特殊处理
     * - 消息解析错误/无法响应：移除用户连接信息
     * - 其他错误：调用退出源连接方法
     * </p>
     * <p>
     * 退出流程：
     * 1. 解析响应状态码
     * 2. 根据状态码执行相应的清理操作
     * 3. 确保Socket连接资源得到正确释放
     * </p>
     *
     * @param socketDataMsg 程控源退出响应消息
     * @param param         检测参数，包含用户信息
     */
    private void quitDeal(SocketDataMsg socketDataMsg, PreDetectionParam param) {
        SourceResponseCodeEnum dictDataEnumByCode = SourceResponseCodeEnum.getDictDataEnumByCode(socketDataMsg.getCode());
        switch (Objects.requireNonNull(dictDataEnumByCode)) {
            case SUCCESS:
                if (FormalTestManager.unknownError) {
                    //获取源初始化参数
                    AdPlanSource planSource = adPlanSourceService.getOne(new LambdaQueryWrapper<AdPlanSource>().eq(AdPlanSource::getPlanId, param.getPlanId()));
                    SourceInitialize sourceParam = pqSourceService.getSourceInitializeParam(planSource.getSourceId());
                    if (ObjectUtil.isNotNull(sourceParam)) {
                        SocketMsg<String> socketMsg1 = new SocketMsg<>();
                        socketMsg1.setRequestId(SourceOperateCodeEnum.YJC_YTXJY.getValue());
                        socketMsg1.setOperateCode(SourceOperateCodeEnum.INIT_GATHER.getValue());
                        socketMsg1.setData(JSON.toJSONString(sourceParam));
                        //使用智能发送工具类，自动管理与源控程序的socket连接
                        socketManager.smartSendToSource(param, JSON.toJSONString(socketMsg1));
                    }
                } else {
                    //通讯校验成功
                    SocketManager.removeUser(param.getUserPageId() + CnSocketUtil.SOURCE_TAG);
                    sendWebSocketMessage(param.getUserPageId(), socketDataMsg);
                }
                break;
            case UNPROCESSED_BUSINESS:
                break;
            case MESSAGE_PARSING_ERROR:
                SocketManager.removeUser(param.getUserPageId() + CnSocketUtil.SOURCE_TAG);
                break;
            case UNABLE_TO_RESPOND:
                SocketManager.removeUser(param.getUserPageId() + CnSocketUtil.SOURCE_TAG);
                break;
            default:
                CnSocketUtil.quitSendSource(param);
                break;
        }

    }


    /**
     * 初始化检测设备和监测点列表
     * <p>
     * 在开始检测前，根据检测参数初始化当前会话的设备信息：
     * 1. 清空之前的设备列表和监测点列表
     * 2. 根据设备ID列表查询设备详细信息
     * 3. 从设备信息中提取所有监测点的线路ID
     * 4. 同步更新XiNumberManager中的设备列表
     * </p>
     * <p>
     * 该方法通常在检测开始前调用，确保后续的检测流程能够获取到正确的
     * 设备配置和监测点信息。
     * </p>
     *
     * @param param 检测参数，包含要检测的设备ID列表
     */
    public void initList(PreDetectionParam param) {
        // 清空现有列表，为新的检测会话做准备
        devList.clear();
        monitorIdList.clear();

        // 查询设备详细信息，包含监测点配置
        this.devList = iPqDevService.getDevInfo(param.getDevIds());

        // 提取所有设备的监测点线路ID
        this.monitorIdList = devList.stream()
                .flatMap(x -> x.getMonitorList().stream())
                .map(PreDetection.MonitorListDTO::getLineId)
                .collect(Collectors.toList());

        // 同步更新系数管理器中的设备列表
        XiNumberManager.xiDevList = devList;
        FormalTestManager.unknownError = false;
        FormalTestManager.currentIssue = null;
    }

}
