using DAL;
using HRD.AppLogger;
using HRD.WebApi;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NLog.Web;
using StaffDBServer.Extends;
using StaffDBServer.SharedExtensions;
using System;
using System.Reflection;
using HRD.LDAPService.JWT;
using HRD.WebApi.DAL.Middleware;
using HRD.WebApi.Helpers;
using StaffDBServer.SharedControllers;
using HRD.LDAPService;
using Microsoft.AspNetCore.Server.IISIntegration;
using NSwag.Generation.Processors.Security;
using NSwag;
using System.Linq;
using Microsoft.Extensions.PlatformAbstractions;
using Microsoft.AspNetCore.Mvc;

AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs unhandledExceptionEventArgs) =>
{
    ILoggerManager logger = new LoggerManager();
    logger.LogException((Exception)unhandledExceptionEventArgs.ExceptionObject, "Application closed due to exception.");
    NLog.LogManager.Flush();
};

ILoggerManager logger = new LoggerManager();
logger.LogWarn($"[Start WebApi Server] BaseDirectory: {AppDomain.CurrentDomain.BaseDirectory}; TargetFrameworkName: {AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName}");

try
{
    var builder = WebApplication.CreateBuilder(args);

    var configuration = builder.Configuration;
    WebApiConfig.Init(configuration, Assembly.GetExecutingAssembly().GetName());

    // Configure logging
    builder.Logging.ClearProviders();
    builder.Logging.SetMinimumLevel(LogLevel.Warning);
    builder.Host.UseNLog();

    // Add services to the container
    // at first
    //services.AddCors();
    builder.Services.AddCustomCors("AllowAllOrigins");

    builder.Services.Configure<IISOptions>(options =>
    {
        options.AuthenticationDisplayName = "Windows";
        options.ForwardClientCertificate = true;
        options.AutomaticAuthentication = true;
    });
    builder.Services.AddAuthentication(IISDefaults.AuthenticationScheme);

    builder.Services.ConfigureJWT(StaffDBServer.Extends.JwtMiddlewareOptionsHelper.GetJwtMiddlewareOptions()); ;

    builder.Services.ConfigureDAL(WebApiMiddlewareOptionsHelper.GetWebApiMiddlewareOptions());

    builder.Services.AddSingleton<ILoggerManager, LoggerManager>();

    //SWAGGER
    builder.Services.AddSwaggerDocument(config =>
    {
        #region add Bearer Authorization

        config.AddSecurity("JWT", Enumerable.Empty<string>(), new OpenApiSecurityScheme
        {
            Type = OpenApiSecuritySchemeType.ApiKey,
            Name = "Authorization",
            In = OpenApiSecurityApiKeyLocation.Header,
            Description = "Bearer JWT token."
        });

        config.OperationProcessors.Add(
            new AspNetCoreOperationSecurityScopeProcessor("JWT"));

        #endregion add Bearer Authorization

        config.PostProcess = document =>
        {
            document.Info.Version = "V." + PlatformServices.Default.Application.ApplicationVersion + "; " + PlatformServices.Default.Application.RuntimeFramework;
            document.Info.Title = $" {PlatformServices.Default.Application.ApplicationName} API";
            document.Info.Description = $" {PlatformServices.Default.Application.ApplicationName} Backend ";
            document.Info.TermsOfService = "None";
            document.Info.Contact = new NSwag.OpenApiContact
            {
                Name = "IT",
                Email = string.Empty,
                Url = "https://hensel-recycling.com"
            };
            document.Info.License = new NSwag.OpenApiLicense
            {
                Name = "Commercial License",
                Url = "https://hensel-recycling.com"
            };
        };
    });

    builder.Services.ConfigureRepositoryWrapper(); // add repos

    var cnnStr = WebApiConfig.ConnectionString(EN_ConnectionType.SQLServer);

    builder.Services.Configure<WebApiContextOptions>(builder.Configuration.GetSection("WebApiContextOptions"));

    builder.Services.AddDbContext<WebApiContext>(options =>
    {
        const int dbTimeoutInMin = 5;
        options.UseSqlServer(cnnStr,
            opts => opts.CommandTimeout((int)TimeSpan.FromMinutes(dbTimeoutInMin).TotalSeconds));
    });

    // Add repositories in DAL
    builder.Services.AddStaffDBRepositories();
    builder.Services.AddScoped<WebAppUserHelper>();
    builder.Services.AddJwtManagerWithLdap(configuration.GetSection("LdapOptions"));

    // should come last
    builder.Services.AddMvc()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.InvalidModelStateResponseFactory = context =>
        {
            var errors = new HRD.WebApi.Helpers.HttpErrorDetails(context);
            return new BadRequestObjectResult(errors);
        };
    });

    var app = builder.Build();

    ((IApplicationBuilder)app).ApplicationServices.SetupNLogServiceLocator();


    // Configure the HTTP request pipeline
    if (app.Environment.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseHsts();
    }

    app.AddCustomExceptionHandling();
    app.UseHttpsRedirection();
    app.UseRouting();
    app.UseCors("AllowAllOrigins");
    app.UseDefaultFiles();
    app.UseStaticFiles();
    app.UseOpenApi();
    app.UseDALMiddleware();
    app.UseJwtMiddleware();
    app.UseSwaggerUi(cfg => cfg.DocExpansion = "none");

    app.MapControllers();

    app.Run();

}
catch (Exception ex)
{
    logger.LogException(ex, "Stopped program because of exception");
    throw;
}
finally
{
    // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
    NLog.LogManager.Flush();
    NLog.LogManager.Shutdown();
}