package cn.reghao.bnt.agent;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import cn.reghao.bnt.agent.config.ConfigFile;
import cn.reghao.bnt.agent.config.DagentConfig;
import cn.reghao.bnt.agent.task.ImageCleanTask;
import cn.reghao.bnt.agent.ws.WsClient;
import cn.reghao.bnt.common.agent.app.iface.AppDeploy;
import cn.reghao.bnt.common.agent.app.iface.AppStat;
import cn.reghao.bnt.common.agent.app.iface.impl.AppDeployImpl;
import cn.reghao.bnt.common.agent.app.iface.impl.AppStatImpl;
import cn.reghao.bnt.common.agent.app.iface.impl.DockerApp;
import cn.reghao.bnt.common.docker.Docker;
import cn.reghao.bnt.common.docker.DockerImpl;
import cn.reghao.bnt.common.msg.MessageSender;
import cn.reghao.jutil.jdk.serializer.JsonConverter;
import cn.reghao.jutil.jdk.string.StringRegexp;
import cn.reghao.jutil.jdk.thread.ThreadPoolWrapper;
import cn.reghao.jutil.jdk.util.SingleInstance;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Slf4j
public class AgentApp {
	static MessageSender messageSender;
	static ScheduledExecutorService scheduler = ThreadPoolWrapper.scheduledThreadPool("heartbeat", 5);
	static Docker docker = new DockerImpl();

	static void setLogLevel() {
		LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
		Logger rootLogger = loggerContext.getLogger("ROOT");
		rootLogger.setLevel(Level.INFO);
		//LoggerConfig.initLogger(Appenders.fileAppender());
	}
	
	static boolean tryConnect(String host, int port) {
		try {
			boolean isAddress = StringRegexp.matchIPv4Address(host);
			InetAddress inetAddress;
			if (isAddress) {
				inetAddress = InetAddress.getByAddress(host.getBytes(StandardCharsets.UTF_8));
			} else {
				inetAddress = InetAddress.getByName(host);
			}

			InetSocketAddress socketAddress = new InetSocketAddress(inetAddress, port);
			Socket socket = new Socket();
			socket.connect(socketAddress);
			return true;
		} catch (IOException e) {
			log.error("尝试建立到 {}:{} 的 Socket 连接失败", host, port);
		}
		return false;
	}

	static MessageSender getMessageSender(DagentConfig dagentConfig) {
		DockerApp dockerApp = new DockerApp(docker);
		AppDeploy appDeploy = new AppDeployImpl(dockerApp);
		AppStat appStat = new AppStatImpl(dockerApp);

		if (tryConnect(dagentConfig.getHost(), dagentConfig.getPort())) {
			messageSender = new WsClient(dagentConfig, scheduler, appDeploy, appStat);
			return messageSender;
		}

		return null;
	}

	static void shutdownGracefully() {
		Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook(), "main-shutdown-hook"));
	}

	static class ShutdownHook implements Runnable {
		@Override
		public void run() {
			messageSender.close();
			log.info("资源清理完成，结束 devops-agent...");
		}
	}

	public static void main(String[] args) {
		setLogLevel();
		if (args.length != 1) {
			log.error("必须指定配置文件...");
			return;
		}

		String configFilePath = ConfigFile.configFilePath(args[0], AgentApp.class);
		DagentConfig dagentConfig = JsonConverter.jsonFileToObject(new File(configFilePath), DagentConfig.class);
		messageSender = getMessageSender(dagentConfig);
		if (messageSender == null) {
			log.error("没有可用的 MessageSender, Agent 结束运行, 具体信息请查看日志");
			System.exit(-1);
		} else {
			messageSender.connect();
		}

		ImageCleanTask cleanTask = new ImageCleanTask(docker);
		scheduler.scheduleAtFixedRate(cleanTask, 1, 12, TimeUnit.HOURS);
		shutdownGracefully();
		SingleInstance.onlyOne(60001);
	}
}
