using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core.Plugins;
using Avalonia.Markup.Xaml;
using AvaloniaLoggingDI.ViewModels;
using AvaloniaLoggingDI.Views;
using LogViewer.Avalonia;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using MsBox.Avalonia;
using MsBox.Avalonia.Enums;
using MsLogger.Core;
using RandomLogging.Service;
using System;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Threading;
using Icon = MsBox.Avalonia.Enums.Icon;

namespace AvaloniaLoggingDI;

public partial class App : Application
{
    public override void Initialize()
        => AvaloniaXamlLoader.Load(this);

    public override void OnFrameworkInitializationCompleted()
    {
        if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
        {
            // Avoid duplicate validations from both Avalonia and the CommunityToolkit. 
            // More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
            DisableAvaloniaDataAnnotationValidation();

            // catch all unhandled errors
            AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;

            HostApplicationBuilder builder = Host.CreateApplicationBuilder();

            builder
                /*
                 * Note: For information on launch profiles for debugging,
                 *     see article: https://www.codeproject.com/Articles/5354478/NET-App-Settings-Demystified-Csharp-VB
                 */

                // Register the Random Logging Service
                .AddRandomBackgroundService()

                // visual debugging tools
                .AddLogViewer()

                // Microsoft Logger
                //.Logging.AddDefaultDataStoreLogger();

                // uncomment to use custom logging colors (note: System.Drawing namespace)
                //
                .Logging.AddDefaultDataStoreLogger(options =>
                {
                    options.Colors[LogLevel.Trace] = new()
                    {
                        Foreground = Color.White,
                        Background = Color.DarkGray
                    };

                    options.Colors[LogLevel.Debug] = new()
                    {
                        Foreground = Color.White,
                        Background = Color.Gray
                    };

                    options.Colors[LogLevel.Information] = new()
                    {
                        Foreground = Color.White,
                        Background = Color.DodgerBlue
                    };

                    options.Colors[LogLevel.Warning] = new()
                    {
                        Foreground = Color.White,
                        Background = Color.Orchid
                    };
                });

            IServiceCollection services = builder.Services;

            services
                .AddSingleton<MainViewModel>()
                .AddSingleton<MainWindow>(service => new MainWindow
                {
                    DataContext = service.GetRequiredService<MainViewModel>()
                });

            _host = builder.Build();
            _cancellationTokenSource = new();

            try
            {
                LogStartingMode();

                // set and show
                desktop.MainWindow = _host.Services.GetRequiredService<MainWindow>();
                desktop.ShutdownRequested += OnShutdownRequested;

                // startup background services
                _ = _host.StartAsync(_cancellationTokenSource.Token);
            }
            catch (OperationCanceledException)
            {
                // skip
            }
            catch (Exception ex)
            {
                ShowMessageBox("Unhandled Error", ex.Message);
                return;
            }
        }

        base.OnFrameworkInitializationCompleted();
    }
    private static void DisableAvaloniaDataAnnotationValidation()
    {
        // Get an array of plugins to remove
        var dataValidationPluginsToRemove = BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();

        // remove each entry found
        foreach (var plugin in dataValidationPluginsToRemove)
        {
            BindingPlugins.DataValidators.Remove(plugin);
        }
    }
    private void OnShutdownRequested(object? sender, ShutdownRequestedEventArgs e)
        => _ = _host!.StopAsync(_cancellationTokenSource!.Token);

    #region Fields

    private IHost? _host;
    private CancellationTokenSource? _cancellationTokenSource;

    #endregion

    private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
        => ShowMessageBox("Unhandled Error", ((Exception)e.ExceptionObject).Message);

    private static void ShowMessageBox(string title, string message)
    {
        var box = MessageBoxManager.GetMessageBoxStandard(
                "Exception",
                text: message,
                ButtonEnum.Ok,
                Icon.Stop
            );
        _ = box.ShowAsync().GetAwaiter();
      }

    private void LogStartingMode()
    {
        // Get the Launch mode
        bool isDevelopment = string.Equals(Environment.GetEnvironmentVariable("DOTNET_MODIFIABLE_ASSEMBLIES"), "debug",
            StringComparison.OrdinalIgnoreCase);

        // initialize a logger & EventId
        ILogger<App> logger = _host!.Services.GetRequiredService<ILogger<App>>();
        EventId eventId = new EventId(id: 0, name: Assembly.GetEntryAssembly()!.GetName().Name);

        // log a test pattern for each log level
        logger.TestPattern(eventId: eventId);

        // log that we have started...
        logger.Emit(eventId, LogLevel.Information, $"Running in {(isDevelopment ? "Debug" : "Release")} mode");
    }
}