package org.framework.lazy.cloud.network.heartbeat.server.context;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.epoll.EpollDatagramChannel;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.internal.SystemPropertyUtil;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.framework.lazy.cloud.network.heartbeat.common.context.SocketApplicationListener;
import org.framework.lazy.cloud.network.heartbeat.server.netty.udp.filter.NettyUdpServerFilter;
import org.framework.lazy.cloud.network.heartbeat.server.properties.ServerNodeProperties;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class NettyUdpServerSocketApplicationListener implements SocketApplicationListener {

    private final EventLoopGroup bossGroup = "linux".equalsIgnoreCase(SystemPropertyUtil.get("os.name")) ? new EpollEventLoopGroup() : new NioEventLoopGroup();
    private final NettyUdpServerFilter nettyUdpServerFilter;// 通道业务处理
    private ChannelFuture channelFuture;
    private final ServerNodeProperties serverNodeProperties;

    public NettyUdpServerSocketApplicationListener(NettyUdpServerFilter nettyUdpServerFilter, ServerNodeProperties serverNodeProperties) {
        this.nettyUdpServerFilter = nettyUdpServerFilter;
        this.serverNodeProperties = serverNodeProperties;
    }

    /**
     * 根据操作系统获取 Channel
     *
     * @return Class<Channel>
     */
    public Class<? extends Channel> channelClassWithOS() {
        String osName = SystemPropertyUtil.get("os.name").toLowerCase();
        if ("linux".equals(osName)) {
            return EpollDatagramChannel.class;
        } else {
            return NioDatagramChannel.class;
        }
    }

    /**
     * 启动Server
     */
    @Override
    public void doRunning() {
        try {
            ServerNodeProperties.Udp udp = serverNodeProperties.getUdp();
            Integer udpPort = udp.getPort();
            Class<? extends Channel> channelledClassWithOS = channelClassWithOS();
            Bootstrap b = new Bootstrap();
            b.group(bossGroup)
//                    .channel(channelledClassWithOS)
                    .channel(NioDatagramChannel.class)
                    .option(ChannelOption.SO_BROADCAST, true)
                    //接收缓存区  10M
                    .option(ChannelOption.SO_RCVBUF, 1024 * 1024 * 10)
                    //发送缓存区  10M
                    .option(ChannelOption.SO_SNDBUF, 1024 * 1024 * 10)
                    .handler(nettyUdpServerFilter);
            channelFuture = b.bind(udpPort).sync();

            channelFuture.addListener((ChannelFutureListener) channelFuture -> {
                // 服务器已启动
                log.info("UDP 服务器启动成功");
            });
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            log.error("UDP 服务启动失败", e);
        }
    }

    /**
     * 销毁资源
     */
    @PreDestroy
    public void destroy() {
        if (channelFuture != null) {
            channelFuture.channel().close().syncUninterruptibly();
        }
        if ((bossGroup != null) && (!bossGroup.isShutdown())) {
            bossGroup.shutdownGracefully();
        }
        log.info("UDP 服务关闭成功");
    }

}