using System.Text.Json;
using System.IO.Compression;
using Lentia.Core.Constants;
using System.Text.Json.Serialization;
using Lentia.Core.Utils;
using System.Net.Http.Json;

namespace Lentia.Core.Game.Extra;

public static class ForgeHelper {
    public class ForgePromotions {
        [JsonPropertyName("promos")]
        public Dictionary<string, string>? Promos { get; set; }
    }

    public static async Task<string> FetchAndDownloadForge(string mcVersion, string root, bool recommended = true) {
        string promoUrl = "https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json";
        
        var response = await HttpHelper.FetchAsync(promoUrl, HttpMethod.Get);
        
        response.EnsureSuccessStatusCode();
        
        var promoData = await response.Content.ReadFromJsonAsync<ForgePromotions>(LauncherConstants._jsonOptions);
        string promoKey = $"{mcVersion}-{(recommended ? "recommended" : "latest")}";

        if (promoData?.Promos == null || !promoData.Promos.TryGetValue(promoKey, out string? buildVersion)) {
            throw new Exception($"Version Forge introuvable pour {promoKey}");
        }

        bool isModern = IsVersionModern(mcVersion);
        string fullVersion = $"{mcVersion}-{buildVersion}";
        
        string classifier = isModern ? "installer" : "universal";
        string downloadUrl = $"https://maven.minecraftforge.net/net/minecraftforge/forge/{fullVersion}/forge-{fullVersion}-{classifier}.jar";

        string destination = Path.Combine(root, "temp", $"forge-{fullVersion}-{classifier}.jar");

        await FileHelper.DownloadFileAsync(downloadUrl, destination);

        return destination;
    }

    private static bool IsVersionModern(string mcVersion) {
        if (string.IsNullOrEmpty(mcVersion)) return false;
        var parts = mcVersion.Split(".");
        if (parts.Length < 2) return false;
        
        if (int.TryParse(parts[1], out int minor)) {
            return minor >= 12;
        }
        return false;
    }

    public static void MergeForge(MinecraftVersion baseVersion, string forgeJsonContent) {
        var forgeVersion = JsonSerializer.Deserialize<MinecraftVersion>(forgeJsonContent, LauncherConstants._jsonOptions);
        if (forgeVersion == null) return;

        baseVersion.MainClass = forgeVersion.MainClass;
        baseVersion.MinecraftArguments = forgeVersion.MinecraftArguments;
        
        if (forgeVersion.Libraries != null) {
            foreach (var lib in forgeVersion.Libraries) {
                if (lib.Downloads?.Artifact == null) {
                    TranslateToModernLibrary(lib);
                }
                
                if (lib.Name!.Contains("net.minecraftforge:forge") && string.IsNullOrEmpty(lib.Downloads?.Artifact?.Url)) {
                    FixForgeUniversalUrl(lib);
                }

                baseVersion.Libraries?.Add(lib);
            }
        }
    }

    private static void TranslateToModernLibrary(Library lib) {
        if (string.IsNullOrEmpty(lib.Name)) return;

        var parts = lib.Name.Split(":");
        if (parts.Length < 3) return;

        string group = parts[0].Replace(".", "/");
        string artifact = parts[1];
        string version = parts[2];
        string path = $"{group}/{artifact}/{version}/{artifact}-{version}.jar";

        string baseUrl = "https://libraries.minecraft.net/";
        if (!baseUrl.EndsWith("/")) baseUrl += "/";

        lib.Downloads = new LibraryDownloads {
            Artifact = new DownloadInfo {
                Path = path,
                Url = baseUrl + path
            }
        };
    }

    private static void FixForgeUniversalUrl(Library lib) {
        var parts = lib.Name!.Split(":");
        string version = parts[2];
        lib.Downloads!.Artifact!.Url = $"https://maven.minecraftforge.net/net/minecraftforge/forge/{version}/forge-{version}-universal.jar";
    }

    public static async Task<MinecraftVersion?> ExtractForgeJson(string jarPath) {
        using (ZipArchive archive = ZipFile.OpenRead(jarPath)) {
            var entry = archive.Entries.FirstOrDefault(e => e.Name == "version.json");
            
            if (entry == null) {
                throw new Exception("Fichier version.json introuvable dans l'archive Forge.");
            }

            using var reader = new StreamReader(entry.Open());
            string jsonContent = await reader.ReadToEndAsync();

            return JsonSerializer.Deserialize<MinecraftVersion>(jsonContent, LauncherConstants._jsonOptions);
        }
    }
    public static async Task<MinecraftVersion?> ProcessForge(MinecraftVersion baseVersion, string root) {
        if (baseVersion.Id == null) throw new ArgumentNullException(nameof(baseVersion.Id));

        string downloadedJarPath = await FetchAndDownloadForge(baseVersion.Id, root, false);

        var forgeMeta = await ExtractForgeJson(downloadedJarPath);
        if (forgeMeta == null) return null;

        var forgeLib = forgeMeta.Libraries?.FirstOrDefault(l => l.Name!.Contains("net.minecraftforge:forge"));
            
        if (forgeLib != null) {
            string relPath = GeneratePathFromArtifactName(forgeLib.Name!);
            string finalDestination = Path.Combine(root, "libraries", relPath);

            Directory.CreateDirectory(Path.GetDirectoryName(finalDestination)!);
            
            if (File.Exists(finalDestination)) File.Delete(finalDestination);
            File.Move(downloadedJarPath, finalDestination);
        }

        MergeForge(baseVersion, JsonSerializer.Serialize(forgeMeta, LauncherConstants._jsonOptions));

        return forgeMeta;
    }
    public static string GeneratePathFromArtifactName(string name) {
        if (string.IsNullOrEmpty(name) || !name.Contains(":")) return name;

        var parts = name.Split(":");
        
        string group = parts[0].Replace(".", "/");
        string artifact = parts[1];
        string version = parts[2];

        return $"{group}/{artifact}/{version}/{artifact}-{version}.jar";
    }

}