using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
using WishNinja.Components;
using WishNinja.Components.Account;
using WishNinja.Configuration;
using WishNinja.Data;
using WishNinja.Services;

var builder = WebApplication.CreateBuilder(args);

// --- Options ---------------------------------------------------------------------------------
builder.Services.Configure<WishNinjaOptions>(builder.Configuration.GetSection(WishNinjaOptions.SectionName));
var appOptions = builder.Configuration.GetSection(WishNinjaOptions.SectionName).Get<WishNinjaOptions>() ?? new WishNinjaOptions();

var dataPath = Path.GetFullPath(appOptions.DataPath);
Directory.CreateDirectory(dataPath);

// Connection string: explicit override wins, otherwise derive from the data path.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
    ?? $"Data Source={Path.Combine(dataPath, "wishninja.db")};Cache=Shared";

// --- Blazor + auth state ---------------------------------------------------------------------
builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();

builder.Services.AddCascadingAuthenticationState();
builder.Services.AddScoped<IdentityRedirectManager>();
builder.Services.AddScoped<AuthenticationStateProvider, IdentityRevalidatingAuthenticationStateProvider>();

builder.Services.AddAuthentication(options =>
    {
        options.DefaultScheme = IdentityConstants.ApplicationScheme;
        options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
    })
    .AddIdentityCookies();

// --- EF Core + Identity ----------------------------------------------------------------------
// Factory for short-lived contexts (used by interactive Blazor components and app services),
// plus a scoped context resolved from the factory for ASP.NET Core Identity's stores.
builder.Services.AddDbContextFactory<ApplicationDbContext>(options => options.UseSqlite(connectionString));
builder.Services.AddScoped<ApplicationDbContext>(sp =>
    sp.GetRequiredService<IDbContextFactory<ApplicationDbContext>>().CreateDbContext());
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddIdentityCore<ApplicationUser>(options =>
    {
        options.SignIn.RequireConfirmedAccount = true;
        options.Stores.SchemaVersion = IdentitySchemaVersions.Version3;
    })
    .AddRoles<IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddSignInManager()
    .AddDefaultTokenProviders();

// --- Data protection (persist keys so cookies survive container restarts) --------------------
builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(Path.Combine(dataPath, "keys")))
    .SetApplicationName("WishNinja");

// --- App services ----------------------------------------------------------------------------
builder.Services.AddSingleton<EmailSender>();
builder.Services.AddSingleton<IAppEmailSender>(sp => sp.GetRequiredService<EmailSender>());
builder.Services.AddSingleton<IEmailSender<ApplicationUser>>(sp => sp.GetRequiredService<EmailSender>());
builder.Services.AddHttpClient("image-fetch", c =>
{
    c.Timeout = TimeSpan.FromSeconds(15);
    c.DefaultRequestHeaders.UserAgent.ParseAdd("WishNinja/1.0");
});
builder.Services.AddSingleton<ImageService>();
builder.Services.AddScoped<WishlistService>();
builder.Services.AddScoped<InviteService>();

// Respect reverse-proxy headers (Unraid + SWAG / NPM) so scheme/host are correct.
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
    options.KnownIPNetworks.Clear();
    options.KnownProxies.Clear();
});

var app = builder.Build();

app.UseForwardedHeaders();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error", createScopeForErrors: true);
    app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true);

app.UseAntiforgery();

app.MapStaticAssets();

// Serve uploaded item images from the data volume.
var imageService = app.Services.GetRequiredService<ImageService>();
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(imageService.UploadsDirectory),
    RequestPath = "/uploads",
});

app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode();

// Add additional endpoints required by the Identity /Account Razor components.
app.MapAdditionalIdentityEndpoints();

// Apply migrations and seed roles + bootstrap admin.
await StartupInitializer.InitializeAsync(app.Services, app.Configuration,
    app.Services.GetRequiredService<ILoggerFactory>().CreateLogger("Startup"));

app.Run();

// Exposed for integration testing.
public partial class Program;
