using System.Reflection;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
using Avalonia.Threading;
using Mlaumcherb.Client.Avalonia.классы;
using Mlaumcherb.Client.Avalonia.холопы;
using MsBox.Avalonia;
using MsBox.Avalonia.Dto;
using MsBox.Avalonia.Models;

namespace Mlaumcherb.Client.Avalonia.зримое;

public partial class MainWindow : Window
{
    public static readonly StyledProperty<string> PlayerNameProperty =
        AvaloniaProperty.Register<MainWindow, string>(nameof(PlayerName),
            defaultBindingMode: BindingMode.TwoWay);
    public string PlayerName
    {
        get => GetValue(PlayerNameProperty);
        set => SetValue(PlayerNameProperty, value);
    }
    
    public static readonly StyledProperty<int> MemoryLimitProperty =
        AvaloniaProperty.Register<MainWindow, int>(nameof(MemoryLimit),
            defaultBindingMode: BindingMode.TwoWay, defaultValue: 2048);
    public int MemoryLimit
    {
        get => GetValue(MemoryLimitProperty);
        set => SetValue(MemoryLimitProperty, value);
    }
    
    public static readonly StyledProperty<bool> UpdateGameFilesProperty =
        AvaloniaProperty.Register<MainWindow, bool>(nameof(UpdateGameFiles),
            defaultBindingMode: BindingMode.TwoWay, defaultValue: false);
    public bool UpdateGameFiles
    {
        get => GetValue(UpdateGameFilesProperty);
        set => SetValue(UpdateGameFilesProperty, value);
    }
    
    
    public static readonly StyledProperty<bool> EnableJavaDownloadProperty =
        AvaloniaProperty.Register<MainWindow, bool>(nameof(EnableJavaDownload),
            defaultBindingMode: BindingMode.TwoWay, defaultValue: true);
    public bool EnableJavaDownload
    {
        get => GetValue(EnableJavaDownloadProperty);
        set => SetValue(EnableJavaDownloadProperty, value);
    }
    
    public static readonly StyledProperty<bool> RedirectGameOutputProperty =
        AvaloniaProperty.Register<MainWindow, bool>(nameof(RedirectGameOutput),
            defaultBindingMode: BindingMode.TwoWay, defaultValue: false);
    public bool RedirectGameOutput
    {
        get => GetValue(RedirectGameOutputProperty);
        set => SetValue(RedirectGameOutputProperty, value);
    }
    
    public MainWindow()
    {
        InitializeComponent();
    }
    
    protected override void OnLoaded(RoutedEventArgs e)
    {
        try
        {
            LauncherApp.Logger.OnLogMessage += GuiLogMessage;
            LauncherVersionTextBox.Text = $"v {Assembly.GetExecutingAssembly().GetName().Version}";

            PlayerName = LauncherApp.Config.player_name;
            MemoryLimit = LauncherApp.Config.max_memory;
            EnableJavaDownload = LauncherApp.Config.download_java;
            RedirectGameOutput = LauncherApp.Config.redirect_game_output;
            
            foreach (var vc in LauncherApp.Config.version_catalogs)
            {
                RemoteVersionCatalogComboBox.Items.Add(vc);
            }
            RemoteVersionCatalogComboBox.SelectedIndex = 0;
            
            UpdateInstalledVersionsCatalogView(LauncherApp.Config.last_launched_version);
        }
        catch (Exception ex)
        {
            ErrorHelper.ShowMessageBox(nameof(MainWindow), ex);
        }
    }

    private void UpdateInstalledVersionsCatalogView(string? selectVersion)
    {
        LauncherApp.InstalledVersionCatalog.CheckInstalledVersions();
        InstalledVersionCatalogComboBox.IsEnabled = false;
        InstalledVersionCatalogComboBox.Items.Clear();
        foreach (var p in LauncherApp.InstalledVersionCatalog.versions)
        {
            InstalledVersionCatalogComboBox.Items.Add(new InstalledGameVersionItemView(p.Value));
        }
        
        InstalledVersionCatalogComboBox.SelectedItem = null;
        if(selectVersion is not null 
           && LauncherApp.InstalledVersionCatalog.versions.TryGetValue(selectVersion, out var props))
        {
            foreach (InstalledGameVersionItemView? view in InstalledVersionCatalogComboBox.Items)
            {
                if (view?.Props.Id == props.Id)
                {
                    InstalledVersionCatalogComboBox.SelectedItem = view;
                    break;
                }
            }
        }
        
        InstalledVersionCatalogComboBox.IsEnabled = true;
    }

