using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Threading;
using DynamicData;
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using VeloeMinecraftLauncher.Entity.Version;
using VeloeMinecraftLauncher.Entity.VersionManifest;
using VeloeMinecraftLauncher.MinecraftLauncher;
using VeloeMinecraftLauncher.Models.Entity;
using VeloeMinecraftLauncher.Views;

namespace VeloeMinecraftLauncher.ViewModels;

public class VersionsDownloaderViewModel : ViewModelBase
{
    private string _installModpackButtonText = "Download Modpack";
    private bool _showOld = false;
    private bool _showSnaps = false;
    private bool _installFabric = false;
    private bool _installForge = false;
    private bool _installOptifine = false;
    private bool _installForgeOptifine = false;
    private bool _installFabricVisible = false;
    private bool _installForgeVisible = false;
    private bool _installOptifineVisible = false;
    private bool _installForgeOptifineVisible = false;
    private bool _downloadJava = false;
    private bool _isControlsEnabled = true;
    private int _progress = 0;
    private string _downloadingFileName;

    Serilog.ILogger _logger;

    ObservableCollection<Entity.VersionManifest.Version> _filteredVersions;
    ObservableCollection<Modpack> _modpackVersions;
    Entity.VersionManifest.Version _filteredVersion;
    Modpack _selectedModpack;
    VersionManifest _versionManifest;

    public VersionsDownloaderViewModel()
    {
        try
        {
            Task.Run(() =>
            {
                _logger = Settings.logger;
                if (FilteredVersions is null)
                {
                    FilteredVersions = new();
                }
                if (ModpackVersions is null)
                {
                    ModpackVersions = new();
                }
                _logger.Debug("Getting versionManifest.json");
                _versionManifest = Downloader.DownloadAndDeserializeJsonData<VersionManifest>("https://launchermeta.mojang.com/mc/game/version_manifest_v2.json");
                ModpackVersions.AddRange(Downloader.DownloadAndDeserializeJsonData<List<Modpack>>("https://files.veloe.link/launcher/modpacks.json"));
                _logger.Debug("Updating available versions to download.");
                updateList();
            });
        }
        catch (Exception ex)
        {
            OpenErrorWindow(ex);
        }
    }

    public Entity.VersionManifest.Version FilteredVersion
    {
        get { return _filteredVersion; }
        set { 
            this.RaiseAndSetIfChanged(ref _filteredVersion, value);

            InstallFabric = false;
            InstallForge = false;
            InstallOptifine = false;
            InstallForgeOptifine = false;
            try
            {
                using (var httpClient = new HttpClient())
                {

                    var response = httpClient.GetAsync(@$"https://files.veloe.link/launcher/forge/Forge{value.Id}/Forge{value.Id}.json").Result;

                    if (response.IsSuccessStatusCode)
                    {
                        InstallForgeVisible = true;
                        response = httpClient.GetAsync(@$"https://files.veloe.link/launcher/forge/Forge{value.Id}/Optifine{value.Id}.jar").Result;
                        if (response.IsSuccessStatusCode)
                            InstallForgeOptifineVisible = true;
                    }
                    else
                    {
                        InstallForgeVisible = false;
                        InstallForgeOptifineVisible = false;
                    }

                        response = httpClient.GetAsync(@$"https://files.veloe.link/launcher/fabric/Fabric{value.Id}/Fabric{value.Id}.json").Result;

                    if (response.IsSuccessStatusCode)
                        InstallFabricVisible = true;
                    else
                        _installFabricVisible = false;

                    response = httpClient.GetAsync(@$"https://files.veloe.link/launcher/optifine/Optifine{value.Id}/Optifine{value.Id}.json").Result;

                    if (response.IsSuccessStatusCode)
                        InstallOptifineVisible = true;
                    else
                        InstallOptifineVisible = false;
                

                }
            }
            catch (Exception ex)
            {
                OpenErrorWindow(ex);
            }
        }
    }

    public Modpack SelectedModpack
    {
        get => _selectedModpack;
        set
        {
            try
            {
                if (System.IO.File.Exists(Settings.minecraftForlderPath + $"versions/{value.Name}/revision.json"))
                {               
                    if (value.Revision > JsonSerializer.Deserialize<int>(System.IO.File.ReadAllText(Settings.minecraftForlderPath + $"versions/{value.Name}/revision.json")))
                        InstallModpackButtonText = "Update Modpack";
                    else
                        InstallModpackButtonText = "Reinstall Modpack";              
                }
                else
                    if (System.IO.Directory.Exists($"{Settings.minecraftForlderPath}versions/{value.Name}") && System.IO.File.Exists($"{Settings.minecraftForlderPath}versions/{value.Name}/{value.Name}.json"))
                        InstallModpackButtonText = "Update Modpack";
                    else
                        InstallModpackButtonText = "Download Modpack";
            }
            catch (Exception)
            {
                InstallModpackButtonText = "Update Modpack";
            }
            this.RaiseAndSetIfChanged(ref _selectedModpack, value); 
        }
    }

