using ClaudeDo.Data;
using ClaudeDo.Data.Git;
using ClaudeDo.Data.Repositories;
using ClaudeDo.Worker.Config;
using ClaudeDo.Worker.Hub;
using ClaudeDo.Worker.Runner;
using ClaudeDo.Worker.Services;
using Microsoft.EntityFrameworkCore;

var cfg = WorkerConfig.Load();

var builder = WebApplication.CreateBuilder(args);

// When launched by the Windows SCM, speak the Service Control Protocol so SCM
// doesn't think we crashed (~30s timeout). No-op when running interactively.
builder.Host.UseWindowsService(o => o.ServiceName = "ClaudeDoWorker");

builder.Services.AddDbContextFactory<ClaudeDoDbContext>(opt =>
    opt.UseSqlite($"Data Source={cfg.DbPath}"));

builder.Services.AddSingleton(cfg);
builder.Services.AddHostedService<StaleTaskRecovery>();
builder.Services.AddSignalR();

// Runner stack.
builder.Services.AddSingleton<IClaudeProcess, ClaudeProcess>();
builder.Services.AddSingleton<HubBroadcaster>();
builder.Services.AddSingleton<GitService>();
builder.Services.AddSingleton<WorktreeManager>();
builder.Services.AddSingleton<ClaudeArgsBuilder>();
builder.Services.AddSingleton<TaskRunner>();
builder.Services.AddSingleton<WorktreeMaintenanceService>();
builder.Services.AddSingleton<TaskResetService>();
builder.Services.AddSingleton<TaskMergeService>();

// Agent file management.
var agentsDir = Path.Combine(ClaudeDo.Data.Paths.AppDataRoot(), "agents");
Directory.CreateDirectory(agentsDir);
builder.Services.AddSingleton(new AgentFileService(agentsDir));

var defaultAgentsBundleDir = Path.Combine(AppContext.BaseDirectory, "DefaultAgents");
builder.Services.AddSingleton(sp => new DefaultAgentSeeder(
    defaultAgentsBundleDir,
    agentsDir,
    sp.GetService<Microsoft.Extensions.Logging.ILogger<DefaultAgentSeeder>>()));

// QueueService: singleton + hosted service (same instance).
builder.Services.AddSingleton<QueueService>();
builder.Services.AddHostedService(sp => sp.GetRequiredService<QueueService>());

// Loopback-only bind. Firewall is irrelevant for 127.0.0.1.
builder.WebHost.UseUrls($"http://127.0.0.1:{cfg.SignalRPort}");

var app = builder.Build();

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

try
{
    var seeder = app.Services.GetRequiredService<DefaultAgentSeeder>();
    var seedResult = await seeder.SeedMissingAsync();
    app.Logger.LogInformation(
        "Default agents seeded: {Copied} copied, {Skipped} already present",
        seedResult.Copied, seedResult.Skipped);
}
catch (Exception ex)
{
    app.Logger.LogWarning(ex, "Default agent seeding failed");
}

app.MapHub<WorkerHub>("/hub");

app.Logger.LogInformation("ClaudeDo.Worker listening on http://127.0.0.1:{Port} (db: {Db})",
    cfg.SignalRPort, cfg.DbPath);

app.Run();
