package com.cisdi.data.caliper.gateway;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;

@Slf4j
public class CaliperClient {
    @Setter
    @Getter
    private volatile Channel channel = null;
    @Setter
    @Getter
    private Long lastHeartbeatTime = System.currentTimeMillis();
    private EventLoopGroup workerGroup = null;
    private final CaliperTaskStartVo startVo;

    public CaliperClient(CaliperTaskStartVo startVo) {
        this.startVo = startVo;

        if (Epoll.isAvailable()) {
            log.info("Caliper enable epoll and have tcp SO_KEEPALIVE check");
        } else {
            log.info("Caliper disable epoll and not have custom SO_KEEPALIVE check");
        }
    }

    public boolean close() {
        boolean result = false;
        if (workerGroup == null && channel == null) {
            return true;
        }

        if (channel != null) {
            try {
                channel.close().sync();
                channel = null;
                result = true;
            } catch (Exception e) {
                log.error(e.getLocalizedMessage(), e);
            }
        }

        if (workerGroup != null) {
            try {
                workerGroup.shutdownGracefully().sync();
                workerGroup = null;
                result = true;
            } catch (InterruptedException e) {
                log.error("Caliper到 {} : {} 的连接关闭失败",
                        startVo.getSocketParam().getPeerIp(), startVo.getSocketParam().getPeerPort(), e);
            }
        }

        if (channel != null || workerGroup != null) {
            log.info("channel:{},workgoup:{}", channel, workerGroup);
        }

        return result;
    }

    public void run() throws IOException {
        start();
    }

    private void start() {
        lastHeartbeatTime = System.currentTimeMillis();
        if (channel != null) {
            close();
        }

        //设置一个多线程循环器
        //启动附注类
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.option(ChannelOption.SO_KEEPALIVE, true);

        if (Epoll.isAvailable()) {
            bootstrap.channel(EpollSocketChannel.class);
            bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
            bootstrap.option(EpollChannelOption.TCP_KEEPIDLE, 10);
            bootstrap.option(EpollChannelOption.TCP_KEEPINTVL, 5);
            bootstrap.option(EpollChannelOption.TCP_KEEPCNT, 2);
            workerGroup = new EpollEventLoopGroup(2);
        } else {
            workerGroup = new NioEventLoopGroup(2);
            bootstrap.channel(NioSocketChannel.class);
        }

        bootstrap.group(workerGroup);
        //指定所使用的NIO传输channel
        //指定客户端初始化处理
        bootstrap.handler(new CaliperClientInitializer(startVo, this));
        try {
            channel = bootstrap.connect(startVo.getSocketParam().getPeerIp(),
                    startVo.getSocketParam().getPeerPort()).sync().channel();
            //channel.closeFuture().sync();  // 如果会话关闭，会退出当前线程
        } catch (InterruptedException e) {
            log.warn(e.getMessage(), e);
        }
    }

    public void reconnect() {
        log.info("Caliper重新连接中......{}:{}", getIp(), getPort());
        close();
        start();
    }

    public String getIp() {
        return startVo.getSocketParam().getPeerIp();
    }

    public int getPort() {
        return startVo.getSocketParam().getPeerPort();
    }

}
