package com.zehong.system.netty;

import com.zehong.system.netty.handler.NettyUdpServerHandler;
import org.springframework.stereotype.Component;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
/**
 * @author lenovo
 * @date 2025/7/31
 * @description TODO
 */
@Component
public class NettyUdpServer {
    private static final Logger log = LoggerFactory.getLogger(NettyUdpServer.class);

    @Resource
    private NettyConfig nettyConfig;

    @Resource
    private NettyUdpServerHandler nettyUdpServerHandler;

    private EventLoopGroup group;
    private ChannelFuture channelFuture;

    /**
     * 启动UDP服务器
     */
    public void start() {
        // 避免重复启动
        if (channelFuture != null && channelFuture.channel().isActive()) {
            log.warn("Netty UDP服务器已启动，无需重复启动");
            return;
        }

        try {
            // UDP只需要一个事件循环组
            group = new NioEventLoopGroup(nettyConfig.getWorkerGroupThreadCount());

            // UDP使用Bootstrap而非ServerBootstrap
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    // 设置UDP通道类型
                    .channel(NioDatagramChannel.class)
                    // UDP支持广播
                    .option(ChannelOption.SO_BROADCAST, true)
                    // 设置接收缓冲区大小
                    .option(ChannelOption.SO_RCVBUF, 1024 * 1024)
                    // 设置发送缓冲区大小
                    .option(ChannelOption.SO_SNDBUF, 1024 * 1024)
                    // 设置处理器
                    .handler(new ChannelInitializer<NioDatagramChannel>() {
                        @Override
                        protected void initChannel(NioDatagramChannel ch) throws Exception {
                            ch.pipeline()
                                    // UDP也可以使用心跳检测，但意义不如TCP大
                                    .addLast(new IdleStateHandler(
                                            0,
                                            0,
                                            nettyConfig.getHeartbeatTimeout(),
                                            TimeUnit.SECONDS))
                                    // 帧解码，解决粘包拆包问题
                                    .addLast(new LengthFieldBasedFrameDecoder(
                                            nettyConfig.getMaxFrameLength(),
                                            0, 4, 0, 4))
                                    // 帧编码
                                    .addLast(new LengthFieldPrepender(4))
                                    // 字符串解码
                                    .addLast(new StringDecoder(CharsetUtil.UTF_8))
                                    // 字符串编码
                                    .addLast(new StringEncoder(CharsetUtil.UTF_8))
                                    // 自定义UDP处理器
                                    .addLast(nettyUdpServerHandler);
                        }
                    });

            // 绑定端口，UDP不需要监听连接
            channelFuture = bootstrap.bind(nettyConfig.getPort()).sync();
            log.info("Netty UDP服务器启动成功，监听端口: {}", nettyConfig.getPort());

            // 等待通道关闭
            channelFuture.channel().closeFuture().addListener(future -> {
                log.info("Netty UDP服务器通道关闭");
                stop();
            });

        } catch (Exception e) {
            log.error("Netty UDP服务器启动失败", e);
            stop();
        }
    }

    /**
     * 停止UDP服务器
     */
    @PreDestroy
    public void stop() {
        try {
            if (channelFuture != null) {
                channelFuture.channel().close().sync();
            }
        } catch (Exception e) {
            log.error("Netty UDP通道关闭异常", e);
        } finally {
            if (group != null) {
                group.shutdownGracefully();
            }
            log.info("Netty UDP服务器已停止");
        }
    }

    /**
     * 重启UDP服务器
     */
    public void restart() {
        log.info("准备重启Netty UDP服务器...");
        stop();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        start();
    }
}
