using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Net.Http.Json;
using System.Text.Json;
using Lentia.Core.Constants;
using Lentia.Core.Utils;
using Lentia.Utils;
using System.Text.Json.Serialization;

namespace Lentia.Core.Game;

public class JavaRuntimeManifest {
    [JsonPropertyName("files")]
    public Dictionary<string, JavaFileEntry>? Files { get; set; }
}

public class JavaFileEntry {
    [JsonPropertyName("type")]
    public string? Type { get; set; }
    [JsonPropertyName("downloads")]
    public JavaDownloads? Downloads { get; set; }
}

public class JavaDownloads {
    [JsonPropertyName("raw")]
    public DownloadInfo? Raw { get; set; }
}

public static class JavaHelper {
    
    public static async Task<string> GetJavaExecutablePath(MinecraftVersion version, string root) {
        string component = version.JavaVersion?.Component ?? "jre-legacy";
        int majorVersion = version.JavaVersion?.MajorVersion ?? 8;
        
        string configuredJava = SettingsManager.ReadSettings().JavaPath;

        if (IsJavaCompatible(configuredJava, majorVersion)) {
            return configuredJava;
        }

        string platform = OsHelper.GetPlatformString();
        string localJavaPath = Path.Combine(root, "runtime", component, platform, "bin", 
            RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "java.exe" : "java");

        if (File.Exists(localJavaPath)) {
            return localJavaPath;
        }

        await DownloadJavaRuntime(root, platform, component);
        
        return localJavaPath;
    }

    private static bool IsJavaCompatible(string javaPath, int requiredMajor) {
        try {
            var psi = new ProcessStartInfo(javaPath, "-version") {
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true
            };
            using var process = Process.Start(psi);
            string output = process?.StandardError.ReadToEnd() ?? "";
            
            string search = requiredMajor <= 8 ? $"1.{requiredMajor}" : $"{requiredMajor}.";
            return output.Contains(search);
        } catch {
            return false;
        }
    }

    private static async Task DownloadJavaRuntime(string root, string platform, string component) {
        string allJsonUrl = "https://piston-meta.mojang.com/v1/products/java-runtime/2ec0cc6c0dba9f635e09f3900331038590632291/all.json";

        var allRuntimesResponse = await HttpHelper.FetchAsync(allJsonUrl);
        allRuntimesResponse.EnsureSuccessStatusCode();
        var allRuntimes = await allRuntimesResponse.Content.ReadFromJsonAsync<JsonElement>(LauncherConstants._jsonOptions);

        if (!allRuntimes.TryGetProperty(platform, out var platformData) || 
            !platformData.TryGetProperty(component, out var componentVersions)) {
            throw new Exception($"Le runtime {component} n'est pas disponible pour {platform}");
        }

        string manifestUrl = componentVersions[0].GetProperty("manifest").GetProperty("url").GetString()!;
        var manifestResponse = await HttpHelper.FetchAsync(manifestUrl);
        manifestResponse.EnsureSuccessStatusCode();
        var manifest = await manifestResponse.Content.ReadFromJsonAsync<JavaRuntimeManifest>(LauncherConstants._jsonOptions);

        string javaDir = Path.Combine(root, "runtime", component, platform);
        await Parallel.ForEachAsync(manifest!.Files!, new ParallelOptions { MaxDegreeOfParallelism = 8 }, async (entry, token) => {
            string localPath = Path.Combine(javaDir, entry.Key);
            
            if (entry.Value.Type == "directory") {
                Directory.CreateDirectory(localPath);
            } else if (entry.Value.Downloads?.Raw != null) {
                var download = entry.Value.Downloads.Raw;
                
                if (!File.Exists(localPath) || new FileInfo(localPath).Length != download.Size) {
                    await FileHelper.DownloadFileAsync(download.Url!, localPath);
                }
            }
        });
    }
}