using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Threading;
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using System.IO.Compression;
using VeloeMinecraftLauncher.Entity.Assets;
using VeloeMinecraftLauncher.ViewModels;
using VeloeMinecraftLauncher.Views;
using System.Collections.ObjectModel;
using VeloeMinecraftLauncher.Models.Entity;
using SkiaSharp;

namespace VeloeMinecraftLauncher.MinecraftLauncher;

internal static class Downloader
{
    public static async Task<TaskStatus> StartDownload(
        Action<string> DownloadingFileName,
        Action<bool> IsControlsEnabled,
        Action<WebClient> SetProgressBar,
        Action<WebClient> RemoveProgressBar,
        Entity.Version.Version versionJson,
        bool DownloadJava = false,
        bool InstallForge = false,
        bool InstallOptifine = false,
        bool InstallForgeOptifine = false,
        bool InstallFabric = false
        )
    {
        try
        {
            Settings.logger.Debug("Downloading minecraft {0}", versionJson.Id);
            var webClient = new WebClient();
            
            SetProgressBar(webClient);
            //webClient.DownloadProgressChanged += WebClient_DownloadProgressChanged;
            //download java
            if (DownloadJava)
            {
                Settings.logger.Debug("Getting required Java version.");
                string javaUrl = "";
                if (versionJson.JavaVersion is not null && versionJson.JavaVersion.MajorVersion != null)
                {
                    switch (versionJson.JavaVersion.MajorVersion)
                    {
                        case 8:
                            if (Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
                                javaUrl = "https://files.veloe.link/launcher/java/8/windows64/java.zip";
                            if (!Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
                                javaUrl = "https://files.veloe.link/launcher/java/8/windows32/java.zip";

                            if (Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
                                javaUrl = "https://files.veloe.link/launcher/java/8/linux64/java.zip";
                            if (!Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
                                javaUrl = "https://files.veloe.link/launcher/java/8/linux32/java.zip";
                            break;
                        case 16:
                            if (Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
                                javaUrl = "https://files.veloe.link/launcher/java/16/windows64/java.zip";
                            if (Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
                                javaUrl = "https://files.veloe.link/launcher/java/16/linux64/java.zip";
                            break;
                        case 17:
                            if (Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
                                javaUrl = "https://files.veloe.link/launcher/java/17/windows64/java.zip";
                            if (Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
                                javaUrl = "https://files.veloe.link/launcher/java/17/linux64/java.zip";

                            break;
                        case 18:
                            if (Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
                                javaUrl = "https://files.veloe.link/launcher/java/18/windows64/java.zip";
                            if (Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
                                javaUrl = "https://files.veloe.link/launcher/java/18/linux64/java.zip";

                            break;
                    }                   
                }

                if (versionJson.Assets == "legacy")
                {
                    if (Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
                        javaUrl = "https://files.veloe.link/launcher/java/8/windows64/java.zip";
                    if (!Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
                        javaUrl = "https://files.veloe.link/launcher/java/8/windows32/java.zip";

                    if (Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
                        javaUrl = "https://files.veloe.link/launcher/java/8/linux64/java.zip";
                    if (!Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
                        javaUrl = "https://files.veloe.link/launcher/java/8/linux32/java.zip";
                }

                if (javaUrl != "")
                {
                    Settings.logger.Debug("Downloading Java");
                    DownloadingFileName("java.zip");
                    webClient.DownloadFileAsync(new System.Uri(javaUrl), Settings.minecraftForlderPath + "java.zip");
                    waitWhileBisy(ref webClient);

                    Settings.logger.Debug("Unpacking Java");
                    DownloadingFileName("Unpacking java.zip");
                    ZipFile.ExtractToDirectory($"{Settings.minecraftForlderPath}java.zip", Settings.minecraftForlderPath, true);
                    File.Delete($"{Settings.minecraftForlderPath}java.zip");
                }
                else
                    Settings.logger.Debug("Required Java version don't found in json file."); //log that java was not downloaded;
            }

            //download json
            var path = Settings.minecraftForlderPath + "/versions/" + versionJson.Id;
            if (!Directory.Exists(path))
            {
                Settings.logger.Debug("Creating path: {0}", path);
                Directory.CreateDirectory(path);
            }

            //Settings.logger.Debug("Downloading {0}", $"{versionJson.id}.json");
            //DownloadingFileName($"{versionJson.id}.json");
            //webClient.DownloadFileAsync(new System.Uri(versionJson.url), path + "/" + versionJson.id + ".json");
            //waitWhileBisy(ref webClient);

            //download jar
            if (!Directory.Exists(path))
            {
                Settings.logger.Debug("Creating path: {0}", path);
                Directory.CreateDirectory(path);
            }

            string chksum = String.Empty;
            //here hash check
            if (File.Exists(path + "/" + versionJson.Id + ".jar"))
            {
                DownloadingFileName($"Checking hash: {versionJson.Id}.jar");
                FileStream fop = File.OpenRead(path + "/" + versionJson.Id + ".jar");
                byte[] hash = System.Security.Cryptography.SHA1.Create().ComputeHash(fop);
                chksum = BitConverter.ToString(hash).Replace("-", String.Empty).ToLower();

                fop.Close();
                fop.Dispose();
            }

            if (chksum != versionJson.Downloads.Client.Sha1)
            {
                Settings.logger.Debug("Downloading {0}", $"{versionJson.Id}.jar");
                DownloadingFileName($"{versionJson.Id}.jar");
                webClient.DownloadFileAsync(new System.Uri(versionJson.Downloads.Client.Url), path + "/" + versionJson.Id + ".jar");
                waitWhileBisy(ref webClient);
            }
            //end download jar
            //download libraries
            Settings.logger.Debug("Downloading libraries.");
            foreach (var library in versionJson.Libraries)
            {
                var libPath = Settings.minecraftForlderPath + "libraries/";
                string libUrl = "";
                string sha1 = String.Empty;
                // getting path and url if universal lib
                if (library.Natives is null)
                {
                    libPath = Settings.minecraftForlderPath + "libraries/" + library.Downloads.Artifact.Path;
                    libUrl = library.Downloads.Artifact.Url;
                    sha1 = library.Downloads.Artifact.Sha1;
                }
                else
                {   // getting path if native
                    libPath = Settings.minecraftForlderPath + "libraries/";
                    libUrl = "";
                    if (library.Downloads.Classifiers is not null)
                    {
                        if (OperatingSystem.IsWindows() && library.Natives.Windows is not null)
                        {
                            if (library.Downloads.Classifiers.NativesWindows is not null)
                            {
                                libPath += library.Downloads.Classifiers.NativesWindows.Path;
                                libUrl = library.Downloads.Classifiers.NativesWindows.Url;
                                sha1 = library.Downloads.Classifiers.NativesWindows.Sha1;
                            }
                            else
                            {
                                if (Environment.Is64BitOperatingSystem && library.Downloads.Classifiers.NativesWindows64 is not null)
                                {
                                    libPath += library.Downloads.Classifiers.NativesWindows64.Path;
                                    libUrl = library.Downloads.Classifiers.NativesWindows64.Url;
                                    sha1 = library.Downloads.Classifiers.NativesWindows64.Sha1;
                                }
                                else if (library.Downloads.Classifiers.NativesWindows32 is not null)
                                {
                                    libPath += library.Downloads.Classifiers.NativesWindows32.Path;
                                    libUrl = library.Downloads.Classifiers.NativesWindows32.Url;
                                    sha1 = library.Downloads.Classifiers.NativesWindows32.Sha1;
                                }
                            }
                        }
                        if (OperatingSystem.IsLinux() && library.Natives.Linux is not null && library.Downloads.Classifiers.NativesLinux is not null)
                        {
                            libPath += library.Downloads.Classifiers.NativesLinux.Path;
                            libUrl = library.Downloads.Classifiers.NativesLinux.Url;
                            sha1 = library.Downloads.Classifiers.NativesLinux.Url;
                        }
                    }
                }

                //if no lib url
                if (libUrl == String.Empty)
                    continue;

                var libName = Path.GetFileName(libPath);
                var libDir = Path.GetDirectoryName(libPath);

                //checking rules
                if (library.Rules == null)
                {                 
                    if (!Directory.Exists(libDir))
                    {
                        Settings.logger.Debug("Creating path: {0}", path);
                        Directory.CreateDirectory(libDir);
                    }

                    chksum = String.Empty;

                    if (File.Exists(libPath))
                    {
                        DownloadingFileName($"Checking hash: {libName}");
                        FileStream fop = File.OpenRead(libPath);
                        byte[] hash = System.Security.Cryptography.SHA1.Create().ComputeHash(fop);
                        chksum = BitConverter.ToString(hash).Replace("-", String.Empty).ToLower();

                        fop.Close();
                        fop.Dispose();
                    }

                    if (chksum != sha1)
                    {
                        Settings.logger.Debug("Downloading: {0}", libName);
                        DownloadingFileName(libName);
                        webClient.DownloadFileAsync(new System.Uri(libUrl), libDir + "/" + libName);
                        waitWhileBisy(ref webClient);
                    }
                }
                else
                {
                    foreach (var rule in library.Rules)
                    {
                        if (rule.Action == "allow") // && rule.os is null
                        {
                            if (!Directory.Exists(libDir))
                            {
                                Settings.logger.Debug("Creating path: {0}", path);
                                Directory.CreateDirectory(libDir);
                            }

                            chksum = String.Empty;

                            if (File.Exists(libDir + "/" + libName) && sha1 != String.Empty)
                            {
                                DownloadingFileName($"Checking hash: {libName}");
                                FileStream fop = File.OpenRead(libDir + "/" + libName);
                                byte[] hash = System.Security.Cryptography.SHA1.Create().ComputeHash(fop);
                                chksum = BitConverter.ToString(hash).Replace("-", String.Empty).ToLower();

                                fop.Close();
                                fop.Dispose();
                            }

                            if (chksum != sha1)
                            {
                                Settings.logger.Debug("Downloading: {0}", libName);
                                DownloadingFileName(libName);
                                webClient.DownloadFileAsync(new System.Uri(libUrl), libDir + "/" + libName);
                                waitWhileBisy(ref webClient);
                            }
                            continue;
                        }
                        //fabic on start needs all libraries for all os, so os check removed
                        /*
                        if (rule.action == "allow" && (rule.os.name == "windows" || rule.os.name == "linux" || rule.os.name == "osx" ))
                        {
                            if (!Directory.Exists(libPath))
                            {
                                Settings.logger.Debug("Creating path: {0}", path);
                                Directory.CreateDirectory(libPath);
                            }
                            Settings.logger.Debug("Downloading: {0}", libName);
                            DownloadingFileName = libName;
                            webClient.DownloadFileAsync(new System.Uri(libUrl), libPath + "/" + libName);
                            waitWhileBisy(ref webClient);
                        }
                        */
                    }
                }
                //unpacking native libs
                if ((library.Natives is not null || library.Downloads.Classifiers is not null) && File.Exists(libPath)/*&& chksum != sha1*/)
                {
                    try
                    {
                        if (!(library.Downloads.Classifiers is not null && (
                            library.Downloads.Classifiers.NativesWindows is not null ||
                            library.Downloads.Classifiers.NativesWindows64 is not null ||
                            (library.Downloads.Classifiers.NativesWindows32 is not null && OperatingSystem.IsWindows()) ||
                            (library.Downloads.Classifiers.NativesLinux is not null && OperatingSystem.IsLinux()))))
                            continue;

                        if (!Directory.Exists(Settings.minecraftForlderPath + "versions/" + versionJson.Id + "/natives/"))
                        {
                            Settings.logger.Debug("Creating path: {0}", Settings.minecraftForlderPath + "versions/" + versionJson.Id + "/natives/");
                            Directory.CreateDirectory(Settings.minecraftForlderPath + "versions/" + versionJson.Id + "/natives/");
                        }
                        Settings.logger.Debug("Extracting {0} to {1}", libName, Settings.minecraftForlderPath + "versions/" + versionJson.Id + "/natives/");
                        ZipFile.ExtractToDirectory(libDir + "/" + libName, Settings.minecraftForlderPath + "versions/" + versionJson.Id + "/natives/", true);
                    }
                    catch (IOException ex)
                    {
                        Settings.logger.Error("IOException in VersionsDownloaderViewModel on native lib extraction");
                    }
                    //TODO delete META-INF and sha1 files after
                }
            }

            var assetsJson = Downloader.DownloadAndDeserializeJsonData<AssetsManifest>(versionJson.AssetIndex.Url);
            var assetsPath = Settings.minecraftForlderPath + "assets/" + versionJson.Assets + "/objects";
            var assetsUrl = "https://resources.download.minecraft.net/";

            //download assets json
            Settings.logger.Debug("Downloading: {0}", versionJson.Assets + ".json");

            if (!Directory.Exists(Settings.minecraftForlderPath + "/assets/" + versionJson.Assets + "/indexes/"))
                Directory.CreateDirectory(Settings.minecraftForlderPath + "/assets/" + versionJson.Assets + "/indexes/");
            webClient.DownloadFileAsync(new System.Uri(versionJson.AssetIndex.Url), Settings.minecraftForlderPath + "/assets/" + versionJson.Assets + "/indexes/" + versionJson.Assets + ".json");
            waitWhileBisy(ref webClient);

            //download assets
            foreach (var asset in assetsJson.Objects)
            {
                var folder = asset.Value.Hash.Substring(0, 2);
                if (!Directory.Exists(assetsPath + "/" + folder))
                    Directory.CreateDirectory(assetsPath + "/" + folder);

                chksum = String.Empty;
                //here hash check
                if (File.Exists(assetsPath + "/" + folder + "/" + asset.Value.Hash))
                {
                    DownloadingFileName($"Checking hash: {asset.Value.Hash}");
                    FileStream fop = File.OpenRead(assetsPath + "/" + folder + "/" + asset.Value.Hash);
                    byte[] hash = System.Security.Cryptography.SHA1.Create().ComputeHash(fop);
                    chksum = BitConverter.ToString(hash).Replace("-", String.Empty).ToLower();

                    fop.Close();
                    fop.Dispose();
                }

                if (chksum != asset.Value.Hash)
                {
                    Settings.logger.Debug("Downloading: {0}", asset.Value.Hash);
                    DownloadingFileName($"Asset {asset.Value.Hash}");
                    webClient.DownloadFileAsync(new System.Uri(assetsUrl + folder + "/" + asset.Value.Hash), assetsPath + "/" + folder + "/" + asset.Value.Hash);
                    waitWhileBisy(ref webClient);
                }
            }

            if (InstallForge)
            {
                var forgePath = $"Forge{versionJson.Id}";
                var forgeUrl = $"https://files.veloe.link/launcher/forge/Forge{versionJson.Id}/";

                if (!Directory.Exists($"{Settings.minecraftForlderPath}versions/Forge{versionJson.Id}"))
                {
                    Settings.logger.Debug("Creating path: {0}", $"{Settings.minecraftForlderPath}versions/" + forgePath);
                    Directory.CreateDirectory($"{Settings.minecraftForlderPath}versions/" + forgePath);
                }
                waitWhileBisy(ref webClient);

                Settings.logger.Debug("Downloading: {0}", $"Forge{versionJson.Id}.json");
                DownloadingFileName($"Forge{versionJson.Id}.json");
                webClient.DownloadFileAsync(new System.Uri($"{forgeUrl}Forge{versionJson.Id}.json"), Settings.minecraftForlderPath + "versions/" + forgePath + "/" + forgePath + ".json");
                waitWhileBisy(ref webClient);

                Settings.logger.Debug("Downloading: {0}", "libraries.zip");
                DownloadingFileName("libraries.zip");
                webClient.DownloadFileAsync(new System.Uri(forgeUrl + "libraries.zip"), Settings.minecraftForlderPath + "versions/" + forgePath + "/libraries.zip");
                waitWhileBisy(ref webClient);

                Settings.logger.Debug("Extracting: {0}", "libraries.zip");
                DownloadingFileName("Unpacking libraries.zip");
                ZipFile.ExtractToDirectory($"{Settings.minecraftForlderPath}versions/Forge{versionJson.Id}/libraries.zip", Settings.minecraftForlderPath, true);
                File.Delete($"{Settings.minecraftForlderPath}versions/Forge{versionJson.Id}/libraries.zip");
            }

            if (InstallOptifine)
            {
                var optifinePath = $"Optifine{versionJson.Id}";
                var optifineUrl = $"https://files.veloe.link/launcher/optifine/Optifine{versionJson.Id}/";

                if (!Directory.Exists($"{Settings.minecraftForlderPath}versions/Optifine{versionJson.Id}"))
                {
                    Settings.logger.Debug("Creating path: {0}", $"{Settings.minecraftForlderPath}Optifine/" + optifinePath);
                    Directory.CreateDirectory($"{Settings.minecraftForlderPath}Optifine/" + optifinePath);
                }

                Settings.logger.Debug("Downloading: {0}", $"Optifine{versionJson.Id}.json");
                DownloadingFileName($"Optifine{versionJson.Id}.json");
                webClient.DownloadFileAsync(new System.Uri($"{optifineUrl}Optifine{versionJson.Id}.json"), Settings.minecraftForlderPath + "versions/" + optifinePath + "/" + optifinePath + ".json");
                waitWhileBisy(ref webClient);

                Settings.logger.Debug("Downloading: {0}", $"Optifine{versionJson.Id}.jar");
                DownloadingFileName($"Optifine{versionJson.Id}.json");
                webClient.DownloadFileAsync(new System.Uri($"{optifineUrl}Optifine{versionJson.Id}.jar"), Settings.minecraftForlderPath + "versions/" + optifinePath + "/" + optifinePath + ".jar");
                waitWhileBisy(ref webClient);

                Settings.logger.Debug("Downloading: {0}", "libraries.zip");
                DownloadingFileName("libraries.zip");
                webClient.DownloadFileAsync(new System.Uri(optifineUrl + "libraries.zip"), Settings.minecraftForlderPath + "versions/" + optifinePath + "/libraries.zip");
                waitWhileBisy(ref webClient);

                Settings.logger.Debug("Extracting: {0}", "libraries.zip");
                DownloadingFileName("Unpacking libraries.zip");
                ZipFile.ExtractToDirectory($"{Settings.minecraftForlderPath}versions/Optifine{versionJson.Id}/libraries.zip", Settings.minecraftForlderPath, true);
                File.Delete($"{Settings.minecraftForlderPath}versions/Optifine{versionJson.Id}/libraries.zip");
            }

            if (InstallForgeOptifine)
            {
                if (!Directory.Exists($"{Settings.minecraftForlderPath}versions/Forge{versionJson.Id}/mods"))
                {
                    Settings.logger.Debug("Creating path: {0}", $"{Settings.minecraftForlderPath}versions/Forge" + versionJson.Id + "/mods");
                    Directory.CreateDirectory($"{Settings.minecraftForlderPath}versions/Forge" + versionJson.Id + "/mods");
                }

                Settings.logger.Debug("Downloading: {0}", $"Optifine{versionJson.Id}.jar");
                DownloadingFileName($"Optifine{versionJson.Id}.jar");
                webClient.DownloadFileAsync(new System.Uri(@$"https://files.veloe.link/launcher/forge/Forge{versionJson.Id}/Optifine{versionJson.Id}.jar"),
                Settings.minecraftForlderPath + "versions/Forge" + versionJson.Id + "/mods/" + "Optifine" + versionJson.Id + ".jar");
                waitWhileBisy(ref webClient);
            }

            RemoveProgressBar(webClient);
            //Progress = 100;
            Settings.logger.Debug("Downloading finished.");
            DownloadingFileName("Finished!");
            IsControlsEnabled(true);
            
            webClient.Dispose();
        }
        catch (Exception ex)
        {
            IsControlsEnabled(true);
            DownloadingFileName($"Error occured while downloading {versionJson.Id}.");
            Settings.logger.Error(ex.Message);
            if (ex.StackTrace is not null)
                Settings.logger.Error(ex.StackTrace);
            return TaskStatus.Faulted;
        }
        return TaskStatus.RanToCompletion;
    }

    public static async Task<TaskStatus> StartDownloadModpack(Action<string> DownloadingFileName,
        Action<bool> IsControlsEnabled,
        Action<WebClient> SetProgressBar,
        Action<WebClient> RemoveProgressBar,
        ObservableCollection<Entity.VersionManifest.Version> FilteredVersions,
        Modpack SelectedModpack,
        bool DownloadJava = false,
        bool InstallForge = false,
        bool InstallOptifine = false,
        bool InstallForgeOptifine = false,
        bool InstallFabric = false)
    {
        try
        {
            var FilteredVersion = FilteredVersions.Where(x => x.Id == SelectedModpack.Version).FirstOrDefault();

            if (FilteredVersion is null)
                return TaskStatus.Faulted;

            IsControlsEnabled(false);

            InstallForge = SelectedModpack.Forge;
            InstallForgeOptifine = SelectedModpack.ForgeOptifine;
            InstallOptifine = SelectedModpack.Optifine;
            InstallFabric = SelectedModpack.Fabric;

            Settings.logger.Debug("Downloading {0}.json", FilteredVersion.Id);
            DownloadingFileName($"{FilteredVersion.Id}.json");
            var versionJson = Downloader.DownloadAndDeserializeJsonData<Entity.Version.Version>(FilteredVersion.Url, Settings.minecraftForlderPath + "versions/" + FilteredVersion.Id + "/", FilteredVersion.Id + ".json");

            await Downloader.StartDownload(
                DownloadingFileName,
                IsControlsEnabled,
                SetProgressBar,
                RemoveProgressBar,
                versionJson,
                DownloadJava,
                InstallForge,
                InstallOptifine,
                InstallForgeOptifine,
                InstallFabric);

            IsControlsEnabled(false);

            string modpackUrl = string.Empty;

            if (SelectedModpack.Url is not null)
                modpackUrl = SelectedModpack.Url;
            else
                modpackUrl = $"https://files.veloe.link/launcher/modpacks/{SelectedModpack.Name}.zip";

            if (!Directory.Exists($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}"))
            {
                Settings.logger.Debug("Creating path: {0}", $"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}");
                Directory.CreateDirectory($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}");
            }

            WebClient webClient = new WebClient();

            SetProgressBar(webClient);

            Settings.logger.Debug("Downloading: {0}", $"{SelectedModpack.Name}.zip");
            DownloadingFileName($"{SelectedModpack.Name}.zip");
            webClient.DownloadFileAsync(new System.Uri(modpackUrl), Settings.minecraftForlderPath + $"versions/{SelectedModpack.Name}.zip");
            waitWhileBisy(ref webClient);

            FileStream stream = null;
            if (Directory.Exists($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/mods"))
            {
                foreach (var file in Directory.GetFiles($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/mods"))
                {
                    try { stream = File.Open(file,FileMode.Open, FileAccess.Read, FileShare.None);}
                    catch (IOException) { throw; }
                    finally { stream?.Close(); }
                }
            }
            if (Directory.Exists($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/config"))
                foreach (var file in Directory.GetFiles($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/mods"))
                {
                    try { stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.None); }
                    catch (IOException) { throw; }
                    finally { stream?.Close(); }
                }

            if (Directory.Exists($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/mods"))
                Directory.Delete($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/mods", true);
            if (Directory.Exists($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/config"))
                Directory.Delete($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/config", true);

            Settings.logger.Debug("Extracting: {0}", $"{SelectedModpack.Name}.zip");
            DownloadingFileName($"Unpacking {SelectedModpack.Name}.zip");
            ZipFile.ExtractToDirectory($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}.zip", Settings.minecraftForlderPath + $"versions/{SelectedModpack.Name}", true);
            File.Delete($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}.zip");

            File.WriteAllText($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/revision.json",JsonSerializer.Serialize(SelectedModpack.Revision));

            RemoveProgressBar(webClient);

            //Progress = 100;
            Settings.logger.Debug("Downloading {0} finished.", SelectedModpack.Name);
            DownloadingFileName($"Finished {SelectedModpack.Name}!");
            IsControlsEnabled(true);
            webClient.Dispose();

        }
        catch (Exception ex)
        {
            IsControlsEnabled(true);
            DownloadingFileName($"Error occured while downloading {SelectedModpack.Name}.");        
            ViewModelBase.OpenErrorWindow(ex);
            return TaskStatus.Faulted;
        }
        return TaskStatus.RanToCompletion;
    }

    public static T DownloadAndDeserializeJsonData<T>(string url, string path = "", string filename = "") where T : new()
    {
        using (var webClient = new HttpClient())
        {
            var jsonData = string.Empty;
            try
            {
                try
                {
                    Settings.logger.Debug($"Downloading: {url.Split('/').Last()}");
                    jsonData = webClient.GetStringAsync(url).Result;
                }
                catch (Exception ex)
                {
                    throw new WebException($"An error occured while downloading {url}. Check your internet connection.",ex);
                }
            
                if (string.IsNullOrEmpty(jsonData))
                {
                    Settings.logger.Warning("Empty string!");
                    return new T();
                }
                else
                {
                    if (!string.IsNullOrEmpty(filename) && !string.IsNullOrEmpty(path))
                    {
                        if (!Directory.Exists(path))
                        {
                            Settings.logger.Debug("Creating path: {0}", path);
                            Directory.CreateDirectory(path);
                        }
                        File.WriteAllText(path + filename, jsonData);
                    }
                    //Settings.logger.Debug("Return serialized string.");
                    return JsonSerializer.Deserialize<T>(jsonData, new JsonSerializerOptions{PropertyNameCaseInsensitive = true});
                }
                /*
                return string.IsNullOrEmpty(jsonData)
                            ? new T()
                            : JsonSerializer.Deserialize<T>(jsonData);*/
            }
            catch (Exception ex)
            {
                throw;
            }
        }
    }

    private static void waitWhileBisy(ref WebClient webClient)
    { 
        while (webClient.IsBusy)
        {
            Task.Delay(10).Wait();
        }
    }
}
