package de.winniepat.citrus.managers;

import de.winniepat.citrus.Client;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.texture.NativeImage;
import net.minecraft.client.texture.NativeImageBackedTexture;
import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
import org.w3c.dom.*;

import javax.xml.parsers.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Consumer;

public class WallpaperManager {
    private static final String CDN_WALLPAPERS_URL = Client.CDN_URL + "/wallpapers";
    private static final String MOD_ID = "citrus";
    private static final String CACHE_DIR_NAME = "citrus/wallpapers";

    private static final Map<String, Identifier> WALLPAPER_CACHE = new ConcurrentHashMap<>();
    private static final Map<String, byte[]> WALLPAPER_DATA_CACHE = new ConcurrentHashMap<>();
    private static final Set<String> LOADING_WALLPAPERS = ConcurrentHashMap.newKeySet();
    private static final Set<String> FAILED_WALLPAPERS = ConcurrentHashMap.newKeySet();
    private static final List<String> AVAILABLE_WALLPAPERS = new CopyOnWriteArrayList<>();

    private static boolean wallpapersListFetched = false;
    private static boolean isInitialized = false;
    private static final List<Runnable> onWallpapersLoadedCallbacks = new CopyOnWriteArrayList<>();

    private static Path cacheDir;

    public static void init() {
        if (isInitialized) return;
        isInitialized = true;

        initCacheDirectory();

        fetchWallpaperListFromCDN();
    }

    private static void initCacheDirectory() {
        try {
            Path runDir = MinecraftClient.getInstance().runDirectory.toPath();
            cacheDir = runDir.resolve(CACHE_DIR_NAME);
            Files.createDirectories(cacheDir);
            Client.debugLog("Wallpaper cache directory: " + cacheDir);
        } catch (Exception e) {
            Client.logger.error("Failed to create wallpaper cache directory", e);
            cacheDir = null;
        }
    }

    private static boolean isWallpaperCachedOnDisk(String wallpaperName) {
        if (cacheDir == null) return false;
        Path cachedFile = cacheDir.resolve(wallpaperName);
        return Files.exists(cachedFile) && Files.isRegularFile(cachedFile);
    }

    private static byte[] loadWallpaperFromDisk(String wallpaperName) {
        if (cacheDir == null) return null;
        try {
            Path cachedFile = cacheDir.resolve(wallpaperName);
            if (Files.exists(cachedFile)) {
                byte[] data = Files.readAllBytes(cachedFile);
                Client.debugLog("Loaded wallpaper from disk cache: " + wallpaperName + " (" + data.length + " bytes)");
                return data;
            }
        } catch (Exception e) {
            Client.logger.error("Failed to load wallpaper from disk cache: {}", wallpaperName, e);
        }
        return null;
    }

    private static void saveWallpaperToDisk(String wallpaperName, byte[] data) {
        if (cacheDir == null || data == null || data.length == 0) return;
        try {
            Path cachedFile = cacheDir.resolve(wallpaperName);
            Files.write(cachedFile, data);
            Client.debugLog("Saved wallpaper to disk cache: " + wallpaperName + " (" + data.length + " bytes)");
        } catch (Exception e) {
            Client.logger.error("Failed to save wallpaper to disk cache: {}", wallpaperName, e);
        }
    }

    public static void fetchWallpaperListFromCDN() {
        Client.debugLog("Fetching wallpaper list from CDN...");

        CompletableFuture.runAsync(() -> {
            try {
                URL url = new URI(CDN_WALLPAPERS_URL).toURL();
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("GET");
                connection.setConnectTimeout(10000);
                connection.setReadTimeout(10000);

                if (connection.getResponseCode() == 200) {
                    try (InputStream stream = connection.getInputStream()) {
                        byte[] xmlData = stream.readAllBytes();
                        parseWallpaperListFromXML(xmlData);
                    }
                } else {
                    Client.logger.error("Failed to fetch wallpaper list. HTTP {}", connection.getResponseCode());
                    loadDefaultWallpapers();
                }

                connection.disconnect();

            } catch (Exception e) {
                Client.logger.error("Error fetching wallpaper list", e);
                loadDefaultWallpapers();
            }
        }, Util.getMainWorkerExecutor());
    }

