using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.OpenApi.Models;

using Serilog;

using watcher_monitoring.Configuration;
using watcher_monitoring.Data;

var builder = WebApplication.CreateBuilder(args);

// Serilog konfigurieren – nur Logs, die nicht von Microsoft stammen
Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .MinimumLevel.Override("Microsoft", Serilog.Events.LogEventLevel.Warning)
    .Enrich.FromLogContext()
    .WriteTo.File(
        "logs/watcher-.log",
        outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss}] [{Level:u3}] {Message:lj}{NewLine}{Exception}",
        rollingInterval: RollingInterval.Day
    )
    .CreateLogger();

builder.Host.UseSerilog();

// ---------- Konfiguration ----------
DotNetEnv.Env.Load();
builder.Configuration.AddEnvironmentVariables();

// OIDC-Einstellungen laden
var oidcSettings = OidcSettings.FromEnvironment();
builder.Services.AddSingleton(oidcSettings);

// Konfiguration laden
var configuration = builder.Configuration;

// DbContext - Nur SQLite wird unterstützt
var sqliteConnectionString = configuration.GetConnectionString("Sqlite")
    ?? configuration["Database:ConnectionStrings:Sqlite"]
    ?? "Data Source=./persistence/watcher.db";

builder.Services.AddDbContext<WatcherDbContext>((serviceProvider, options) =>
{
    options.UseSqlite(sqliteConnectionString);
});

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

// Cookie-basierte Authentifizierung
var authBuilder = builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.LoginPath = "/Auth/Login";
        options.LogoutPath = "/Auth/Logout";
        options.AccessDeniedPath = "/Auth/AccessDenied";
        options.ExpireTimeSpan = TimeSpan.FromHours(8);
        options.SlidingExpiration = true;
        options.Cookie.HttpOnly = true;
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
        options.Cookie.SameSite = SameSiteMode.Lax;
    });

// OIDC-Authentifizierung (wenn aktiviert)
if (oidcSettings.IsValid)
{
    Log.Information("OIDC-Authentifizierung aktiviert für Authority: {Authority}", oidcSettings.Authority);
    authBuilder.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
    {
        options.Authority = oidcSettings.Authority;
        options.ClientId = oidcSettings.ClientId;
        options.ClientSecret = oidcSettings.ClientSecret;
        options.ResponseType = OpenIdConnectResponseType.Code;
        options.SaveTokens = true;
        options.GetClaimsFromUserInfoEndpoint = true;
        options.CallbackPath = oidcSettings.CallbackPath;
        options.SignedOutCallbackPath = "/signout-callback-oidc";

        options.Scope.Clear();
        foreach (var scope in oidcSettings.GetScopes())
        {
            options.Scope.Add(scope);
        }

        options.TokenValidationParameters.NameClaimType = oidcSettings.ClaimUsername;
        options.TokenValidationParameters.RoleClaimType = "roles";
    });
}
else if (oidcSettings.Enabled)
{
    Log.Warning("OIDC ist aktiviert aber nicht korrekt konfiguriert. Erforderlich: OIDC_AUTHORITY, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET");
}

builder.Services.AddAuthorization();

// Health Checks
builder.Services.AddHealthChecks();

// Swagger API-Dokumentation
builder.Services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1", new OpenApiInfo { Title = "Watcher-Server API", Version = "v1" });

    // Nur API-Controller dokumentieren (mit [ApiController]-Attribut)
    options.DocInclusionPredicate((docName, apiDesc) =>
    {
        var controllerActionDescriptor = apiDesc.ActionDescriptor as Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor;
        if (controllerActionDescriptor == null) return false;

        // Nur Controller mit [ApiController]-Attribut einbeziehen
        return controllerActionDescriptor.ControllerTypeInfo
            .GetCustomAttributes(typeof(ApiControllerAttribute), true).Any();
    });
});

var app = builder.Build();

// Stelle sicher, dass das persistence-Verzeichnis existiert
var persistenceDir = Path.Combine(Directory.GetCurrentDirectory(), "persistence");
if (!Directory.Exists(persistenceDir))
{
    Log.Information("Erstelle persistence-Verzeichnis: {PersistenceDir}", persistenceDir);
    Directory.CreateDirectory(persistenceDir);
}

// Datenbank-Migration beim Start ausführen
using (var scope = app.Services.CreateScope())
{
    var dbContext = scope.ServiceProvider.GetRequiredService<WatcherDbContext>();
    try
    {
        Log.Information("Führe Datenbank-Migrationen aus...");
        dbContext.Database.Migrate();
        Log.Information("Datenbank-Migrationen erfolgreich angewendet");

        // Standard-Admin-User erstellen, falls noch kein User existiert
        if (!dbContext.Users.Any())
        {
            Log.Information("Erstelle Standard-Admin-User...");
            var adminUser = new watcher_monitoring.Models.User
            {
                Username = "admin",
                Email = "admin@watcher.local",
                Password = BCrypt.Net.BCrypt.HashPassword("admin"),
                IsActive = true,
                CreatedAt = DateTime.UtcNow,
                LastLogin = DateTime.UtcNow
            };
            dbContext.Users.Add(adminUser);
            dbContext.SaveChanges();
            Log.Information("Standard-Admin-User erstellt (Username: admin, Passwort: admin)");
        }
    }
    catch (Exception ex)
    {
        Log.Error(ex, "Fehler beim Ausführen der Datenbank-Migrationen");
        throw;
    }
}

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

// 🔹 Swagger aktivieren
app.UseSwagger();
app.UseSwaggerUI(options =>
{
    options.SwaggerEndpoint("/swagger/v1/swagger.json", "Watcher-Server API v1");
    options.RoutePrefix = "api/v1/swagger";
});

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

// Health Check Endpoint
app.MapHealthChecks("/health");

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();
