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

import com.njcn.gather.detection.handler.SocketSourceResponseService;
import com.njcn.gather.detection.lock.DetectionLockManager;
import com.njcn.gather.detection.pojo.enums.SourceOperateCodeEnum;
import com.njcn.gather.detection.pojo.param.PreDetectionParam;
import com.njcn.gather.detection.util.socket.CnSocketUtil;
import com.njcn.gather.detection.util.socket.SocketManager;
import com.njcn.gather.detection.util.socket.websocket.WebServiceManager;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
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 cn.hutool.core.util.StrUtil;


/**
 * 源设备Netty客户端通道处理器
 * 负责处理程控源设备的Socket通信
 * 
 * @author wr
 * @since 2024/12/10
 */

@Slf4j
@RequiredArgsConstructor
public class NettySourceClientHandler extends SimpleChannelInboundHandler<String> {

    /** 检测参数对象，包含用户页面ID等信息 */
    private final PreDetectionParam webUser;
    /** 源设备响应处理服务 */
    private final SocketSourceResponseService sourceResponseService;

    /**
     * 通道激活回调，将通道注册到SocketManager
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 验证webUser参数有效性
        if (webUser == null) {
            log.warn("源设备客户端通道已建立但webUser为空, channelId: {}", ctx.channel().id());
            return;
        }
        
        String userId = webUser.getUserPageId();
        log.info("源设备客户端通道已建立, channelId: {}, userId: {}", ctx.channel().id(), userId);
        
        // 将通道注册到Socket管理器，便于后续消息推送
        if (StrUtil.isNotBlank(userId)) {
            SocketManager.addUser(userId + CnSocketUtil.SOURCE_TAG, ctx.channel());
        } else {
            log.warn("源设备userId为空或空白，跳过通道注册, channelId: {}", ctx.channel().id());
        }
    }

    /**
     * 通道断开回调，清理资源
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        String userId = webUser != null ? webUser.getUserPageId() : "unknown";
        log.warn("源通讯客户端断线, channelId: {}, userId: {}", ctx.channel().id(), userId);
        // 关闭通道连接
        ctx.close();
        // 从Socket管理器中移除用户通道映射
        if (webUser != null && StrUtil.isNotBlank(userId)) {
            String key = userId + CnSocketUtil.SOURCE_TAG;
            if (SocketManager.isActiveClosing(key)) {
                SocketManager.removeMapping(key);
                return;
            }
            SocketManager.removeUser(key);
            // 源端主动断开 → 本次检测视为结束，释放检测锁
            DetectionLockManager.getInstance()
                    .releaseIfMatchPage(userId, "SOURCE_CHANNEL_INACTIVE");
        }
    }


    /**
     * 处理源设备响应消息
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws InterruptedException {
        // 验证用户参数
        if (webUser == null) {
            log.warn("源设备消息处理失败: webUser为空, message: {}", msg);
            return;
        }
        
        String userId = webUser.getUserPageId();
        log.info("source接收server端数据, userId: {}, message: {}", userId, msg);
        
        try {
            // 委托给专门的响应处理服务处理业务逻辑
            sourceResponseService.deal(webUser, msg);
        } catch (Exception e) {
            log.error("源设备消息处理异常, userId: {}, message: {}", userId, msg, e);
            // 发生异常时退出发送，避免后续问题
            CnSocketUtil.quitSend(webUser);
            // 业务消息处理异常 → 释放检测锁
            if (StrUtil.isNotBlank(userId)) {
                DetectionLockManager.getInstance()
                        .releaseIfMatchPage(userId, "SOURCE_READ_EXCEPTION");
            }
        }
    }


    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        // 记录处理器添加事件，用于调试
        String userId = webUser != null ? webUser.getUserPageId() : "unknown";
        log.debug("源设备通道准备接入, channelId: {}, userId: {}", ctx.channel().id(), userId);
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        String userId = webUser != null ? webUser.getUserPageId() : "unknown";
        String channelId = ctx.channel().id().toString();
        if (StrUtil.isNotBlank(userId) && SocketManager.isActiveClosing(userId + CnSocketUtil.SOURCE_TAG)) {
            log.debug("ignore source exception during active close, channelId: {}, userId: {}", channelId, userId);
            ctx.close();
            return;
        }
        
        // 根据异常类型进行分类处理和日志记录
        if (cause instanceof ConnectException) {
            // 连接异常：网络连接失败
            log.error("连接源设备Socket服务端异常, channelId: {}, userId: {}", channelId, userId, cause);
        } else if (cause instanceof IOException) {
            // IO异常：数据传输错误，需通知前端
            log.error("源设备IO异常, channelId: {}, userId: {}", channelId, userId, cause);
            // 向前端发送服务器错误消息
            if (StrUtil.isNotBlank(userId) && !"unknown".equals(userId)) {
                WebServiceManager.sendDetectionErrorMessage(userId, SourceOperateCodeEnum.SERVER_ERROR);
            }
        } else if (cause instanceof TimeoutException) {
            // 超时异常：通信响应超时
            log.warn("源设备通信超时, channelId: {}, userId: {}", channelId, userId, cause);
        } else if (cause instanceof ProtocolException) {
            // 协议异常：数据格式不符合协议规范
            log.error("源设备协议异常, channelId: {}, userId: {}", channelId, userId, cause);
        } else {
            // 其他未知异常
            log.error("源设备未知异常, channelId: {}, userId: {}, message: {}", channelId, userId, cause.getMessage(), cause);
        }
        
        // 发生异常时关闭通道
        ctx.close();

        // 源通道异常 → 释放检测锁
        String userIdForRelease = webUser != null ? webUser.getUserPageId() : null;
        if (StrUtil.isNotBlank(userIdForRelease)) {
            DetectionLockManager.getInstance()
                    .releaseIfMatchPage(userIdForRelease, "SOURCE_EXCEPTION");
        }
    }

}
