using Avalonia;
using ClaudeDo.Data;
using ClaudeDo.Data.Git;
using ClaudeDo.Releases;
using ClaudeDo.Ui;
using ClaudeDo.Ui.Services;
using ClaudeDo.Ui.ViewModels;
using ClaudeDo.Ui.ViewModels.Islands;
using ClaudeDo.Ui.ViewModels.Modals;
using ClaudeDo.Ui.ViewModels.Modals.Settings;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Net.Http;
using System.Reflection;
using System.Runtime.InteropServices;

namespace ClaudeDo.App;

sealed class Program
{
    [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
    private static extern int SetCurrentProcessExplicitAppUserModelID(string appId);

    [STAThread]
    public static void Main(string[] args)
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            SetCurrentProcessExplicitAppUserModelID("ClaudeDo.App");

        var services = BuildServices();
        App.Services = services;

        using (var scope = services.CreateScope())
        {
            var db = scope.ServiceProvider.GetRequiredService<ClaudeDoDbContext>();
            ClaudeDoDbContext.MigrateAndConfigure(db);
        }

        try
        {
            BuildAvaloniaApp()
                .StartWithClassicDesktopLifetime(args);
        }
        finally
        {
            // Dispose the container so WorkerClient.DisposeAsync runs —
            // cancels the retry loop and closes the SignalR connection cleanly
            // instead of abandoning it.
            try { services.DisposeAsync().AsTask().GetAwaiter().GetResult(); }
            catch { /* best effort on shutdown */ }
        }
    }

    public static AppBuilder BuildAvaloniaApp()
        => AppBuilder.Configure<App>()
            .UsePlatformDetect()
#if DEBUG
            .WithDeveloperTools()
#endif
            .WithInterFont()
            .LogToTrace();

    private static ServiceProvider BuildServices()
    {
        var settings = AppSettings.Load();
        var dbPath = Paths.Expand(settings.DbPath);

        var sc = new ServiceCollection();

        // Infrastructure
        sc.AddSingleton(settings);
        sc.AddDbContextFactory<ClaudeDoDbContext>(opt =>
            opt.UseSqlite($"Data Source={dbPath}"));
        sc.AddScoped<ClaudeDoDbContext>(sp =>
            sp.GetRequiredService<IDbContextFactory<ClaudeDoDbContext>>().CreateDbContext());

        // Services
        sc.AddSingleton<GitService>();
        sc.AddSingleton(sp => new WorkerClient(sp.GetRequiredService<AppSettings>().SignalRUrl));

        // Release check + installer update
        sc.AddSingleton<HttpClient>(_ => new HttpClient { Timeout = TimeSpan.FromSeconds(10) });
        sc.AddSingleton<IReleaseClient>(sp => new ReleaseClient(sp.GetRequiredService<HttpClient>()));
        sc.AddSingleton<InstallerLocator>();
        sc.AddSingleton(sp =>
        {
            var releases = sp.GetRequiredService<IReleaseClient>();
            var informational = Assembly.GetEntryAssembly()?
                .GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion;
            // Strip MinVer build metadata ("+sha") and any prerelease suffix for the update-compare.
            var version = (informational ?? "0.0.0").Split('+')[0];
            return new UpdateCheckService(releases, version);
        });

        // ViewModels
        sc.AddTransient<WorktreeModalViewModel>();
        sc.AddTransient<Func<WorktreeModalViewModel>>(sp => () => sp.GetRequiredService<WorktreeModalViewModel>());
        sc.AddTransient<WorktreesOverviewModalViewModel>();
        sc.AddTransient<Func<WorktreesOverviewModalViewModel>>(sp => () => sp.GetRequiredService<WorktreesOverviewModalViewModel>());
        sc.AddSingleton<IPrimeScheduleApi, WorkerPrimeScheduleApi>();
        sc.AddTransient<PrimeClaudeTabViewModel>();
        sc.AddTransient<SettingsModalViewModel>();
        sc.AddTransient<MergeModalViewModel>();
        sc.AddTransient<Func<MergeModalViewModel>>(sp => () => sp.GetRequiredService<MergeModalViewModel>());
        sc.AddTransient<ListSettingsModalViewModel>();

        // Islands shell VMs
        sc.AddSingleton<ListsIslandViewModel>(sp =>
            new ListsIslandViewModel(
                sp.GetRequiredService<IDbContextFactory<ClaudeDoDbContext>>(),
                sp,
                sp.GetRequiredService<WorkerClient>()));
        sc.AddSingleton<TasksIslandViewModel>(sp =>
            new TasksIslandViewModel(
                sp.GetRequiredService<IDbContextFactory<ClaudeDoDbContext>>(),
                sp.GetRequiredService<WorkerClient>()));
        sc.AddSingleton<DetailsIslandViewModel>(sp =>
            new DetailsIslandViewModel(
                sp.GetRequiredService<IDbContextFactory<ClaudeDoDbContext>>(),
                sp.GetRequiredService<WorkerClient>(),
                sp));
        sc.AddSingleton<IslandsShellViewModel>();

        return sc.BuildServiceProvider();
    }
}