    public ObservableCollection<Entity.VersionManifest.Version> FilteredVersions
    {
        get => _filteredVersions; 
        set => this.RaiseAndSetIfChanged(ref _filteredVersions, value);
    }

    public ObservableCollection<Models.Entity.Modpack> ModpackVersions
    {
        get => _modpackVersions;
        set => this.RaiseAndSetIfChanged(ref _modpackVersions, value);
    }

    public string InstallModpackButtonText
    {
        get => _installModpackButtonText; 
        set => this.RaiseAndSetIfChanged(ref _installModpackButtonText, value);
    }

    public bool ShowOld
    {
        get => _showOld;
        set { 
            this.RaiseAndSetIfChanged(ref _showOld, value);
            updateList();
        }
    }

    public bool ShowSnaps
    {
        get => _showSnaps;
        set { 
            this.RaiseAndSetIfChanged(ref _showSnaps, value);
            updateList();
        }
    }

    public int Progress
    {
        get => _progress;
        set => this.RaiseAndSetIfChanged(ref _progress, value);
    }

    public string DownloadingFileName
    {
        get => _downloadingFileName;
        set => this.RaiseAndSetIfChanged(ref _downloadingFileName, value);
    }

    public bool InstallForge
    {
        get => _installForge;
        set
        {
            this.RaiseAndSetIfChanged(ref _installForge, value);

            if (InstallFabric)
                InstallFabric = false;
        }
    }

    public bool InstallFabric
    {
        get => _installFabric;
        set
        {
            this.RaiseAndSetIfChanged(ref _installFabric, value);
            if (InstallForge)
                InstallForge = false;
        }
    }

    public bool InstallOptifine
    {
        get => _installOptifine;
        set => this.RaiseAndSetIfChanged(ref _installOptifine, value);
    }

    public bool InstallForgeOptifine
    {
        get { return _installForgeOptifine; }
        set
        {
            this.RaiseAndSetIfChanged(ref _installForgeOptifine, value);
            if (value)
                InstallForge = true;
        }
    }

    public bool InstallForgeVisible
    {
        get => _installForgeVisible;
        set => this.RaiseAndSetIfChanged(ref _installForgeVisible, value);
    }

    public bool InstallFabricVisible
    {
        get => _installFabricVisible;
        set => this.RaiseAndSetIfChanged(ref _installFabricVisible, value);
    }

    public bool InstallOptifineVisible
    {
        get => _installOptifineVisible;
        set => this.RaiseAndSetIfChanged(ref _installOptifineVisible, value);
    }

    public bool InstallForgeOptifineVisible
    {
        get => _installForgeOptifineVisible;
        set => this.RaiseAndSetIfChanged(ref _installForgeOptifineVisible, value);
    }

    public bool DownloadJava
    {
        get => _downloadJava;
        set => this.RaiseAndSetIfChanged(ref _downloadJava, value);
    }

    public bool IsControlsEnabled
    {
        get => _isControlsEnabled;
        set => this.RaiseAndSetIfChanged(ref _isControlsEnabled, value);
    }

    public async Task OnStartBunttonClick()
    {
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
        Task.Run(() => {

            if (FilteredVersion is null)
                return TaskStatus.Faulted;

            _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");

            if (versionJson is not null)
                Downloader.StartDownload(
                  value => DownloadingFileName = value,
                  value => IsControlsEnabled = value,
                  value => value.DownloadProgressChanged += WebClient_DownloadProgressChanged,
                  value => value.DownloadProgressChanged -= WebClient_DownloadProgressChanged,
                  versionJson,
                  DownloadJava,
                  InstallForge,
                  InstallOptifine,
                  InstallForgeOptifine,
                  InstallFabric);
        return TaskStatus.RanToCompletion; });
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
    }
  
    public async void OnStartModpackBunttonClick()
    {
        if (SelectedModpack is null)
            return;

        FilteredVersion = FilteredVersions.Where(x => x.Id == SelectedModpack.Version).FirstOrDefault();

        if (FilteredVersion is null)
            return;

#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
        Task.Run(() => Downloader.StartDownloadModpack(
            value => DownloadingFileName = value,
            value => IsControlsEnabled = value,
            value => value.DownloadProgressChanged += WebClient_DownloadProgressChanged,
            value => value.DownloadProgressChanged -= WebClient_DownloadProgressChanged,
            FilteredVersions,
            SelectedModpack,
            DownloadJava,
            InstallFabric = SelectedModpack.Fabric,
            InstallForge = SelectedModpack.Forge,
            InstallOptifine = SelectedModpack.Optifine,
            InstallForgeOptifine = SelectedModpack.ForgeOptifine));
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
    }

    private void WebClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
    {
        Progress = e.ProgressPercentage;
    }

    public void updateList()
    {
        try
        {
            FilteredVersions.Clear();

            if (_versionManifest.Versions is null)
                return;

            FilteredVersions.AddRange(_versionManifest.Versions.Where(version => ShowSnaps && version.Type == "snapshot" || ShowOld && version.Type is ("old_alpha" or "old_beta") || version.Type == "release"));
        }
        catch (Exception ex)
        {
            OpenErrorWindow(ex);
        }
    }
}