    private void RescanInstalledVersionsButton_OnClick(object? sender, RoutedEventArgs e)
    {
        var selectedVersionView = InstalledVersionCatalogComboBox.SelectedItem as InstalledGameVersionItemView;
        UpdateInstalledVersionsCatalogView(selectedVersionView?.Props.Id);
    }
    
    private void GuiLogMessage(LauncherLogger.LogMessage msg)
    {
        if (msg.severity == LogSeverity.Debug) return;

        Dispatcher.UIThread.Invoke(() =>
        {
            double offsetFromBottom = LogScrollViewer.Extent.Height - LogScrollViewer.Offset.Y - LogScrollViewer.Viewport.Height;
            bool is_scrolled_to_end = offsetFromBottom < 20.0; // scrolled less then one line up 
            LogPanel.Children.Add(new LogMessageView(msg));
            if (is_scrolled_to_end) LogScrollViewer.ScrollToEnd();
        });
    }

    private async void Запуск(object? sender, RoutedEventArgs e)
    {
        try
        {
            if (InstalledVersionCatalogComboBox.SelectedItem is not InstalledGameVersionItemView selectedVersionView) 
                return;
            
            Dispatcher.UIThread.Invoke(() => LaunchButton.IsEnabled = false);
            LauncherApp.Config.last_launched_version = selectedVersionView.Props.Id;
            LauncherApp.Config.player_name = PlayerName;
            LauncherApp.Config.max_memory = MemoryLimit;
            LauncherApp.Config.download_java = EnableJavaDownload;
            LauncherApp.Config.redirect_game_output = RedirectGameOutput;
            LauncherApp.Config.SaveToFile();
            
            var v = await selectedVersionView.Props.LoadDescriptor(UpdateGameFiles);
            await v.Download(UpdateGameFiles, nt =>
                {
                    Dispatcher.UIThread.Invoke(() =>
                    {
                        DownloadsPanel.Children.Add(new NetworkTaskView(nt,
                            ntv => DownloadsPanel.Children.Remove(ntv)));
                    });
                }
            );
            Dispatcher.UIThread.Invoke(() =>
            {
                UpdateGameFiles = false;
            });
            await v.Launch();
        }
        catch (Exception ex)
        {
            ErrorHelper.ShowMessageBox(nameof(MainWindow), ex);
        }
        finally
        {
            Dispatcher.UIThread.Invoke(() => LaunchButton.IsEnabled = true);
        }
    }

    private void ОткрытьПапкуЛаунчера(object? s, RoutedEventArgs e)
    {
        try
        {

            string workingDir = Directory.GetCurrent().ToString();
            LauncherApp.Logger.LogDebug(nameof(MainWindow), 
                $"opening working directory: {workingDir}");
            Launcher.LaunchDirectoryInfoAsync(new DirectoryInfo(workingDir))
                .ConfigureAwait(false);
        }
        catch (Exception ex)
        {
            ErrorHelper.ShowMessageBox(nameof(MainWindow), ex);
        }
    }
    
    private void ОткрытьФайлЛогов(object? sender, RoutedEventArgs e)
    {
        try
        {
            string logFilePath = LauncherApp.Logger.LogFilePath.ToString();
            LauncherApp.Logger.LogDebug(nameof(MainWindow), 
                $"opening log file: {logFilePath}");
            Launcher.LaunchFileInfoAsync(new FileInfo(logFilePath))
                .ConfigureAwait(false);
        }
        catch (Exception ex)
        {
            ErrorHelper.ShowMessageBox(nameof(MainWindow), ex);
        }
    }

    private void ОткрытьРепозиторий(object? sender, RoutedEventArgs e)
    {
        try
        {
            var sourcesUri = new Uri(LauncherApp.Config.gitea.GetRepoUrl());
            LauncherApp.Logger.LogDebug(nameof(MainWindow), 
                $"opening in web browser: {sourcesUri}");
            Launcher.LaunchUriAsync(sourcesUri)
                .ConfigureAwait(false);
        }
        catch (Exception ex)
        {
            ErrorHelper.ShowMessageBox(nameof(MainWindow), ex);
        }
    }

