package com.docus.server.common.netty.client;

import com.docus.server.common.CommMsg;
import com.docus.server.common.netty.event.StartUpEvent;
import com.docus.server.common.netty.server.CollectorChannelCacheMap;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * Created by 1-point at 2021/9/7
 * Netty客户端
 */
@Slf4j
@Component
public class NettyClient {

    @Resource
    private NettyClientProperties nettyProperties;

    @Value("${spring.application.name}")
    private String appName;

    @Value("${docus.terminal-restart-bat}")
    private String terminalRestartBat;

    private SocketChannel socketChannel;

    @Resource
    private CollectorChannelCacheMap collectorChannelCacheMap;

    @Value("${docus.collector-package-download-savePath:H://packages/}")
    private String saveCollectorPackagePath;
    @Resource
    private StringRedisTemplate template;
    @Resource
    private Environment env;
    @Resource
    private ApplicationContext applicationContext;

    /**
     * 发送消息给服务端
     *
     * @param message 消息内容
     */
    public void sendMessage(CommMsg message) {
        boolean success = socketChannel.writeAndFlush(message).isSuccess();
        if (success) {
            log.info("发送消息成功");
        }
    }

    /**
     * 发送消息给服务端
     *
     * @param message 消息内容
     */
    public void publishEvent(String message, CommMsg commMsg) {
        applicationContext.publishEvent(new StartUpEvent(this, message, commMsg));
    }

    @PostConstruct
    public void start() {
        final EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group)
            .channel(NioSocketChannel.class)
            .remoteAddress(nettyProperties.getHost(), nettyProperties.getPort())
            .option(ChannelOption.SO_KEEPALIVE, true)
            .option(ChannelOption.TCP_NODELAY, true)
            .handler(new NettyClientInitializer(nettyProperties, this, appName));
        ChannelFuture future = bootstrap.connect();
        //客户端断线重连逻辑
        future.addListener((ChannelFutureListener) status -> {
            if (status.isSuccess()) {
                log.info("连接Netty服务端成功");
            } else {
                log.warn("连接失败，进行断线重连");
                status.channel().eventLoop().schedule(this::start, nettyProperties.getReconnectSeconds(), TimeUnit.SECONDS);
            }
        });
        socketChannel = (SocketChannel) future.channel();
    }

    public String getRedisMsg() {
        return template.opsForValue().get("docus:collectorsPackagesDownload:" + env.getProperty("server.port"));
    }

    public CollectorChannelCacheMap getCollectorChannelCacheMap() {
        return collectorChannelCacheMap;
    }

    public String getSaveCollectorPackagePath() {
        return saveCollectorPackagePath;
    }

    public String getAppName() {
        return this.appName;
    }

    public String getTerminalRestartBat() {
        return this.terminalRestartBat;
    }
}
