using Dapper;
using DbController.TypeHandler;
using FluentValidation;
using Microsoft.AspNetCore.Authentication.Cookies;
using System.Reflection;
using Tabletop.Core.Middlewares;
using Tabletop.Core.Services;
using Tabletop.Hubs;

namespace Tabletop
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // Dapper TypeHandler Konfiguration
            SqlMapper.AddTypeHandler(new GuidTypeHandler());
            SqlMapper.RemoveTypeMap(typeof(Guid));
            SqlMapper.RemoveTypeMap(typeof(Guid?));

            var config = builder.Configuration;

            // Add services to the container
            builder.Services.AddRazorPages();
            builder.Services.AddServerSideBlazor()
                .AddCircuitOptions(options =>
                {
                    options.DetailedErrors = true;
                });

            builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
                {
                    options.LoginPath = "/Account/Login";           // Umleitung bei nicht angemeldetem Zugriff
                    options.SlidingExpiration = true;                // Verlängert die Session automatisch
                    options.ExpireTimeSpan = TimeSpan.FromMinutes(60); // Session läuft nach 60 Minuten ab
                });

            // Scoped Services für deine Anwendung
            builder.Services.AddScoped<PermissionService>();
            builder.Services.AddScoped<UserService>();
            builder.Services.AddScoped<AuthService>();
            builder.Services.AddScoped<UnitService>();
            builder.Services.AddScoped<AbilityService>();
            builder.Services.AddScoped<WeaponService>();
            builder.Services.AddScoped<GamemodeService>();
            builder.Services.AddScoped<FractionService>();
            builder.Services.AddScoped<GameService>();
            builder.Services.AddScoped<PlayerService>();
            builder.Services.AddScoped<TemplateService>();
            builder.Services.AddScoped<LayoutService>();
            builder.Services.AddScoped<SurfaceService>();
            builder.Services.AddScoped<ConnectionLogService>();
            builder.Services.AddScoped<GeolocationService>();

            // **HttpClient für GeolocationService**
            builder.Services.AddHttpClient(); // Registriert IHttpClientFactory, das HttpClient für GeolocationService bereitstellt.

            // Lokalisierung konfigurieren
            builder.Services.AddLocalization(options =>
            {
                options.ResourcesPath = "Languages";
            });

            // Konfiguration aus `appsettings.json` laden
            builder.Configuration.AddJsonFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "appsettings.json"), optional: false, reloadOnChange: true);

            // Hinzufügen von Controllern für MVC-Unterstützung
            builder.Services.AddControllersWithViews();

            // FluentValidation-Setup
            builder.Services.AddValidatorsFromAssembly(Assembly.LoadFrom(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Tabletop.Core.dll")));

            // SignalR für Echtzeitkommunikation mit Hub
            builder.Services.AddSignalR(options =>
            {
                options.KeepAliveInterval = TimeSpan.FromSeconds(15); // Häufigkeit der Heartbeats
                options.ClientTimeoutInterval = TimeSpan.FromMinutes(30); // Timeout für den Client
                options.EnableDetailedErrors = false; 
            });

            // **Session-Middleware hinzufügen und konfigurieren**
            builder.Services.AddDistributedMemoryCache(); // Session-Caching konfigurieren
            builder.Services.AddSession(options =>
            {
                options.IdleTimeout = TimeSpan.FromMinutes(30);  // Timeout für die Session (optional)
                options.Cookie.HttpOnly = true;  // Sicherstellen, dass Cookies nur über HTTP zugänglich sind
                options.Cookie.IsEssential = true;  // Sicherstellen, dass das Cookie für die Funktionsweise der App erforderlich ist
            });

            var app = builder.Build();

            // **Wichtige Reihenfolge der Middleware**

            // **Session Middleware aktivieren**
            app.UseSession();  // Die Session muss vor Authentifizierung und Autorisierung aufgerufen werden

            // Registriere die Middleware in der Request-Pipeline
            app.UseMiddleware<ConnectionLogMiddleware>();

            // Initialisiere App-Daten
            using var serviceScope = app.Services.CreateScope();
            var services = serviceScope.ServiceProvider;
            await AppdataService.InitAsync(builder.Configuration);

            // HTTP Request-Pipeline konfigurieren
            if (!app.Environment.IsDevelopment())
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }

            // Lokalisierungsoptionen anwenden
            var localizationOptions = new RequestLocalizationOptions()
                .SetDefaultCulture(AppdataService.SupportedCultures[0].Name)
                .AddSupportedCultures(AppdataService.SupportedCultureCodes)
                .AddSupportedUICultures(AppdataService.SupportedCultureCodes);

            app.UseRequestLocalization(localizationOptions);

            // Middleware für HTTPS, statische Dateien und Routing
            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseRouting();

            // **Session Middleware muss vor Authentication und Authorization sein**
            app.UseAuthentication();  // Authentifizierungsmiddleware
            app.UseAuthorization();   // Autorisierungsmiddleware

            // Endpunkte für Blazor, SignalR und Controller
            app.MapControllers();
            app.MapBlazorHub();
            app.MapHub<LobbyHub>("/Lobbyhub"); // SignalR-Endpunkt für Echtzeitkommunikation
            app.MapHub<GameHub>("/Gamehub"); // SignalR-Endpunkt für Echtzeitkommunikation
            app.MapFallbackToPage("/_Host");

            app.Run();
        }

        public static string GetVersion()
        {
            return Assembly.GetEntryAssembly()!.GetName()!.Version!.ToString(3);
        }
    }
}