    private static void parseWallpaperListFromXML(byte[] xmlData) {
        try {
            List<String> discoveredWallpapers = new ArrayList<>();

            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(new ByteArrayInputStream(xmlData));

            NodeList keyNodes = doc.getElementsByTagName("Key");

            for (int i = 0; i < keyNodes.getLength(); i++) {
                Node node = keyNodes.item(i);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    String keyValue = node.getTextContent().trim();

                    if (keyValue.toLowerCase().endsWith(".png")) {
                        String wallpaperName = keyValue;
                        discoveredWallpapers.add(wallpaperName);

                        Client.debugLog("Found wallpaper: " + wallpaperName);
                    }
                }
            }

            if (discoveredWallpapers.isEmpty()) {
                Client.debugLog("No wallpapers found in CDN, using defaults");
                loadDefaultWallpapers();
            } else {
                AVAILABLE_WALLPAPERS.clear();
                AVAILABLE_WALLPAPERS.addAll(discoveredWallpapers);
                wallpapersListFetched = true;
                Client.debugLog("Loaded " + discoveredWallpapers.size() + " wallpapers from CDN");

                for (Runnable callback : onWallpapersLoadedCallbacks) {
                    try {
                        callback.run();
                    } catch (Exception e) {
                        Client.logger.error("Error in wallpaper loaded callback", e);
                    }
                }
            }

        } catch (Exception e) {
            Client.logger.error("Error parsing wallpaper list XML", e);
            loadDefaultWallpapers();
        }
    }

    private static void loadDefaultWallpapers() {
        AVAILABLE_WALLPAPERS.clear();
        AVAILABLE_WALLPAPERS.add("default.png");
        wallpapersListFetched = true;

        for (Runnable callback : onWallpapersLoadedCallbacks) {
            try {
                callback.run();
            } catch (Exception e) {
                Client.logger.error("Error in wallpaper loaded callback", e);
            }
        }
    }

    public static void onWallpapersLoaded(Runnable callback) {
        if (wallpapersListFetched) {
            callback.run();
        } else {
            onWallpapersLoadedCallbacks.add(callback);
        }
    }

    public static List<String> getAvailableWallpapers() {
        return new ArrayList<>(AVAILABLE_WALLPAPERS);
    }

    public static boolean isWallpapersListLoaded() {
        return wallpapersListFetched;
    }

    public static Identifier getWallpaperTexture(String wallpaperName) {
        return WALLPAPER_CACHE.get(wallpaperName);
    }

    public static boolean isWallpaperLoaded(String wallpaperName) {
        return WALLPAPER_CACHE.containsKey(wallpaperName);
    }

    public static boolean isWallpaperLoading(String wallpaperName) {
        return LOADING_WALLPAPERS.contains(wallpaperName);
    }

    public static boolean hasWallpaperFailed(String wallpaperName) {
        return FAILED_WALLPAPERS.contains(wallpaperName);
    }

    public static byte[] getWallpaperImageData(String wallpaperName) {
        return WALLPAPER_DATA_CACHE.get(wallpaperName);
    }

    public static void loadWallpaperWithData(String wallpaperName, Consumer<byte[]> onLoaded) {
        if (WALLPAPER_DATA_CACHE.containsKey(wallpaperName)) {
            if (onLoaded != null) {
                onLoaded.accept(WALLPAPER_DATA_CACHE.get(wallpaperName));
            }
            return;
        }

        if (isWallpaperCachedOnDisk(wallpaperName)) {
            byte[] cachedData = loadWallpaperFromDisk(wallpaperName);
            if (cachedData != null && cachedData.length > 0) {
                WALLPAPER_DATA_CACHE.put(wallpaperName, cachedData);
                if (onLoaded != null) {
                    onLoaded.accept(cachedData);
                }
                return;
            }
        }

        if (FAILED_WALLPAPERS.contains(wallpaperName)) {
            if (onLoaded != null) {
                onLoaded.accept(null);
            }
            return;
        }

        if (LOADING_WALLPAPERS.contains(wallpaperName)) {
            CompletableFuture.runAsync(() -> {
                while (LOADING_WALLPAPERS.contains(wallpaperName)) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        break;
                    }
                }
                if (onLoaded != null) {
                    onLoaded.accept(WALLPAPER_DATA_CACHE.get(wallpaperName));
                }
            }, Util.getMainWorkerExecutor());
            return;
        }

        LOADING_WALLPAPERS.add(wallpaperName);

        CompletableFuture.runAsync(() -> {
            try {
                byte[] imageData = downloadWallpaperImage(wallpaperName);
                if (imageData.length == 0) {
                    Client.logger.error("Empty image data for wallpaper {}", wallpaperName);
                    markWallpaperAsFailed(wallpaperName);
                    if (onLoaded != null) {
                        onLoaded.accept(null);
                    }
                    LOADING_WALLPAPERS.remove(wallpaperName);
                    return;
                }

                WALLPAPER_DATA_CACHE.put(wallpaperName, imageData);
                FAILED_WALLPAPERS.remove(wallpaperName);

                saveWallpaperToDisk(wallpaperName, imageData);

                Client.debugLog("Successfully loaded wallpaper data: " + wallpaperName + " (" + imageData.length + " bytes)");

                if (onLoaded != null) {
                    onLoaded.accept(imageData);
                }
            } catch (Exception e) {
                Client.logger.error("Failed to download wallpaper {}", wallpaperName, e);
                markWallpaperAsFailed(wallpaperName);
                if (onLoaded != null) {
                    onLoaded.accept(null);
                }
            } finally {
                LOADING_WALLPAPERS.remove(wallpaperName);
            }
        }, Util.getMainWorkerExecutor());
    }

    public static void loadWallpaper(String wallpaperName, Consumer<Identifier> onLoaded) {
        if (WALLPAPER_CACHE.containsKey(wallpaperName)) {
            if (onLoaded != null) {
                onLoaded.accept(WALLPAPER_CACHE.get(wallpaperName));
            }
            return;
        }

        if (FAILED_WALLPAPERS.contains(wallpaperName)) {
            if (onLoaded != null) {
                onLoaded.accept(null);
            }
            return;
        }

        if (LOADING_WALLPAPERS.contains(wallpaperName)) {
            CompletableFuture.runAsync(() -> {
                while (LOADING_WALLPAPERS.contains(wallpaperName)) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        break;
                    }
                }
                if (onLoaded != null) {
                    MinecraftClient.getInstance().execute(() -> {
                        onLoaded.accept(WALLPAPER_CACHE.get(wallpaperName));
                    });
                }
            }, Util.getMainWorkerExecutor());
            return;
        }

        LOADING_WALLPAPERS.add(wallpaperName);

        CompletableFuture.runAsync(() -> {
            try {
                byte[] imageData = downloadWallpaperImage(wallpaperName);
                if (imageData.length == 0) {
                    Client.logger.error("Empty image data for wallpaper {}", wallpaperName);
                    markWallpaperAsFailed(wallpaperName);
                    if (onLoaded != null) {
                        MinecraftClient.getInstance().execute(() -> onLoaded.accept(null));
                    }
                    return;
                }

                saveWallpaperToDisk(wallpaperName, imageData);

                NativeImage nativeImage = NativeImage.read(new ByteArrayInputStream(imageData));

                MinecraftClient.getInstance().execute(() -> {
                    try {
                        NativeImageBackedTexture texture = new NativeImageBackedTexture(nativeImage);
                        String safeName = wallpaperName.replace(".png", "").replaceAll("[^a-zA-Z0-9_]", "_");
                        Identifier textureId = Identifier.of(MOD_ID, "wallpapers/" + safeName);
                        MinecraftClient.getInstance().getTextureManager().registerTexture(textureId, texture);
                        WALLPAPER_CACHE.put(wallpaperName, textureId);
                        FAILED_WALLPAPERS.remove(wallpaperName);
                        Client.debugLog("Successfully loaded wallpaper: " + wallpaperName + " (" + nativeImage.getWidth() + "x" + nativeImage.getHeight() + ")");

                        if (onLoaded != null) {
                            onLoaded.accept(textureId);
                        }
                    } catch (Exception e) {
                        Client.logger.error("Failed to create texture for wallpaper {}", wallpaperName, e);
                        nativeImage.close();
                        markWallpaperAsFailed(wallpaperName);
                        if (onLoaded != null) {
                            onLoaded.accept(null);
                        }
                    } finally {
                        LOADING_WALLPAPERS.remove(wallpaperName);
                    }
                });

            } catch (Exception e) {
                Client.logger.error("Failed to download wallpaper {}", wallpaperName, e);
                markWallpaperAsFailed(wallpaperName);
                LOADING_WALLPAPERS.remove(wallpaperName);
                if (onLoaded != null) {
                    MinecraftClient.getInstance().execute(() -> onLoaded.accept(null));
                }
            }
        }, Util.getMainWorkerExecutor());
    }

    private static byte[] downloadWallpaperImage(String wallpaperName) throws Exception {
        String downloadUrl = CDN_WALLPAPERS_URL + "/" + wallpaperName;
        Client.debugLog("Downloading wallpaper from: " + downloadUrl);

        URL url = new URI(downloadUrl).toURL();
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.setConnectTimeout(30000);
        connection.setReadTimeout(30000);

        if (connection.getResponseCode() != 200) {
            throw new IOException("Failed to download wallpaper: HTTP " + connection.getResponseCode());
        }

        try (InputStream stream = connection.getInputStream()) {
            return stream.readAllBytes();
        } finally {
            connection.disconnect();
        }
    }

    private static void markWallpaperAsFailed(String wallpaperName) {
        FAILED_WALLPAPERS.add(wallpaperName);
        LOADING_WALLPAPERS.remove(wallpaperName);
    }

    public static void preloadWallpaper(String wallpaperName) {
        loadWallpaper(wallpaperName, null);
    }
}

