using Avalonia;
using ClaudeDo.Data;
using ClaudeDo.Data.Git;
using ClaudeDo.Localization;
using ClaudeDo.Releases;
using ClaudeDo.Ui;
using ClaudeDo.Ui.Localization;
using ClaudeDo.Ui.Services;
using ClaudeDo.Ui.Services.Interfaces;
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.Globalization;
using System.IO;
using System.Linq;
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();

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

        try
        {
            ConfigureAppBuilder(AppBuilder.Configure(() => new App(services)))
                .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 */
            }
        }
    }

    // Parameterless entry point required by the XAML previewer / designer.
    public static AppBuilder BuildAvaloniaApp()
        => ConfigureAppBuilder(AppBuilder.Configure<App>());

    private static AppBuilder ConfigureAppBuilder(AppBuilder builder)
        => builder
            .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);
        var localesDir = Path.Combine(AppContext.BaseDirectory, "locales");
        var localeStore = LocaleStore.Load(localesDir);
        var initialLang = !string.IsNullOrWhiteSpace(settings.Language)
            ? settings.Language
            : CultureResolver.Resolve(
                CultureInfo.CurrentUICulture.Name,
                localeStore.Available.Select(l => l.Code).ToArray(),
                fallback: "en");
        var localizer = new Localizer(localeStore, initialLang);
        TrExtension.Localizer = localizer;
        ClaudeDo.Ui.Localization.Loc.Current = localizer;
        sc.AddSingleton<ILocalizer>(localizer);
        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));
        sc.AddSingleton<IWorkerClient>(sp => sp.GetRequiredService<WorkerClient>());

        // Release check + installer update
        sc.AddSingleton<HttpClient>(_ =>
            new HttpClient(new SocketsHttpHandler { PooledConnectionLifetime = TimeSpan.FromMinutes(5) })
                { Timeout = TimeSpan.FromSeconds(10) });
        sc.AddSingleton<IReleaseClient>(sp => new ReleaseClient(sp.GetRequiredService<HttpClient>()));
        sc.AddSingleton<InstallerLocator>();
        sc.AddSingleton<WorkerLocator>();
        sc.AddSingleton(sp =>
        {
            var releases = sp.GetRequiredService<IReleaseClient>();
            var informational = Assembly.GetEntryAssembly()?
                .GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion;
            // Strip MinVer build metadata ("+sha") only — keep the prerelease suffix
            // (e.g. "-alpha.0.14"), VersionComparer needs it to tell a dev build on
            // main apart from a tagged release of the same numeric core.
            var version = (informational ?? "0.0.0").Split('+')[0];
            return new UpdateCheckService(releases, version);
        });

        // Conflict-merge coordinator: single seam the shell wires to its resolver entry.
        sc.AddSingleton<MergeCoordinator>();

        // ViewModels
        sc.AddTransient<DiffViewerViewModel>();
        sc.AddTransient<Func<DiffViewerViewModel>>(sp => () => sp.GetRequiredService<DiffViewerViewModel>());
        sc.AddTransient<WorktreesOverviewModalViewModel>();
        sc.AddTransient<Func<WorktreesOverviewModalViewModel>>(sp =>
            () => sp.GetRequiredService<WorktreesOverviewModalViewModel>());
        sc.AddTransient<MergeHelperSelectionModalViewModel>();
        sc.AddSingleton<IPrimeScheduleApi, WorkerPrimeScheduleApi>();
        sc.AddSingleton<INotesApi, WorkerNotesApi>();
        sc.AddSingleton<OnlineLoginService>();
        sc.AddTransient<PrimeClaudeTabViewModel>();
        sc.AddTransient<SettingsModalViewModel>();
        sc.AddTransient<MergeModalViewModel>();
        sc.AddTransient<Func<MergeModalViewModel>>(sp => () => sp.GetRequiredService<MergeModalViewModel>());
        sc.AddTransient<ListSettingsModalViewModel>();
        sc.AddTransient<RepoImportModalViewModel>();
        sc.AddTransient<Func<RepoImportModalViewModel>>(sp => () => sp.GetRequiredService<RepoImportModalViewModel>());
        sc.AddTransient<WeeklyReportModalViewModel>();
        sc.AddTransient<Func<WeeklyReportModalViewModel>>(sp =>
            () => sp.GetRequiredService<WeeklyReportModalViewModel>());
        sc.AddTransient<UsageMonitorModalViewModel>();
        sc.AddTransient<Func<UsageMonitorModalViewModel>>(sp =>
            () => sp.GetRequiredService<UsageMonitorModalViewModel>());
        sc.AddSingleton<Func<string, ClaudeDo.Ui.ViewModels.Conflicts.ConflictResolverViewModel>>(sp =>
            taskId => new ClaudeDo.Ui.ViewModels.Conflicts.ConflictResolverViewModel(
                sp.GetRequiredService<IWorkerClient>(), taskId));

        // Islands shell VMs
        sc.AddSingleton<ListsIslandViewModel>(sp =>
            new ListsIslandViewModel(
                sp.GetRequiredService<IDbContextFactory<ClaudeDoDbContext>>(),
                sp,
                sp.GetRequiredService<IWorkerClient>()));
        sc.AddSingleton<TasksIslandViewModel>(sp =>
            new TasksIslandViewModel(
                sp.GetRequiredService<IDbContextFactory<ClaudeDoDbContext>>(),
                sp.GetRequiredService<IWorkerClient>(),
                sp.GetRequiredService<INotesApi>()));
        sc.AddSingleton<DetailsIslandViewModel>(sp =>
            new DetailsIslandViewModel(
                sp.GetRequiredService<IDbContextFactory<ClaudeDoDbContext>>(),
                sp.GetRequiredService<IWorkerClient>(),
                sp,
                sp.GetRequiredService<MergeCoordinator>()));
        sc.AddSingleton<UsagePillViewModel>(sp =>
            new UsagePillViewModel(sp.GetRequiredService<IWorkerClient>()));
        sc.AddSingleton<MissionControlViewModel>(sp =>
            new MissionControlViewModel(
                sp.GetRequiredService<IDbContextFactory<ClaudeDoDbContext>>(),
                sp.GetRequiredService<IWorkerClient>(),
                sp.GetRequiredService<UsagePillViewModel>()));
        sc.AddSingleton<IslandsShellViewModel>(sp =>
        {
            var shell = ActivatorUtilities.CreateInstance<IslandsShellViewModel>(sp);
            shell.ConflictResolverFactory =
                sp.GetRequiredService<Func<string, ClaudeDo.Ui.ViewModels.Conflicts.ConflictResolverViewModel>>();
            sp.GetRequiredService<MergeCoordinator>().Handler = shell.RequestConflictResolutionAsync;
            return shell;
        });

        return sc.BuildServiceProvider();
    }
}
