package com.wdkl.ncs.s433.transbox.tcp;

import android.util.Log;

import com.wdkl.ncs.s433.transbox.common.Constants;

import org.greenrobot.eventbus.EventBus;

import java.util.concurrent.TimeUnit;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
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.NioSocketChannel;
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;

public class TcpClient {
    private String TAG = TcpClient.class.getSimpleName();

    private NioEventLoopGroup workGroup;
    public Channel channel;
    private Bootstrap bootstrap;
    //客户端是否启动
    private volatile boolean isRunning = false;
    //数据处理
    private  TcpClientHandler tcpClientHandler = new TcpClientHandler();
    //重试间隔
    private Integer retrySeconds = 5;
    //重试计数
    private Integer retryTimes = 1;
    private Integer reconnetTimes = 0;


    //单例
    private static class TcpClientHolder {
        private static TcpClient instance = new TcpClient();
    }

    public static TcpClient getInstance() {
        return TcpClientHolder.instance;
    }

    //初始化Netty Tcp Client 并连接
    public void init(String serverIP, Integer serverPort, Integer heartBeatSeconds) {
        final Integer hbSeconds = heartBeatSeconds;
        workGroup = new NioEventLoopGroup();
        bootstrap = new Bootstrap();
        bootstrap.group(workGroup)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 15 * 1000)
                .option(ChannelOption.SO_KEEPALIVE, true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        // 这里将LengthFieldBasedFrameDecoder添加到pipeline的首位，因为其需要对接收到的数据
                        // 进行长度字段解码，这里也会对数据进行粘包和拆包处理
                        socketChannel.pipeline().addLast(new LengthFieldBasedFrameDecoder(2048, 0, 2, 0, 2));
                        // LengthFieldPrepender是一个编码器，主要是在响应字节数据前面添加字节长度字段
                        socketChannel.pipeline().addLast(new LengthFieldPrepender(2));
                        //心跳包应当小于服务器间隔
                        socketChannel.pipeline().addLast(new IdleStateHandler(hbSeconds*2, hbSeconds, 0, TimeUnit.SECONDS));
                        socketChannel.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));
                        socketChannel.pipeline().addLast(new StringEncoder(CharsetUtil.UTF_8));
                        socketChannel.pipeline().addLast(tcpClientHandler);
                    }
                }).remoteAddress(serverIP, serverPort);
        doConnect();
        isRunning=true;
    }

    //独立连接方法，用于重新连接
    public synchronized void doConnect() {
        if (channel != null && channel.isActive()) {
            System.out.println("TcpClient connecting");
            return;
        }

        System.out.println("TcpClient connect start");
        ChannelFuture future = bootstrap.connect().addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(final ChannelFuture channelFuture) throws Exception {
                if (channelFuture.isSuccess()) {
                    channel = channelFuture.channel();
                    retryTimes = 1;
                    System.out.println("TcpClient connect success");
                } else {
                    //连接失败时的处理
                    System.out.println("TcpClient connect retry : " + retryTimes);
                    channelFuture.channel().eventLoop().schedule(new Runnable() {
                        @Override
                        public void run() {
                            retryTimes++;
                            if (retryTimes > 30) { //重试30次还没连成功，等10分钟后再试
                                retryTimes=1;
                                reconnetTimes++;
                                channelFuture.channel().eventLoop().schedule(new Runnable() {
                                    @Override
                                    public void run() {
                                        System.out.println("TcpClientHandler 重新连接，第" + retryTimes + "次" + ", 重试" + reconnetTimes + "次");
                                        if (reconnetTimes > 2) {
                                            EventBus.getDefault().post(new EventBusModel(Constants.EVENT_RESTART_APP, 0));
                                        } else {
                                            doConnect();
                                        }
                                    }
                                }, 60*2, TimeUnit.SECONDS);

                            }else{
                                doConnect();
                            }

                        }
                    }, 5, TimeUnit.SECONDS);
                }
            }
        });
    }


    public synchronized void closeClient(){
        try {
            if(channel!=null){
                channel.close();
            }
        } finally {
            workGroup.shutdownGracefully();
            isRunning=false;
        }
    }

    public boolean isRunning() {
        return isRunning;
    }


    //发送消息，线程安全
    public synchronized void sendMsg(String content) {
        Log.e(TAG, "发送的数据 " + content);
        if (tcpClientHandler != null) {
            tcpClientHandler.sendMsg(content);
        }
    }
}