package com.njcn.gather.detection.util.socket.cilent;

import cn.hutool.core.util.ObjectUtil;
import com.njcn.gather.detection.handler.SocketContrastResponseService;
import com.njcn.gather.detection.lock.DetectionLockManager;
import com.njcn.gather.detection.pojo.enums.SourceOperateCodeEnum;
import com.njcn.gather.detection.pojo.enums.SourceResponseCodeEnum;
import com.njcn.gather.detection.pojo.param.PreDetectionParam;
import com.njcn.gather.detection.pojo.vo.SocketDataMsg;
import com.njcn.gather.detection.util.socket.CnSocketUtil;
import com.njcn.gather.detection.util.socket.FormalTestManager;
import com.njcn.gather.detection.util.socket.MsgUtil;
import com.njcn.gather.detection.util.socket.SocketManager;
import com.njcn.gather.detection.util.socket.websocket.WebServiceManager;
import com.njcn.gather.plan.pojo.enums.DataSourceEnum;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.TimeoutException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.ConnectException;
import java.net.ProtocolException;
import java.time.LocalDateTime;
import java.util.Objects;

/**
 * @author caozehui
 * @data 2025-07-25
 */
@Slf4j
@RequiredArgsConstructor
public class NettyContrastClientHandler extends SimpleChannelInboundHandler<String> {


