using AipGateway.API.Application.Pipeline.Middlewares;
using AipGateway.API.Domain;
using AipGateway.API.Services;
using AipGateway.API.Job;
using Microsoft.OpenApi.Models;
using Microsoft.AspNetCore.HttpOverrides;
using System.Net;
using AipGateway.API.Configurations;
using AutoMapper;
using AipGateway.AIP;
using AipGateway.API.Services.impl;
using Serilog;
using Serilog.Events;

internal class Program
{
    private static void Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration().WriteTo.Console(LogEventLevel.Information)
            .MinimumLevel.Debug()
            .CreateBootstrapLogger();

       Log.Information("Start Azure Information RESTFull API Service... [{0}]", Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"));
        try
        {
            var builder = WebApplication.CreateBuilder(args);
            builder.Host.UseSerilog((context, services, configuration) => configuration
            .ReadFrom.Configuration(context.Configuration)
            .ReadFrom.Services(services)
            .Enrich.FromLogContext(), true);

            //builder.Host.UseSerilog((context, loggerConfiguration) => loggerConfiguration.ReadFrom.Configuration(context.Configuration));

            ConfigureSettings(builder.Host, builder.Environment);               // 환경설정 파일 설정
            AddApplicationSettings(builder.Services, builder.Configuration);    // 어플리케이션 환경파일 DI(dependency injection)-의존성 주입

            builder.Services.AddControllers();

            builder.Services.AddSwaggerGen(c => {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "Azure Information Protection RESTFull API Service Gateway", Version = "v1" });
            });

            builder.Services.Configure<ForwardedHeadersOptions>(options =>
            {
                options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
                options.KnownNetworks.Clear();
                options.KnownProxies.Clear();
            });

            int Port = 9871;
            if (!int.TryParse(builder.Configuration["Port"], out Port))
            {
                Port = 9871;
            }
            //https://learn.microsoft.com/ko-kr/aspnet/core/fundamentals/servers/kestrel/options?view=aspnetcore-8.0
            //builder.WebHost.ConfigureKestrel((context, serverOptions) =>
            //{
            //    serverOptions.ListenAnyIP(Port);
            //});
            builder.WebHost.ConfigureKestrel((context, serverOptions) =>
            {
                //serverOptions.Limits.MaxRequestBodySize = 100_000_000;      // [RequestSizeLimit(100_000_000)] --> Controller 위에 선언,  IHttpMaxRequestBodySizeFeature
                //serverOptions.Limits.MaxConcurrentConnections = 100;
                //serverOptions.Limits.MaxConcurrentUpgradedConnections = 100;
                serverOptions.Listen(IPAddress.Any, Port, listenOptions =>
                {
                    //listenOptions.UseHttps("testCert.pfx", "testPassword");
                    //listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
                });
            });

            builder.Services.InjectDependencies(builder.Configuration);

            builder.Services.AddScoped<AipFileApiService>();
            builder.Services.AddSingleton<AipFileJobService>();
            builder.Services.AddSingleton<ScheduleService>();
            builder.Services.AddScoped<IApiAipService, ApiAipService>();
            builder.Services.AddScoped<IApiDbService, ApiDbService>();
            builder.Services.AddScoped<IApiDummyService, ApiDummyService>();
            builder.Services.AddScoped<IApiFileService, ApiFileService>();
            builder.Services.AddScoped<IApiStreamService, ApiStreamService>();

            var mappingConfig = new MapperConfiguration(mc =>
            {
                mc.AddProfile(new MappingProfile());
            });
            IMapper mapper = mappingConfig.CreateMapper();
            builder.Services.AddSingleton(mapper);

            builder.Services.AddHealthChecks();

            builder.Services.AddCors(p => p.AddPolicy("corsapp", builder =>
            {
                //builder.WithOrigins("*", "http://localhost:3011", "https://localhost:3011", "https://localhost:7261").AllowAnyMethod().AllowAnyHeader();
            }));


            ContainerService.provider = builder.Services.BuildServiceProvider();

