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.util.Util;

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;
import java.util.concurrent.ConcurrentHashMap;

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

    private static final Map<UUID, PlayerProfile> PROFILE_CACHE = new ConcurrentHashMap<>();
    private static final long CACHE_EXPIRY = 300000;
    private static final Map<UUID, Long> CACHE_TIMESTAMPS = new ConcurrentHashMap<>();

    public static class PlayerProfile {
        public String uuid;
        public String playerName;
        public String bio;
        public String discord;
        public String twitter;
        public String youtube;
        public String twitch;
        public String instagram;
        public String github;
        public String website;
        public String createdAt;
        public String updatedAt;

        public PlayerProfile() {}

        public PlayerProfile(String uuid, String playerName) {
            this.uuid = uuid;
            this.playerName = playerName;
            this.bio = "";
            this.discord = "";
            this.twitter = "";
            this.youtube = "";
            this.twitch = "";
            this.instagram = "";
            this.github = "";
            this.website = "";
        }

        public boolean hasSocialLinks() {
            return !isEmpty(discord) || !isEmpty(twitter) || !isEmpty(youtube)
                || !isEmpty(twitch) || !isEmpty(instagram) || !isEmpty(github) || !isEmpty(website);
        }

        private boolean isEmpty(String s) {
            return s == null || s.trim().isEmpty();
        }
    }

    public static class SearchResult {
        public String uuid;
        public String playerName;
        public String bio;
        public boolean hasSocials;
    }

    public static CompletableFuture<PlayerProfile> getProfile(UUID uuid) {
        if (PROFILE_CACHE.containsKey(uuid)) {
            Long timestamp = CACHE_TIMESTAMPS.get(uuid);
            if (timestamp != null && System.currentTimeMillis() - timestamp < CACHE_EXPIRY) {
                return CompletableFuture.completedFuture(PROFILE_CACHE.get(uuid));
            }
        }

        return CompletableFuture.supplyAsync(() -> {
            try {
                URL url = new URI(API_BASE_URL + "/profiles/" + 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);
                    JsonObject json = GSON.fromJson(response, JsonObject.class);

                    if (json.has("success") && json.get("success").getAsBoolean()) {
                        PlayerProfile profile = GSON.fromJson(json.get("profile"), PlayerProfile.class);
                        PROFILE_CACHE.put(uuid, profile);
                        CACHE_TIMESTAMPS.put(uuid, System.currentTimeMillis());
                        return profile;
                    }
                } else if (conn.getResponseCode() == 404) {
                    return null;
                }
                conn.disconnect();
            } catch (Exception e) {
                Client.logger.error("Failed to fetch profile for {}", uuid, e);
            }
            return null;
        }, Util.getMainWorkerExecutor());
    }

    public static CompletableFuture<PlayerProfile> getOwnProfile() {
        UUID uuid = getCurrentUuid();
        if (uuid == null) return CompletableFuture.completedFuture(null);
        return getProfile(uuid);
    }

    public static CompletableFuture<String> updateProfile(PlayerProfile profile) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                UUID uuid = getCurrentUuid();
                if (uuid == null) return "Not logged in";

                URL url = new URI(API_BASE_URL + "/profiles/update").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);

                JsonObject payload = new JsonObject();
                payload.addProperty("uuid", uuid.toString());
                payload.addProperty("playerName", MinecraftClient.getInstance().getSession().getUsername());
                payload.addProperty("bio", profile.bio);
                payload.addProperty("discord", profile.discord);
                payload.addProperty("twitter", profile.twitter);
                payload.addProperty("youtube", profile.youtube);
                payload.addProperty("twitch", profile.twitch);
                payload.addProperty("instagram", profile.instagram);
                payload.addProperty("github", profile.github);
                payload.addProperty("website", profile.website);

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

                if (conn.getResponseCode() == 200) {
                    String response = new String(conn.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
                    JsonObject json = GSON.fromJson(response, JsonObject.class);

                    if (json.has("success") && json.get("success").getAsBoolean()) {
                        PROFILE_CACHE.put(uuid, profile);
                        CACHE_TIMESTAMPS.put(uuid, System.currentTimeMillis());
                        return null;
                    } else {
                        return json.has("error") ? json.get("error").getAsString() : "Unknown error";
                    }
                } else {
                    return "Server error: " + conn.getResponseCode();
                }
            } catch (Exception e) {
                Client.logger.error("Failed to update profile", e);
                return "Failed to update profile: " + e.getMessage();
            }
        }, Util.getMainWorkerExecutor());
    }

    public static CompletableFuture<List<SearchResult>> searchProfiles(String query) {
        return CompletableFuture.supplyAsync(() -> {
            List<SearchResult> results = new ArrayList<>();
            try {
                String encodedQuery = java.net.URLEncoder.encode(query, StandardCharsets.UTF_8);
                URL url = new URI(API_BASE_URL + "/profiles/search?q=" + encodedQuery).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);
                    JsonObject json = GSON.fromJson(response, JsonObject.class);

                    if (json.has("success") && json.get("success").getAsBoolean()) {
                        JsonArray array = json.getAsJsonArray("results");
                        for (JsonElement element : array) {
                            SearchResult result = GSON.fromJson(element, SearchResult.class);
                            results.add(result);
                        }
                    }
                }
                conn.disconnect();
            } catch (Exception e) {
                Client.logger.error("Failed to search profiles", e);
            }
            return results;
        }, Util.getMainWorkerExecutor());
    }

    public static void invalidateCache(UUID uuid) {
        PROFILE_CACHE.remove(uuid);
        CACHE_TIMESTAMPS.remove(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;
    }
}

