package com.namelessmc.plugin.common;

import com.github.mizosoft.methanol.Methanol;
import com.github.mizosoft.methanol.WritableBodyPublisher;
import com.google.gson.JsonObject;
import com.namelessmc.plugin.common.command.AbstractScheduledTask;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.configurate.ConfigurationNode;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URI;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.UUID;
import java.util.zip.GZIPOutputStream;

public class Metrics implements Reloadable {

	// TODO actual uri
	private static final URI SUBMIT_URI = URI.create("https://metrics.namelessmc.com/plugin");
	private static final String USER_AGENT = "Nameless-Plugin/" + MavenConstants.PROJECT_VERSION;
	private static final Duration SEND_INTERVAL = Duration.ofMinutes(10);

	private final NamelessPlugin plugin;
	private final String platformInternalName;
	private final String platformVersion;
	private final Methanol methanol;

	private @Nullable AbstractScheduledTask task;

	public Metrics(NamelessPlugin plugin, String platformInternalName, String platformVersion) {
		this.plugin = plugin;
		this.platformInternalName = platformInternalName;
		this.platformVersion = platformVersion;
		this.methanol = Methanol.newBuilder().defaultHeader("User-Agent", USER_AGENT).build();

		this.plugin.properties().registerProperty("metrics-id", () -> UUID.randomUUID().toString());
		this.plugin.properties().registerProperty("metrics-debug", () -> "false");
	}

	public void sendMetrics() {
		String metricsId = this.plugin.properties().get("metrics-id");

		// Format defined here: https://github.com/NamelessMC/Nameless-Plugin/wiki/Metrics
		JsonObject json = new JsonObject();
		json.addProperty("id", metricsId);
		json.addProperty("version", MavenConstants.PROJECT_VERSION);

		JsonObject platform = new JsonObject();
		platform.addProperty("internal-name", this.platformInternalName);
//		platform.addProperty("external-name", this.platformExternalName);
		platform.addProperty("version", this.platformVersion);
		platform.addProperty("java-version", Runtime.version().feature());
		json.add("platform", platform);

		JsonObject system = new JsonObject();
		system.addProperty("os", System.getProperty("os.name"));
		json.add("system", system);

		JsonObject stats = new JsonObject();
		stats.addProperty("api-working", this.plugin.apiProvider().isApiWorkingMetric());
		json.add("stats", stats);

		ConfigurationNode config = this.plugin.config().main();
		ConfigurationNode modules = this.plugin.config().modules();
		JsonObject settings = new JsonObject();
		settings.addProperty("language", this.plugin.language().getActiveLanguageCode());
		settings.addProperty("server-data-sender", config.node("server-data-sender", "enabled").getBoolean());
		settings.addProperty("server-data-sender-placeholders", config.node("server-data-sender", "placeholders", "enabled").getBoolean());
		settings.addProperty("auto-ban-on-website", config.node("auto-ban-on-website").getBoolean());
		settings.addProperty("not-registered-join-message", config.node("not-registered-join-message").getBoolean());
		settings.addProperty("user-sync-whitelist", config.node("user-sync", "whitelist", "enabled").getBoolean());
		settings.addProperty("user-sync-bans", config.node("user-sync", "bans", "enabled").getBoolean());
		settings.addProperty("announcements", config.node("announcements", "enabled").getBoolean());
		settings.addProperty("websend-command-executor", modules.node("websend", "command-executor", "enabled").getBoolean());
		settings.addProperty("websend-send-logs", modules.node("websend", "send-logs", "enabled").getBoolean());
		json.add("settings", settings);

		final String jsonString = json.toString();

		boolean debug = this.plugin.properties().get("metrics-debug").equals("true");

		if (debug) {
			this.plugin.logger().info("Sending metrics: " + jsonString);
		}

		this.plugin.scheduler().runAsync(() -> {
			WritableBodyPublisher body = WritableBodyPublisher.create();
			HttpRequest request = HttpRequest.newBuilder(SUBMIT_URI)
					.POST(body)
					.build();

			this.plugin.scheduler().runAsync(() -> {
				try (Writer writer = new OutputStreamWriter(new GZIPOutputStream(body.outputStream()), StandardCharsets.UTF_8)) {
					writer.write(jsonString);
				} catch (IOException e) {
					body.closeExceptionally(e);
				}
			});

			this.plugin.scheduler().runAsync(() -> {
				try {
					this.methanol.send(request, HttpResponse.BodyHandlers.discarding());
				} catch (Exception e) {
					if (debug) {
						e.printStackTrace();
					}
				}
			});
		});
	}

	@Override
	public void reload() {
		if (this.task == null) {
			this.task = this.plugin.scheduler().runTimer(this::sendMetrics, SEND_INTERVAL);
		}
	}

}

@@ -1677,30 +1677,37 @@
 %0A%0A%09p
-ublic void sendM
+rivate JsonObject m
 etrics
+Json
 () %7B
@@ -3881,16 +3881,64 @@
 ings);%0A%0A
+%09%09return json;%0A%09%7D%0A%0A%09public void sendMetrics() %7B%0A
 %09%09final 
@@ -3957,20 +3957,34 @@
 tring = 
-j
+this.metricsJ
 son
+()
 .toStrin
@@ -4632,59 +4632,13 @@
 %09%09%09t
-his.plugin.scheduler().runAsync(() -%3E %7B%0A%09%09%09%09try %7B%0A%09
+ry %7B%0A
 %09%09%09%09
@@ -4705,25 +4705,24 @@
 ding());%0A%09%09%09
-%09
 %7D catch (Exc
@@ -4729,25 +4729,24 @@
 eption e) %7B%0A
-%09
 %09%09%09%09if (debu
@@ -4755,17 +4755,16 @@
  %7B%0A%09%09%09%09%09
-%09
 e.printS
@@ -4784,24 +4784,15 @@
 %09%09%09%09
-%09
 %7D%0A
-%09
 %09%09%09%7D%0A
-%09%09%09%7D);%0A
 %09%09%7D)

remove nested async