using Mbproxy;
using Mbproxy.Admin;
using Mbproxy.Diagnostics;
using Mbproxy.Options;
using Mbproxy.Proxy;
using Microsoft.Extensions.Hosting.WindowsServices;
using Microsoft.Extensions.Options;

var builder = Host.CreateApplicationBuilder(args);

// Windows Service support; no-op when running under dotnet run / console.
builder.Services.AddWindowsService();

// Phase 08: wire EventLogBridge only when actually running as a Windows Service.
bool isWindowsService = WindowsServiceHelpers.IsWindowsService();

// Wire up structured config, Serilog, and typed options.
builder.AddMbproxySerilog(addEventLogBridge: isWindowsService);
builder.AddMbproxyOptions();

// PDU pipeline: BcdPduPipeline is stateless (Phase 9: per-call correlation flows through
// PerPlcContext.CurrentRequest set by the multiplexer); registering as singleton is fine
// and avoids repeated construction.
builder.Services.AddSingleton<IPduPipeline, BcdPduPipeline>();

// Proxy worker — owns all PlcListeners and logs mbproxy.startup.ready.
// Registered as singleton so StatusSnapshotBuilder can inject ProxyWorker directly
// and access its Supervisors dictionary.
builder.Services.AddSingleton<ProxyWorker>();
builder.Services.AddHostedService(sp => sp.GetRequiredService<ProxyWorker>());

// Phase 07: admin endpoint (Kestrel read-only status page).
builder.AddMbproxyAdmin();

// Phase 08: graceful-shutdown coordinator.
// ShutdownCoordinator depends on PlcListenerSupervisor instances via ProxyWorker.Supervisors.
// Registered as a singleton so Program can resolve it after the host is built.
builder.Services.AddSingleton<ShutdownCoordinator>(sp =>
{
    var worker  = sp.GetRequiredService<ProxyWorker>();
    var admin   = sp.GetRequiredService<AdminEndpointHost>();
    var options = sp.GetRequiredService<IOptions<MbproxyOptions>>();
    var logger  = sp.GetRequiredService<ILogger<ShutdownCoordinator>>();
    // Supervisors is populated after ProxyWorker.StartAsync; the coordinator only
    // enumerates them during ShutdownAsync, which runs on ApplicationStopping —
    // after the host is fully started.
    return new ShutdownCoordinator(
        worker.Supervisors.Values,
        admin,
        options,
        logger);
});

var host = builder.Build();

// Wire ApplicationStopping → ShutdownCoordinator BEFORE hosted services start.
// The callback fires when the host signals stop; it drains in-flight PDUs and stops
// the admin endpoint before the host tears down individual services.
var lifetime = host.Services.GetRequiredService<IHostApplicationLifetime>();
lifetime.ApplicationStopping.Register(() =>
{
    // IHostApplicationLifetime callbacks do not support async — block briefly.
    // The coordinator manages its own drain deadline so the host is not held indefinitely.
    var coordinator = host.Services.GetRequiredService<ShutdownCoordinator>();
    coordinator.ShutdownAsync().GetAwaiter().GetResult();
});

await host.RunAsync();
