using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Microsoft.Extensions.DependencyInjection;
using OF_DL.Helpers;
using OF_DL.Services;
using Serilog;

namespace OF_DL.Gui;

public static class Program
{
    private static int s_hasProcessedUnhandledException;

    public static bool HidePrivateInfo { get; private set; }

    public static void Main(string[] args)
    {
        try
        {
            // Parse command line arguments
            HidePrivateInfo = args.Contains("--hide-private-info", StringComparer.OrdinalIgnoreCase);

            ServiceCollection services = new();
            services.AddSingleton<ILoggingService, LoggingService>();
            ServiceProvider tempProvider = services.BuildServiceProvider();
            ILoggingService loggingService = tempProvider.GetRequiredService<ILoggingService>();

            RegisterGlobalExceptionHandlers();
            Log.Information("Starting OF DL GUI");

            // Check if running in Docker and print a message
            if (EnvironmentHelper.IsRunningInDocker())
            {
                Console.WriteLine(
                    "In your web browser, navigate to the port forwarded from your docker container. For instance, if your docker run command included \"-p 8080:8080\", open your web browser to \"http://localhost:8080\".");
            }

            BuildAvaloniaApp()
                .StartWithClassicDesktopLifetime(args);
        }
        catch (Exception ex)
        {
            HandleUnhandledException(ex, "Program.Main", isTerminating: true);
        }
        finally
        {
            Log.CloseAndFlush();
        }
    }

    private static AppBuilder BuildAvaloniaApp() =>
        AppBuilder.Configure<App>()
            .UsePlatformDetect()
            .LogToTrace();

    private static void RegisterGlobalExceptionHandlers()
    {
        AppDomain.CurrentDomain.UnhandledException += (_, eventArgs) =>
        {
            HandleUnhandledException(eventArgs.ExceptionObject as Exception,
                "AppDomain.CurrentDomain.UnhandledException",
                eventArgs.IsTerminating);
        };

        TaskScheduler.UnobservedTaskException += (_, eventArgs) =>
        {
            HandleUnhandledException(eventArgs.Exception, "TaskScheduler.UnobservedTaskException",
                isTerminating: false);
            eventArgs.SetObserved();
        };
    }

    private static void HandleUnhandledException(Exception? exception, string source, bool isTerminating)
    {
        if (Interlocked.Exchange(ref s_hasProcessedUnhandledException, 1) != 0)
        {
            return;
        }

        try
        {
            if (exception != null)
            {
                Log.Fatal(exception, "Unhandled exception from {Source}. Terminating={IsTerminating}",
                    source, isTerminating);
                Console.WriteLine($"Unhandled exception from {source}: {exception}");
            }
            else
            {
                Log.Fatal("Unhandled non-exception object from {Source}. Terminating={IsTerminating}",
                    source, isTerminating);
                Console.WriteLine($"Unhandled non-exception object from {source}.");
            }
        }
        finally
        {
            Log.CloseAndFlush();
        }

        if (!isTerminating &&
            Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime)
        {
            desktopLifetime.Shutdown(1);
        }
    }
}
