
using System.Text;
using System.Text.Json.Serialization;
using FluentValidation;
using FluentValidation.AspNetCore;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Prometheus;
using Serilog;
using StackExchange.Redis;

try
{
    var builder = WebApplication.CreateBuilder(args);

    if (!builder.Environment.IsEnvironment("Testing"))
        builder.Host.UseSerilog((ctx, _, cfg) => cfg.ReadFrom.Configuration(ctx.Configuration));

    builder.Services.AddDbContext<GatewayDbContext>(opts =>
        opts.UseNpgsql(builder.Configuration.GetConnectionString("GatewayDb")));

    builder.Services.AddSingleton<IConnectionMultiplexer>(sp =>
        ConnectionMultiplexer.Connect(builder.Configuration["Redis:ConnectionString"]!));

    builder.Services.Configure<GatewayOptions>(builder.Configuration.GetSection(GatewayOptions.Section));
    builder.Services.Configure<CentralApiOptions>(builder.Configuration.GetSection(CentralApiOptions.Section));
    builder.Services.Configure<RabbitMqOptions>(builder.Configuration.GetSection(RabbitMqOptions.Section));
    builder.Services.Configure<SuppressionOptions>(builder.Configuration.GetSection(SuppressionOptions.SectionName));

    var jwt = builder.Configuration.GetSection("Jwt");
    builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(o =>
        {
            o.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = jwt["Issuer"],
                ValidAudience = jwt["Audience"],
                IssuerSigningKey = new SymmetricSecurityKey(
                    Encoding.UTF8.GetBytes(jwt["SigningKey"]!))
            };
        });
    builder.Services.AddAuthorization();

    builder.Services.AddFluentValidationAutoValidation();
    builder.Services.AddValidatorsFromAssemblyContaining<Program>();

    builder.Services.AddHttpClient("central");

    builder.Services.AddSingleton<CentralReachabilityService>();
    builder.Services.AddHostedService(sp => sp.GetRequiredService<CentralReachabilityService>());
    builder.Services.AddHostedService<GatewayHeartbeatService>();
    builder.Services.AddHostedService<EncounterReplicaSyncService>();
    builder.Services.AddHostedService<SyncUploaderService>();
    builder.Services.AddHostedService<ThresholdCacheLoader>();

    builder.Services.AddSingleton<RabbitMqTopologyProvisioner>();
    builder.Services.AddHostedService(sp => sp.GetRequiredService<RabbitMqTopologyProvisioner>());
    builder.Services.AddSingleton<LocalPagingPublisher>();
    builder.Services.AddHostedService<LocalPagingWorkerService>();
    builder.Services.AddHostedService<LocalEscalationWorkerService>();
    builder.Services.AddScoped<LocalWarningEvaluator>();
    builder.Services.AddScoped<ILocalObservationService, LocalObservationService>();
    builder.Services.AddScoped<IObservationQueryService, ObservationQueryService>();
    builder.Services.AddScoped<ILocalAlertService, LocalAlertService>();
    builder.Services.AddScoped<IEncounterReadService, EncounterReadService>();

    // Add services to the container.

    builder.Services.AddHealthChecks()
        .AddDbContextCheck<GatewayDbContext>("postgresql", tags: ["ready"])
        .AddCheck<RedisHealthCheck>("redis", tags: ["ready"])
        .AddCheck<RabbitMqHealthCheck>("rabbitmq", tags: ["ready"])
        .AddCheck<EncounterReplicaReadyCheck>("encounter_replica", tags: ["ready"]);

    builder.Services.AddControllers()
    .AddJsonOptions(o => o.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));

    builder.Services.AddCors(o => o.AddPolicy("Dashboard", p =>
        p.WithOrigins("http://localhost:5173").AllowAnyHeader().AllowAnyMethod()));
    // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen();

    var app = builder.Build();

    app.UseMiddleware<ExceptionHandlerMiddleware>();

    // Configure the HTTP request pipeline.
    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }

    if (!app.Environment.IsEnvironment("Testing"))
    {
        app.UseSerilogRequestLogging();
    }

    app.UseCors("Dashboard");
    app.UseAuthentication();
    app.UseAuthorization();
    app.UseHttpMetrics();
    app.MapControllers();
    app.MapMetrics("/metrics");

    app.MapHealthChecks("/health/live", new()
    {
        Predicate = _ => false,
        ResponseWriter = HealthCheckResponseWriter.WriteAsync
    });
    app.MapHealthChecks("/health/ready", new()
    {
        Predicate = c => c.Tags.Contains("ready"),
        ResponseWriter = HealthCheckResponseWriter.WriteAsync
    });

    // Startup migration is the proven path for this single-instance edge host.
    // Gate with Gateway:AutoMigrate so production can switch to an out-of-band
    // EF migration bundle later without a code change (Phase 36 Step 6).
    if (!app.Environment.IsEnvironment("Testing")
        && builder.Configuration.GetValue("Gateway:AutoMigrate", true))
    {
        using var scope = app.Services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<GatewayDbContext>();
        await db.Database.MigrateAsync();
    }

    app.Run();
}
catch (System.Exception)
{
    
    throw;
}


public partial class Program { }