package de.winniepat.citrus.managers;

import com.google.gson.*;
import de.winniepat.citrus.Client;
import de.winniepat.citrus.utils.SecurityUtils;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ServerInfo;
import net.minecraft.util.Util;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.CompletableFuture;

public class FriendManager {
    private static final String API_BASE_URL = Client.API_URL;
    private static final Gson GSON = new GsonBuilder().create();

    private static final List<Friend> FRIENDS = Collections.synchronizedList(new ArrayList<>());
    private static final List<FriendRequest> INCOMING_REQUESTS = Collections.synchronizedList(new ArrayList<>());
    
    private static long lastRefresh = 0;
    private static final long REFRESH_INTERVAL = 60000;

    public static void init() {
        refresh();
    }

    public static String getCurrentServerIp() {
        MinecraftClient client = MinecraftClient.getInstance();
        if (client.getCurrentServerEntry() != null) {
            ServerInfo serverInfo = client.getCurrentServerEntry();
            return serverInfo.address;
        }
        return null;
    }

    public static CompletableFuture<Void> updateServerStatus() {
        UUID uuid = getCurrentUuid();
        if (uuid == null) return CompletableFuture.completedFuture(null);

        String serverIp = getCurrentServerIp();

        return CompletableFuture.runAsync(() -> {
            try {
                JsonObject json = new JsonObject();
                json.addProperty("uuid", uuid.toString());
                json.addProperty("serverIp", serverIp != null ? serverIp : "");

                URL url = new URI(API_BASE_URL + "/friends/server").toURL();
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("POST");
                conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
                conn.setRequestProperty("x-daily-key", SecurityUtils.getDailyKey());
                conn.setDoOutput(true);
                conn.setConnectTimeout(5000);
                conn.setReadTimeout(5000);

                try (OutputStream os = conn.getOutputStream()) {
                    os.write(GSON.toJson(json).getBytes(StandardCharsets.UTF_8));
                }

                int responseCode = conn.getResponseCode();
                if (responseCode == 200) {
                    Client.debugLog("Updated server status: " + (serverIp != null ? serverIp : "none"));
                }
                conn.disconnect();
            } catch (Exception e) {
                Client.logger.error("Failed to update server status", e);
            }
        }, Util.getMainWorkerExecutor());
    }

    public static CompletableFuture<Void> refresh() {
        UUID uuid = getCurrentUuid();
        if (uuid == null) return CompletableFuture.completedFuture(null);

        lastRefresh = System.currentTimeMillis();

        return CompletableFuture.allOf(fetchFriends(uuid), fetchIncomingRequests(uuid));
    }

    private static UUID getCurrentUuid() {
        MinecraftClient client = MinecraftClient.getInstance();
        if (client.player != null) return client.player.getUuid();
        if (client.getSession() != null) return client.getSession().getUuidOrNull();
        return null;
    }

