package com.its.op.xnettcp.client;

import com.its.op.xnettcp.client.codec.NettyTcpClientDecoder;
import com.its.op.xnettcp.client.codec.NettyTcpClientEncoder;
import com.its.op.xnettcp.client.handler.NettyTcpClientIdleHandler;
import com.its.op.xnettcp.client.handler.NettyTcpClientInboundHandler;
import com.its.utils.NettyUtils;
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.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

@Slf4j
@RequiredArgsConstructor
public class NettyTcpClientVdsBootstrapFactory {

    private final int workerThread;
    private final int connectTimeout;
    private EventLoopGroup nioEventLoopGroup = null;

    public Bootstrap createBootstrap() {
        if (this.nioEventLoopGroup == null) {
            this.nioEventLoopGroup = NettyUtils.newEventLoopGroup(this.workerThread, "vdsEventGroup");//new NioEventLoopGroup(this.workerThread);  //EpollEventLoopGroup
        }
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(this.nioEventLoopGroup);

        bootstrap.channel(NioSocketChannel.class);
        bootstrap.option(ChannelOption.AUTO_READ, true);
        bootstrap.option(ChannelOption.TCP_NODELAY, true);
        bootstrap.option(ChannelOption.SO_RCVBUF, 8192);
        bootstrap.option(ChannelOption.SO_SNDBUF, 8192);
        bootstrap.option(ChannelOption.SO_KEEPALIVE, false);
        bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, this.connectTimeout * 1000);
        bootstrap.handler(new ChannelInitializer<SocketChannel>() {
            // VDS 전송 요청을 먼저하고 데이터를 수신한다.
            // 핸들러가 실행되는 순서는 추가된 순서에 의해 결정된다.(Inbound: head=>tail, Outbound: tail=>head, name2ctx)
            @Override
            public void initChannel(SocketChannel ch) {
                ch.pipeline().addLast(new LoggingHandler(LogLevel.WARN));
                ch.pipeline().addLast("vdsClientIdleHandler",    new NettyTcpClientIdleHandler(0, 0, 0, TimeUnit.SECONDS));
                ch.pipeline().addLast("vdsClientDecoder",        new NettyTcpClientDecoder());            // Decoding handler
                ch.pipeline().addLast("vdsClientInboundHandler", new NettyTcpClientInboundHandler());     // Packet Inbound handler
                ch.pipeline().addLast("vdsClientEncoder",        new NettyTcpClientEncoder());            // Encoding handler
            }
        });

        return bootstrap;
    }

    public void addChannelFuture(ChannelFuture future) {
        //this.channelFutures.add(future);
    }
}