    public static PreDetectionParam param;
    public static SocketContrastResponseService socketContrastResponseService;

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("客户端通道已建立" + ctx.channel().id());
        Channel channel = SocketManager.getChannelByUserId(param.getUserPageId() + CnSocketUtil.CONTRAST_DEV_TAG);
        if (Objects.nonNull(channel)) {
            try {
                channel.close().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        SocketManager.addUser(param.getUserPageId() + CnSocketUtil.CONTRAST_DEV_TAG, ctx.channel());
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws InterruptedException {
        log.info("contrastdevhandler接收server端数据: {}", msg);
        try {
            socketContrastResponseService.deal(param, msg);
        } catch (Exception e) {
            log.error("处理服务端消息异常", e);
//            if (FormalTestManager.currentStep == SourceOperateCodeEnum.RECORD_WAVE_STEP1) {
//                CnSocketUtil.contrastSendquit(param.getUserPageId(), SourceOperateCodeEnum.QUIT_INIT_03, true);
//            } else {
//                CnSocketUtil.contrastSendquit(param.getUserPageId(), SourceOperateCodeEnum.QUIT_INIT_02, true);
//            }
            CnSocketUtil.contrastSendquit(param.getUserPageId(), SourceOperateCodeEnum.QUIT_INIT_01, false);
            CnSocketUtil.contrastSendquit(param.getUserPageId(), SourceOperateCodeEnum.QUIT_INIT_02, false);
            CnSocketUtil.contrastSendquit(param.getUserPageId(), SourceOperateCodeEnum.QUIT_INIT_03, true);
            // 业务消息处理异常 → 释放检测锁
            if (param != null && param.getUserPageId() != null) {
                DetectionLockManager.getInstance()
                        .releaseIfMatchPage(param.getUserPageId(), "CONTRAST_READ_EXCEPTION");
            }
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("与通信模块端断线");
        ctx.close();
        SocketManager.removeUser(param.getUserPageId() + CnSocketUtil.CONTRAST_DEV_TAG);
        // 比对通信模块主动断开 → 本次检测视为结束，释放检测锁
        if (param != null && param.getUserPageId() != null) {
            DetectionLockManager.getInstance()
                    .releaseIfMatchPage(param.getUserPageId(), "CONTRAST_CHANNEL_INACTIVE");
        }
    }

    /**
     * 用户事件的回调方法（自定义事件用于心跳机制）
     *
     * @param ctx
     * @param evt
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
        if (evt instanceof IdleStateEvent) { //IdleState.在一段时间内没有收到任何消息时，会触发该事件
            if (((IdleStateEvent) evt).state() == IdleState.READER_IDLE) {
                if (FormalTestManager.isTesting) {
                    System.out.println(LocalDateTime.now() + "contrastClientHandler触发读超时函数**************************************");

                    if (!FormalTestManager.isRemoveSocket && ObjectUtil.isNotNull(FormalTestManager.nonWaveDataSourceEnum)) {
                        long time = SocketManager.contrastClockMap.get(FormalTestManager.nonWaveDataSourceEnum) + 60L;
                        SocketManager.contrastClockMap.put(FormalTestManager.nonWaveDataSourceEnum, time);

                        if (FormalTestManager.isPstData) {
                            if (time > 60 * 10) {
                                if (DataSourceEnum.REAL_DATA == FormalTestManager.nonWaveDataSourceEnum) {
                                    CnSocketUtil.contrastSendquit(param.getUserPageId(), SourceOperateCodeEnum.QUIT_INIT_02, true);
                                }
                                if (FormalTestManager.isWaveCheck) {
                                    CnSocketUtil.contrastSendquit(param.getUserPageId(), SourceOperateCodeEnum.QUIT_INIT_03, true);
                                }
                                CnSocketUtil.contrastSendquit(param.getUserPageId(), SourceOperateCodeEnum.QUIT_INIT_01, true);
                                timeoutSend(SourceOperateCodeEnum.QUIT_INIT_01);
                            }
                        } else if (DataSourceEnum.REAL_DATA == FormalTestManager.nonWaveDataSourceEnum) {
                            if (time >= 60) {
                                CnSocketUtil.contrastSendquit(param.getUserPageId(), SourceOperateCodeEnum.QUIT_INIT_02, true);
                                timeoutSend(SourceOperateCodeEnum.QUIT_INIT_02);
                            }
                        } else if (time >= FormalTestManager.maxTime) {
                            CnSocketUtil.contrastSendquit(param.getUserPageId(), SourceOperateCodeEnum.QUIT_INIT_01, true);
                            timeoutSend(SourceOperateCodeEnum.QUIT_INIT_01);
                        }
                    }
                }
            }
        }
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        System.out.println("有通道准备接入" + ctx.channel());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        System.out.println("捕获到通信模块服务异常。。。。。。。");
        // 处理异常，例如记录日志、关闭连接等
        cause.printStackTrace();
        // 根据异常类型进行不同的处理
        if (cause instanceof ConnectException) {
            System.out.println("连接socket服务端异常");
        } else if (cause instanceof IOException) {
            System.out.println("IOException caught: There was an I/O error.");
            WebServiceManager.sendDetectionErrorMessage(param.getUserPageId(), SourceOperateCodeEnum.DEVICE_ERROR);
        } else if (cause instanceof TimeoutException) {
            System.out.println("TimeoutException caught: Operation timed out.");
        } else if (cause instanceof ProtocolException) {
            System.out.println("ProtocolException caught: Invalid protocol message.");
        } else {
            // 处理其他类型的异常
            System.out.println("Unknown exception caught: " + cause.getMessage());
            WebServiceManager.sendDetectionErrorMessage(param.getUserPageId(), SourceOperateCodeEnum.DEVICE_ERROR);
        }
        CnSocketUtil.contrastSendquit(param.getUserPageId(), SourceOperateCodeEnum.QUIT_INIT_01, false);
        CnSocketUtil.contrastSendquit(param.getUserPageId(), SourceOperateCodeEnum.QUIT_INIT_02, false);
        CnSocketUtil.contrastSendquit(param.getUserPageId(), SourceOperateCodeEnum.QUIT_INIT_03, true);
        ctx.close();
        // 比对通道异常 → 释放检测锁
        if (param != null && param.getUserPageId() != null) {
            DetectionLockManager.getInstance()
                    .releaseIfMatchPage(param.getUserPageId(), "CONTRAST_EXCEPTION");
        }
    }


    /**
     * 接收数据超时处理
     * 比对模式读超时（10 分钟 Pst / 1 分钟实时 / 动态统计）都汇到这里，
     * 推前端的同时一并释放检测锁（避免锁卡到 4 小时绝对超时）。
     */
    private void timeoutSend(SourceOperateCodeEnum sourceOperateCodeEnum) {
        System.out.println("超时处理-----》" + "统计数据已超时----------------关闭");
        // 向前端推送超时消息
        SocketDataMsg webSend = new SocketDataMsg();
        webSend.setRequestId(sourceOperateCodeEnum.getValue());
        webSend.setData(sourceOperateCodeEnum.getMsg() + SourceResponseCodeEnum.RECEIVE_DATA_TIME_OUT.getMessage());
        webSend.setCode(SourceResponseCodeEnum.RECEIVE_DATA_TIME_OUT.getCode());
        WebServiceManager.sendMsg(param.getUserPageId(), MsgUtil.msgToWebData(webSend, FormalTestManager.devNameMapComm, 0));
        // 比对模式读超时终态 → 释放检测锁
        if (param != null && param.getUserPageId() != null) {
            DetectionLockManager.getInstance()
                    .releaseIfMatchPage(param.getUserPageId(), "CONTRAST_IDLE_TIMEOUT");
        }
    }

}
