using GmRelay.Web.Components;
using GmRelay.Web.Services;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.DataProtection;
using System.Security.Claims;
using Telegram.Bot;
using Npgsql;

var builder = WebApplication.CreateBuilder(args);

// Add Aspire service defaults
builder.AddServiceDefaults();

// Add Data Protection
builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo("/app/dataprotection-keys"));

// Add Npgsql
builder.AddNpgsqlDataSource("gmrelaydb");

// Add Services
builder.Services.AddSingleton<TelegramAuthService>();
builder.Services.AddSingleton<ISessionStore, SessionService>();
builder.Services.AddScoped<AuthorizedSessionService>();
builder.Services.AddScoped<CalendarSubscriptionService>();

// Add Bot Client
builder.Services.AddSingleton<ITelegramBotClient>(sp =>
{
    var config = sp.GetRequiredService<IConfiguration>();
    var token = config["Telegram__BotToken"] ?? config["Telegram:BotToken"]
        ?? throw new InvalidOperationException("Telegram__BotToken is required.");
    return new TelegramBotClient(token);
});

// Add Authentication with hardened cookie settings
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.LoginPath = "/login";
        options.AccessDeniedPath = "/access-denied";
        options.Cookie.HttpOnly = true;
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
        options.Cookie.SameSite = SameSiteMode.Strict;
        options.ExpireTimeSpan = TimeSpan.FromDays(7);
        options.SlidingExpiration = true;
    });

builder.Services.AddAuthorization();
builder.Services.AddCascadingAuthenticationState();

// Add services to the container.
builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error", createScopeForErrors: true);
    app.UseHsts();
}

app.UseHttpsRedirection();

// Security headers middleware
app.Use(async (context, next) =>
{
    context.Response.Headers["X-Content-Type-Options"] = "nosniff";
    context.Response.Headers["X-Frame-Options"] = "DENY";
    context.Response.Headers["Referrer-Policy"] = "strict-origin-when-cross-origin";
    context.Response.Headers["Permissions-Policy"] = "camera=(), microphone=(), geolocation=()";
    await next();
});

app.UseAuthentication();
app.UseAuthorization();
app.UseAntiforgery();

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

// Endpoint to handle Telegram Login callback
app.MapGet("/auth/telegram", async (HttpContext context, TelegramAuthService authService) =>
{
    if (authService.Verify(context.Request.Query, out var telegramId, out var name))
    {
        var authProperties = new AuthenticationProperties { IsPersistent = true };
        await context.SignInAsync(
            CookieAuthenticationDefaults.AuthenticationScheme,
            CreateTelegramPrincipal(telegramId, name),
            authProperties);
        return Results.Redirect("/");
    }

    return Results.Redirect("/login?error=auth_failed");
});

app.MapPost("/auth/telegram-webapp", async (
    HttpContext context,
    TelegramAuthService authService,
    TelegramWebAppAuthRequest request) =>
{
    if (!authService.VerifyWebAppInitData(request.InitData, out var telegramId, out var name))
    {
        return Results.Unauthorized();
    }

    var authProperties = new AuthenticationProperties { IsPersistent = true };
    await context.SignInAsync(
        CookieAuthenticationDefaults.AuthenticationScheme,
        CreateTelegramPrincipal(telegramId, name),
        authProperties);

    return Results.Ok(new { redirectUrl = "/" });
}).DisableAntiforgery();

app.MapPost("/auth/telegram-login", async (
    HttpContext context,
    TelegramAuthService authService,
    TelegramLoginPayload request) =>
{
    if (!authService.VerifyLoginPayload(request, out var telegramId, out var name))
    {
        return Results.Unauthorized();
    }

    var authProperties = new AuthenticationProperties { IsPersistent = true };
    await context.SignInAsync(
        CookieAuthenticationDefaults.AuthenticationScheme,
        CreateTelegramPrincipal(telegramId, name),
        authProperties);

    return Results.Ok(new { redirectUrl = "/" });
}).DisableAntiforgery();

app.MapGet("/auth/status", (HttpContext context) =>
    Results.Ok(new { authenticated = context.User.Identity?.IsAuthenticated == true }));

app.MapPost("/auth/logout", async (HttpContext context) =>
{
    await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    return Results.Redirect("/");
});

// Public calendar subscription endpoint (no auth required)
app.MapGet("/calendar/{token}.ics", async (
    string token,
    CalendarSubscriptionService service,
    CancellationToken ct) =>
{
    try
    {
        var ics = await service.GetIcsAsync(token, ct);
        var bytes = System.Text.Encoding.UTF8.GetBytes(ics);
        return Results.File(bytes, "text/calendar", "schedule.ics");
    }
    catch (SubscriptionNotFoundException)
    {
        return Results.NotFound();
    }
});

app.Run();

static ClaimsPrincipal CreateTelegramPrincipal(long telegramId, string name)
{
    var claims = new List<Claim>
    {
        new(ClaimTypes.NameIdentifier, telegramId.ToString(System.Globalization.CultureInfo.InvariantCulture)),
        new(ClaimTypes.Name, name),
        new("TelegramId", telegramId.ToString(System.Globalization.CultureInfo.InvariantCulture))
    };

    var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
    return new ClaimsPrincipal(claimsIdentity);
}

public sealed record TelegramWebAppAuthRequest(string InitData);
