package com.inzy.wsmock


import io.netty.bootstrap.ServerBootstrap
import io.netty.channel.ChannelInitializer
import io.netty.channel.ChannelOption
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.SocketChannel
import io.netty.channel.socket.nio.NioServerSocketChannel
import io.netty.handler.codec.http.HttpObjectAggregator
import io.netty.handler.codec.http.HttpServerCodec
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler
import io.netty.handler.stream.ChunkedWriteHandler
import io.netty.util.concurrent.DefaultThreadFactory
import jakarta.annotation.PostConstruct
import jakarta.annotation.PreDestroy
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import lombok.extern.slf4j.Slf4j
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
import java.net.BindException
import java.net.InetSocketAddress
import java.net.ServerSocket

@Slf4j
@Component
class

NettyWebSocketServer(
    @Value("\${netty.websocket.port:8089}") private val port: Int,
    private val webSocketHandler: WebSocketHandler
) {

    private val logger = LoggerFactory.getLogger(javaClass)

    private val websocketPath = "/ws"

    // Netty主从线程组
    private val bossGroup = NioEventLoopGroup(1)
    private val workerThreadNum = 1
    private val workerGroup = NioEventLoopGroup(workerThreadNum, DefaultThreadFactory("netty-worker-thread"))

    // 保存Netty服务的ChannelFuture，用于优雅关闭
    private var serverChannelFuture: io.netty.channel.ChannelFuture? = null

    /**
     * 启动Netty WebSocket服务（异步执行，避免阻塞Spring主线程）
     */
    @PostConstruct
    fun start() {
        // 🔥 关键修改：使用新线程启动Netty，不阻塞Spring初始化
        CoroutineScope(Dispatchers.IO).launch {
            try {
                val bootstrap = ServerBootstrap()
                bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel::class.java)
                    .option(ChannelOption.SO_BACKLOG, 8192)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childHandler(object : ChannelInitializer<SocketChannel>() {
                        override fun initChannel(ch: SocketChannel) {
                            val pipeline = ch.pipeline()
                            pipeline.addLast(HttpServerCodec())
                            pipeline.addLast(ChunkedWriteHandler())
                            pipeline.addLast(HttpObjectAggregator(1024 * 1024))
                            pipeline.addLast(RequestParamHandler())  // 添加HTTP请求拦截器
                            pipeline.addLast(WebSocketServerProtocolHandler(websocketPath))
                            pipeline.addLast(webSocketHandler)
                            // 调试：打印处理器链顺序，确认RequestParamHandler在正确位置
//                            logger.info("ChannelPipeline顺序：${pipeline.map { it.javaClass.simpleName }}")
                        }
                    })
                // 检测端口是否被占用
                val isPortAvailable = InetSocketAddress(port).let {
                    ServerSocket().use { socket ->
                        try {
                            socket.bind(it)
                            true
                        } catch (e: BindException) {
                            false
                        }
                    }
                }
                if (!isPortAvailable) {
                    logger.error("端口$port 已被占用，启动失败！")
                    return@launch
                }
                // 绑定端口并启动（非阻塞？不，这里sync()只阻塞当前新线程，不阻塞Spring主线程）
                serverChannelFuture = bootstrap.bind(port).sync()
                logger.info("Netty WebSocket服务启动成功，端口：$port")

                // 阻塞当前新线程（而非Spring主线程）直到服务关闭
                serverChannelFuture?.channel()?.closeFuture()?.sync()
            } catch (e: Exception) {
                logger.error("Netty服务启动失败", e)
            } finally {
                // 优雅关闭线程组
                bossGroup.shutdownGracefully()
                workerGroup.shutdownGracefully()
                logger.info("Netty线程组已关闭")
            }
        }
    }

    /**
     * 销毁时关闭Netty服务
     */
    @PreDestroy
    fun stop() {
        // 主动关闭Netty服务，解除closeFuture的阻塞
        serverChannelFuture?.channel()?.close()?.sync()
        bossGroup.shutdownGracefully()
        workerGroup.shutdownGracefully()
        logger.info("Netty WebSocket服务已关闭")
    }
}