using System.Text;
using AccountTracking.Api.Data;
using AccountTracking.Api.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Polly;

var builder = WebApplication.CreateBuilder(args);

// ── Configuration ──────────────────────────────────────────────────────────
var connectionString = builder.Configuration["DB_CONNECTION"];
var jwtSecret = builder.Configuration["JWT_SECRET"]
    ?? throw new InvalidOperationException("JWT_SECRET is required");
var appUsername = builder.Configuration["APP_USERNAME"]
    ?? throw new InvalidOperationException("APP_USERNAME is required");
var appPassword = builder.Configuration["APP_PASSWORD"]
    ?? throw new InvalidOperationException("APP_PASSWORD is required");
var allowedOrigin = builder.Configuration["ALLOWED_ORIGIN"] ?? "http://localhost:3000";

// ── Database ────────────────────────────────────────────────────────────────
if (!string.IsNullOrEmpty(connectionString))
{
    builder.Services.AddDbContext<AppDbContext>(opts =>
        opts.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)));
}
else
{
    // NSwag build-time spec generation: no real DB available
    builder.Services.AddDbContext<AppDbContext>(opts =>
        opts.UseInMemoryDatabase("nswag_gen"));
}

// ── Services ────────────────────────────────────────────────────────────────
builder.Services.AddScoped<CsvImportService>();
builder.Services.AddScoped<DashboardService>();

// ── Auth ────────────────────────────────────────────────────────────────────
var keyBytes = Convert.FromBase64String(jwtSecret);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(opts =>
    {
        opts.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(keyBytes),
            ValidateIssuer = false,
            ValidateAudience = false,
            ClockSkew = TimeSpan.Zero
        };
    });
builder.Services.AddAuthorization();

// Store credentials for use by AuthController
builder.Services.AddSingleton(new AppCredentials(appUsername, appPassword, keyBytes));

// ── CORS ────────────────────────────────────────────────────────────────────
builder.Services.AddCors(opts =>
{
    opts.AddDefaultPolicy(policy =>
        policy.WithOrigins(allowedOrigin, "http://localhost:3000")
              .AllowAnyHeader()
              .AllowAnyMethod());
});

// ── Controllers & OpenAPI ───────────────────────────────────────────────────
builder.Services.AddControllers();
builder.Services.AddOpenApiDocument(config =>
{
    config.Title = "AccountTracking API";
    config.Version = "v1";
    config.AddSecurity("Bearer", new NSwag.OpenApiSecurityScheme
    {
        Type = NSwag.OpenApiSecuritySchemeType.Http,
        Scheme = "bearer",
        BearerFormat = "JWT"
    });
});

// ── Kestrel: limit upload to 10 MB ─────────────────────────────────────────
builder.WebHost.ConfigureKestrel(opts =>
    opts.Limits.MaxRequestBodySize = 10 * 1024 * 1024);

var app = builder.Build();

// ── Migrate DB (skip when running without a real DB) ───────────────────────
if (!string.IsNullOrEmpty(connectionString))
{
    var retryPolicy = Policy
        .Handle<Exception>()
        .WaitAndRetry(
            5,
            attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt - 1)),
            (ex, delay, attempt, _) =>
                Console.WriteLine($"DB migration attempt {attempt} failed: {ex.Message}. Retrying in {delay.TotalSeconds}s..."));

    using var scope = app.Services.CreateScope();
    var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
    retryPolicy.Execute(() => db.Database.Migrate());
}

// ── Middleware pipeline ─────────────────────────────────────────────────────
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.UseOpenApi();
app.UseSwaggerUi();
app.MapControllers();

app.Run();

// Accessible by tests
public partial class Program { }

// Credential container registered in DI
public record AppCredentials(string Username, string PasswordHash, byte[] JwtKeyBytes);