    private void ClearLogPanel(object? sender, RoutedEventArgs e)
    {
        LogPanel.Children.Clear();
    }
    
    
    private void ClearDownloadsPanel(object? sender, RoutedEventArgs e)
    {
        foreach (var control in DownloadsPanel.Children)
        {
            var nt = (NetworkTaskView)control;
            nt.Task.Cancel();
        }
        DownloadsPanel.Children.Clear();
    }
    
    private async void SearchVersionsButton_OnClick(object? sender, RoutedEventArgs e)
    {
        try 
        {
            if(RemoteVersionCatalogComboBox.SelectedItem is not GameVersionCatalogProps catalogProps)
                return;

            var catalog = await catalogProps.GetVersionCatalogAsync();
            var searchParams = new VersionSearchParams
            {
                ReleaseTypeAllowed = ReleaseVersionTypeCheckBox.IsChecked ?? false,
                SnapshotTypeAllowed = SnapshotVersionTypeCheckBox.IsChecked ?? false,
                OldTypeAllowed = OldVersionTypeCheckBox.IsChecked ?? false,
                OtherTypeAllowed = OtherVersionTypeAlphaCheckBox.IsChecked ?? false
            };
            var versions = catalog.GetDownloadableVersions(searchParams);
            
            Dispatcher.UIThread.Invoke(() =>
            {
                RemoteVersionCatalogItemsComboBox.IsEnabled = false;
                RemoteVersionCatalogItemsComboBox.Items.Clear();
                foreach (var p in versions)
                {
                    RemoteVersionCatalogItemsComboBox.Items.Add(new RemoteGameVersionItemView(p));
                }
                RemoteVersionCatalogItemsComboBox.IsEnabled = true;
                AddVersionButton.IsEnabled = versions.Count > 0;
            });
        }
        catch (Exception ex)
        {
           ErrorHelper.ShowMessageBox(nameof(MainWindow), ex);
        }
    }

    private void AddVersionButton_OnClick(object? sender, RoutedEventArgs e)
    {
        try
        {
            if(RemoteVersionCatalogComboBox.SelectedItem is not GameVersionCatalogProps catalogProps)
                return;
            
            if(RemoteVersionCatalogItemsComboBox.SelectedItem is not RemoteGameVersionItemView sel)
                return;
            
            var installedProps = new InstalledGameVersionProps(sel.Props.id, catalogProps, sel.Props);
            if (!LauncherApp.InstalledVersionCatalog.versions.TryAdd(sel.Props.id, installedProps))
                throw new Exception("Версия уже была добавлена");
            LauncherApp.InstalledVersionCatalog.Save();
            
            var propsView = new InstalledGameVersionItemView(installedProps);
            InstalledVersionCatalogComboBox.Items.Insert(0, propsView);
            InstalledVersionCatalogComboBox.SelectedItem = propsView;
        }
        catch (Exception ex)
        {
            ErrorHelper.ShowMessageBox(nameof(MainWindow), ex);
        }
    }

    private async void DeleteVersionButton_OnClick(object? sender, RoutedEventArgs e)
    {
        try
        {
            if(InstalledVersionCatalogComboBox.SelectedItem is not InstalledGameVersionItemView sel)
                return;
        
            var box = MessageBoxManager.GetMessageBoxCustom(new MessageBoxCustomParams
                {
                    ButtonDefinitions = new List<ButtonDefinition> { new() { Name = "Да" }, new() { Name = "Нет" } },
                    ContentTitle = $"Удаление версии {sel.Props.Id}",
                    ContentMessage = $"Вы уверены, что хотите удалить версию {sel.Props.Id}? Все файлы, включая сохранения, будут удалены!",
                    Icon = MsBox.Avalonia.Enums.Icon.Question,
                    WindowStartupLocation = WindowStartupLocation.CenterOwner,
                    SizeToContent = SizeToContent.WidthAndHeight,
                    ShowInCenter = true,
                    Topmost = true
                }
            );
            var result = await box.ShowAsync().ConfigureAwait(false);
            if (result != "Да") 
                return;
            
            sel.Props.Delete();
            Dispatcher.UIThread.Invoke(() =>
            {
                InstalledVersionCatalogComboBox.Items.Remove(sel);
                LauncherApp.InstalledVersionCatalog.versions.Remove(sel.Props.Id);
                LauncherApp.InstalledVersionCatalog.Save();
            });
        }
        catch (Exception ex)
        {
            ErrorHelper.ShowMessageBox(nameof(MainWindow), ex);
        }
    }
}