package de.winniepat.citrus.beta;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import de.winniepat.citrus.Client;
import de.winniepat.citrus.managers.ConfigManager;
import de.winniepat.citrus.ModConfig;
import de.winniepat.citrus.utils.SecurityUtils;
import net.minecraft.client.MinecraftClient;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;

public class VerificationClient {
    private static VerificationClient instance;
    private static final Gson GSON = new Gson();

    private String getApiKey() {
        ModConfig.BetaConfig betaConfig = ConfigManager.getBetaConfig();
        if (betaConfig == null) {
            Client.logger.error("Beta config is null, using fallback API key");
            return "ClientF8CjVGn7VTOAhROa65Ot";
        }

        String apiKey = betaConfig.getActiveApiKey();

        if (apiKey == null || apiKey.trim().isEmpty()) {
            Client.logger.error("API key is empty in config, using fallback");
            return "ClientF8CjVGn7VTOAhROa65Ot";
        }

        return apiKey;
    }

    private VerificationClient() {}

    public static synchronized VerificationClient getInstance() {
        if (instance == null) {
            instance = new VerificationClient();
        }
        return instance;
    }

    public VerificationResult verifyKey(String key, String hardwareId) {
        try {
            MinecraftClient client = MinecraftClient.getInstance();
            String playerUUID = String.valueOf(client.getSession().getUuidOrNull());
            String playerName = client.getSession().getUsername();

            String apiUrl = Client.BETA_URL + "/api/verify";
            String apiKey = getApiKey();

            Client.debugLog("Verifying key at: " + apiUrl);
            Client.debugLog("Using API key: " + (apiKey.length() > 8 ?
                    apiKey.substring(0, 8) + "..." : apiKey));

            URL url = new URL(apiUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            setupConnection(conn, apiKey);

            JsonObject request = new JsonObject();
            request.addProperty("key", key);
            request.addProperty("playerUUID", playerUUID);
            request.addProperty("playerName", playerName);
            request.addProperty("hardwareFingerprint", hardwareId);
            request.addProperty("ipAddress", "127.0.0.1");

            Client.debugLog("Sending verification request for key: " + key);
            Client.debugLog("Player: " + playerName + " (" + playerUUID + ")");

            try (OutputStream os = conn.getOutputStream()) {
                byte[] input = request.toString().getBytes(StandardCharsets.UTF_8);
                os.write(input, 0, input.length);
            }

            int responseCode = conn.getResponseCode();
            Client.debugLog("Server response code: " + responseCode);

            if (responseCode == 200) {
                try (BufferedReader br = new BufferedReader(
                        new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
                    String responseText = br.readLine();
                    JsonObject response = GSON.fromJson(responseText, JsonObject.class);

                    Client.debugLog("Response: " + responseText);

                    if (response.get("valid").getAsBoolean()) {
                        Client.debugLog("Key verification successful!");
                        String linkedUsername = response.has("linkedUsername") && !response.get("linkedUsername").isJsonNull()
                                ? response.get("linkedUsername").getAsString() : null;

                        // Validate that the linked username matches the current player
                        if (linkedUsername != null && !linkedUsername.isEmpty() && !linkedUsername.equalsIgnoreCase(playerName)) {
                            Client.logger.warn("Username mismatch! Key is linked to: {}, but current player is: {}", linkedUsername, playerName);
                            return VerificationResult.failure("This key is linked to " + linkedUsername + ", not " + playerName);
                        }

                        return VerificationResult.success(
                                response.get("token").getAsString(),
                                response.get("expiresIn").getAsLong(),
                                key,
                                playerUUID,
                                linkedUsername
                        );
                    } else {
                        String reason = response.has("reason") ?
                                response.get("reason").getAsString() : "Unknown error";
                        Client.logger.warn("Key verification failed: {}", reason);
                        return VerificationResult.failure(reason);
                    }
                }
            } else if (responseCode == 401) {
                Client.logger.error("API key rejected by server. Check your API key in config.");
                return VerificationResult.failure("Invalid API key");
            } else if (responseCode == 404) {
                Client.logger.error("Server endpoint not found. Check API URL in config. URL: {}", url);
                return VerificationResult.failure("Server endpoint not found");
            } else {
                Client.logger.error("Verification failed with HTTP code: {}", responseCode);
                return VerificationResult.failure("Server error: " + responseCode);
            }
        } catch (Exception e) {
            Client.logger.error("Error verifying key: {}", e.getMessage(), e);
            return VerificationResult.failure("Connection error: " + e.getMessage());
        }
    }

    public VerificationResult validateSession(String token) {
        try {
            MinecraftClient client = MinecraftClient.getInstance();
            String currentPlayerName = client.getSession().getUsername();

            String apiUrl = Client.BETA_URL + "/validate-session";
            String apiKey = getApiKey();

            URL url = new URL(apiUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            setupConnection(conn, apiKey);

            JsonObject request = new JsonObject();
            request.addProperty("token", token);

            try (OutputStream os = conn.getOutputStream()) {
                byte[] input = request.toString().getBytes(StandardCharsets.UTF_8);
                os.write(input, 0, input.length);
            }

            int responseCode = conn.getResponseCode();
            if (responseCode == 200) {
                try (BufferedReader br = new BufferedReader(
                        new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
                    JsonObject response = GSON.fromJson(br, JsonObject.class);

                    if (response.get("valid").getAsBoolean()) {
                        String linkedUsername = response.has("playerName") && !response.get("playerName").isJsonNull()
                                ? response.get("playerName").getAsString() : null;

                        // Validate that the linked username matches the current player
                        if (linkedUsername != null && !linkedUsername.isEmpty() && !linkedUsername.equalsIgnoreCase(currentPlayerName)) {
                            Client.logger.warn("Session username mismatch! Session is linked to: {}, but current player is: {}", linkedUsername, currentPlayerName);
                            return VerificationResult.failure("Session is linked to " + linkedUsername + ", not " + currentPlayerName);
                        }

                        return VerificationResult.success(
                                token,
                                (response.get("expiresAt").getAsLong() - System.currentTimeMillis()) / 1000,
                                "SESSION",
                                response.get("playerUUID").getAsString(),
                                linkedUsername
                        );
                    } else {
                        return VerificationResult.failure("Invalid session");
                    }
                }
            } else {
                return VerificationResult.failure("Server error: " + responseCode);
            }
        } catch (Exception e) {
            Client.logger.error("Error validating session", e);
            return VerificationResult.failure("Connection error");
        }
    }

    private void setupConnection(HttpURLConnection conn, String apiKey) throws Exception {
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/json");
        conn.setRequestProperty("x-api-key", apiKey);
        conn.setRequestProperty("x-daily-key", SecurityUtils.getDailyKey());
        conn.setDoOutput(true);
        conn.setConnectTimeout(10000);
        conn.setReadTimeout(10000);
    }
}