            AipFileApiService? aipFileApiService = ContainerService.provider.GetService<AipFileApiService>();
            if (aipFileApiService == null)
            {
                Log.Error("Not Found AipFileApiService...");
                return;
            }
            aipFileApiService.LoadConfig();
            ContainerService.aipConfig = aipFileApiService.GetAipSettings();
            string supportedFileExt = ContainerService.aipConfig.SupportedFileExt;
            string protectedFileExt = ContainerService.aipConfig.ProtectedFileExt;
            string[] fileExts = supportedFileExt.Split(';');
            foreach (string ext in fileExts)
            {
                if (ext.Trim() == "") continue;
                ContainerService.supportedFileExtMap[ext.Trim()] = ext.Trim();
                ContainerService.protectedFileExtMap[ext.Trim()] = ext.Trim();
                ContainerService.supportedDelFileExtMap[ext.Trim()] = ext.Trim();
                ContainerService.protectedDelFileExtMap[ext.Trim()] = ext.Trim();
            }
            string[] protectedExts = protectedFileExt.Split(';');
            foreach (string ext in protectedExts)
            {
                if (ext.Trim() == "") continue;
                string[] extFile = ext.Split('-');
                if (extFile.Length == 2)
                {
                    ContainerService.protectedFileExtMap[extFile[0].Trim()] = extFile[1].Trim();
                    if (ContainerService.protectedDelFileExtMap.Contains(extFile[0].Trim()))
                    {
                        ContainerService.protectedDelFileExtMap.Remove(extFile[0].Trim());
                    }
                    ContainerService.protectedDelFileExtMap[extFile[1].Trim()] = extFile[0].Trim();
                }
            }

            ContainerService.aipFileManager = new AipFileManager(aipFileApiService.GetAipSettings().GetConfig());
            if (!AipFileInitialize(ContainerService.aipFileManager))
            {
                Log.Error("AipFileInitialize: Failed. {0}, {1}", ContainerService.aipFileManager.LastErrNo, ContainerService.aipFileManager.LastErrMsg);
                return;
            }

            aipFileApiService.DownloadAipFileInformations();
            aipFileApiService.LoadLinkedApiKeys();
            aipFileApiService.LoadLinkedDecryptKeys();

            AipFileJobService? aipFileJobService = ContainerService.provider.GetService<AipFileJobService>();
            if (aipFileJobService != null)
            {
                aipFileJobService.Start();
            }

            var app = builder.Build();

            //app.UseExceptionHandler("/Error");

            app.UseSerilogRequestLogging();

            //HTTP Strict Transport Security : Method used by server to declare that they should only be accessed using HTTPS (secure connection) only
            app.UseHsts();
            app.UseHttpsRedirection();

            app.UseStaticFiles();

            app.UseRouting();
            app.UseCors("corsapp");

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

            app.UseMiddlewares();
            //app.UseMiddleware<ApiValidationMiddleware>();
            //app.UseMiddleware<ApiGuidGeneratorMiddleware>();

            app.UseHealthChecks("/health");

            //if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

            app.MapControllers();

            app.Run();
            //
            // 프로그램 종료 후 처리 수행
            //
        }
        catch (Exception ex) when (ex.GetType().Name is not "StopTheHostException"
            && ex.GetType().Name is not "HostAbortedException")
        {
            Log.Fatal(ex, "Program Unhandled exception");
        }
        finally
        {
            Log.Information("Shut down complete");
            Log.CloseAndFlush();
        }

    }

    private static bool AipFileInitialize(AipFileManager aipFileManager)
    {
        if (!aipFileManager.Initialize())
        {
            Log.Error("AipFileInitialize, aipFileManager.Initialize Failed, {0}, {1}", aipFileManager.LastErrNo, aipFileManager.LastErrMsg);
            return false;
        }
        if (!aipFileManager.CreateProfile())
        {
            Log.Error("AipFileInitialize, aipFileManager.CreateProfile Failed, {0}, {1}", aipFileManager.LastErrNo, aipFileManager.LastErrMsg);
            return false;
        }
        if (!aipFileManager.CreateEngine())
        {
            Log.Error("AipFileInitialize, aipFileManager.CreateEngine Failed, {0}, {1}", aipFileManager.LastErrNo, aipFileManager.LastErrMsg);
            return false;
        }
        return true;
    }

    private static void ConfigureSettings(IHostBuilder hostBuilder, IHostEnvironment environment)
    {
        hostBuilder.ConfigureAppConfiguration(config =>
        {
            config
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile(
                    path: "appsettings.json",
                    optional: false,
                    reloadOnChange: true)
                .AddJsonFile(
                    path: $"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json",
                    optional: true,
                    reloadOnChange: true)
                .AddEnvironmentVariables();
        });
    }

    private static void AddApplicationSettings(IServiceCollection services, IConfiguration configuration)
    {
        services.Configure<AipSettings>(configuration.GetSection(nameof(AipSettings)));
        
        //services.Configure<EmailSenderSettings>(configuration.GetSection(nameof(EmailSenderSettings)));
        //services.Configure<RequestLocalizationSettings>(configuration.GetSection(nameof(RequestLocalizationSettings)));
        //if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development")
        //{
        //    services.Configure<SwaggerSettings>(configuration.GetSection(nameof(SwaggerSettings)));
        //}
    }

}