    private static CompletableFuture<Void> fetchFriends(UUID uuid) {
        return CompletableFuture.runAsync(() -> {
            try {
                URL url = new URI(API_BASE_URL + "/friends/list/" + uuid.toString()).toURL();
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                conn.setRequestProperty("x-daily-key", SecurityUtils.getDailyKey());
                conn.setConnectTimeout(5000);
                conn.setReadTimeout(5000);

                if (conn.getResponseCode() == 200) {
                    String response = new String(conn.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
                    Friend[] friendsArray = GSON.fromJson(response, Friend[].class);
                    
                    if (friendsArray != null) {
                        synchronized (FRIENDS) {
                            FRIENDS.clear();
                            Collections.addAll(FRIENDS, friendsArray);
                        }
                        Client.debugLog("Fetched " + FRIENDS.size() + " friends");
                    }
                }
                conn.disconnect();
            } catch (Exception e) {
                Client.logger.error("Failed to fetch friends for {}", uuid, e);
            }
        }, Util.getMainWorkerExecutor());
    }

    private static CompletableFuture<Void> fetchIncomingRequests(UUID uuid) {
        return CompletableFuture.runAsync(() -> {
            try {
                URL url = new URI(API_BASE_URL + "/friends/requests/" + uuid.toString()).toURL();
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                conn.setRequestProperty("x-daily-key", SecurityUtils.getDailyKey());
                conn.setConnectTimeout(5000);
                conn.setReadTimeout(5000);

                if (conn.getResponseCode() == 200) {
                    String response = new String(conn.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
                    FriendRequest[] requests = GSON.fromJson(response, FriendRequest[].class);
                    
                    if (requests != null) {
                        synchronized (INCOMING_REQUESTS) {
                            INCOMING_REQUESTS.clear();
                            Collections.addAll(INCOMING_REQUESTS, requests);
                        }
                        Client.debugLog("Fetched " + INCOMING_REQUESTS.size() + " incoming requests");
                    }
                }
                conn.disconnect();
            } catch (Exception e) {
                Client.logger.error("Failed to fetch friend requests for {}", uuid, e);
            }
        }, Util.getMainWorkerExecutor());
    }

    private static CompletableFuture<String> postJson(String endpoint, JsonObject json) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                URL url = new URI(API_BASE_URL + endpoint).toURL();
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("POST");
                conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
                conn.setRequestProperty("x-daily-key", SecurityUtils.getDailyKey());
                conn.setDoOutput(true);
                conn.setConnectTimeout(5000);
                conn.setReadTimeout(5000);

                try (OutputStream os = conn.getOutputStream()) {
                    os.write(GSON.toJson(json).getBytes(StandardCharsets.UTF_8));
                }

                int responseCode = conn.getResponseCode();
                if (responseCode == 200) {
                    conn.disconnect();
                    return null;
                } else {
                    String errorMsg = "Server error (" + responseCode + ")";
                    try (InputStream es = (responseCode >= 400 ? conn.getErrorStream() : conn.getInputStream())) {
                        if (es != null) {
                            String response = new String(es.readAllBytes(), StandardCharsets.UTF_8);
                            JsonObject obj = GSON.fromJson(response, JsonObject.class);
                            if (obj != null && obj.has("error")) {
                                errorMsg = obj.get("error").getAsString();
                            }
                        }
                    }
                    Client.debugLog("Friend Action Failed: " + errorMsg);
                    conn.disconnect();
                    return errorMsg;
                }
            } catch (Exception e) {
                Client.debugLog("Friend Action Exception: " + e.getMessage());
                return "Connection failed: " + e.getMessage();
            }
        }, Util.getMainWorkerExecutor());
    }

    public static CompletableFuture<String> sendRequest(String friendName) {
        UUID uuid = getCurrentUuid();
        if (uuid == null) return CompletableFuture.completedFuture("Not logged in");

        JsonObject json = new JsonObject();
        json.addProperty("uuid", uuid.toString());
        json.addProperty("friendName", friendName);

        return postJson("/friends/request", json);
    }

    public static CompletableFuture<String> acceptRequest(UUID friendUuid) {
        UUID uuid = getCurrentUuid();
        if (uuid == null) return CompletableFuture.completedFuture("Not logged in");

        JsonObject json = new JsonObject();
        json.addProperty("uuid", uuid.toString());
        json.addProperty("friendUuid", friendUuid.toString());

        return postJson("/friends/accept", json).thenCompose(error -> {
            if (error == null) return refresh().thenApply(v -> null);
            return CompletableFuture.completedFuture(error);
        });
    }

    public static CompletableFuture<String> removeFriend(UUID friendUuid) {
        UUID uuid = getCurrentUuid();
        if (uuid == null) return CompletableFuture.completedFuture("Not logged in");

        JsonObject json = new JsonObject();
        json.addProperty("uuid", uuid.toString());
        json.addProperty("friendUuid", friendUuid.toString());

        return postJson("/friends/remove", json).thenCompose(error -> {
            if (error == null) return refresh().thenApply(v -> null);
            return CompletableFuture.completedFuture(error);
        });
    }

    public static List<Friend> getFriends() {
        if (System.currentTimeMillis() - lastRefresh > REFRESH_INTERVAL) {
            refresh();
        }
        synchronized (FRIENDS) {
            return new ArrayList<>(FRIENDS);
        }
    }

    public static List<FriendRequest> getIncomingRequests() {
        synchronized (INCOMING_REQUESTS) {
            return new ArrayList<>(INCOMING_REQUESTS);
        }
    }

    public static class Friend {
        public String player_uuid;
        public String player_name;
        public int is_online;
        public String server_ip;

        public UUID getUuid() {
            return UUID.fromString(player_uuid);
        }
        
        public boolean isOnline() {
            return this.is_online == 1;
        }

        public String getServerDisplay() {
            if (!isOnline() || server_ip == null || server_ip.isEmpty()) {
                return null;
            }
            String display = server_ip;
            if (display.endsWith(":25565")) {
                display = display.substring(0, display.length() - 6);
            }
            return display;
        }
    }

    public static class FriendRequest {
        public String player_uuid;
        public String player_name;

        public UUID getUuid() {
            return UUID.fromString(player_uuid);
        }
    }
}
