using EonaCat.Logger;
using EonaCat.Logger.EonaCatCoreLogger;
using EonaCat.Logger.EonaCatCoreLogger.Extensions;
using EonaCat.Logger.Managers;
using EonaCat.Logger.Test.Web;
using EonaCat.Web.RateLimiter;
using EonaCat.Web.RateLimiter.Endpoints.Extensions;
using EonaCat.Web.Tracer.Extensions;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
FileLoggerOptions options = new FileLoggerOptions();
options.MaxRolloverFiles = 5;
options.FileSizeLimit = 1 * 1024 * 1024 / 4;
options.UseLocalTime = true;
builder.Logging.AddEonaCatFileLogger(fileLoggerOptions: options, filenamePrefix:"web");

builder.Services.AddRazorPages();

//var rateLimitOptions = new RateLimitOptions
//{
//    Capacity = 10,
//    Duration = TimeSpan.FromMinutes(1)
//};

//builder.Services.AddRateLimiting(rateLimitOptions);
var rateOptions = new RateLimiterOptions();
rateOptions.OutputLimitMessageAsHtml = false;
rateOptions.OutputLimitMessageAsXml = false;
rateOptions.OutputLimitMessageAsJson = true;

rateOptions.AddDefaultConfiguration(config =>
    config.AddIpResolver().AddRule(3, TimeSpan.FromSeconds(10))
);

RateLimiterMiddleware.OnLimitResponseCreated += RateLimiterMiddlewareOnLimitResponseCreatedAsync;
async void RateLimiterMiddlewareOnLimitResponseCreatedAsync(object? sender, HttpContext httpContext)
{
    await httpContext.Response.WriteAsync(" THIS IS MY CUSTOM RATE LIMIT MESSAGE").ConfigureAwait(false);
}

//builder.Services.UseWebRateLimiter(rateOptions);
builder.Services.UseWebRateLimiter(rateOptions);
builder.Services.UseWebRateLimiter(rateOptions =>
{
    // Configures the default rateLimitConfiguration
    rateOptions.AddDefaultConfiguration(rateLimitConfiguration =>
    {
        // throttling is based on request ip
        rateLimitConfiguration.AddIpResolver()
            // add general rules for all ips
            .AddRule(3, TimeSpan.FromSeconds(10)) // 3 requests could be called every 10 seconds
            .AddRule(30, TimeSpan.FromMinutes(1)) // 30 requests could be called every 1 minute
            .AddRule(500, TimeSpan.FromHours(1)); // 500 requests could be called every 1 hour
    });
});
builder.Services.AddMemoryCache();


var app = builder.Build();

Logger.UseLocalTime = true;
Logger.MaxLogType = ELogType.TRACE;
Logger.Configure();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/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();
}

//EonaCat.Web.RateLimiter.RateLimiterOptions options = new EonaCat.Web.RateLimiter.RateLimiterOptions();
//options.LimitMessage = "FUCKING NOOB!";
//options.WriteLimitMessageToResponse = true;
//options.WriteLimitMessageStatusCodeToResponse = true;
//app.UseRateLimiter(options);
//RateLimiterMiddleware.OnLimitResponseCreated += RateLimiterMiddleware_OnLimitResponseCreatedAsync;
//async void RateLimiterMiddleware_OnLimitResponseCreatedAsync(object? sender, HttpContext httpContext)
//{
//    await httpContext.Response.WriteAsync("THIS IS MY CUSTOM RATE LIMIT MESSAGE");
//}
WebTracer.OnLog += WebTracer_OnLog;
void WebTracer_OnLog(object? sender, string e)
{
    Console.WriteLine(e);
}
//app.UseWebTracer();

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

app.UseRouting();
app.UseAuthorization();
app.UseWebRateLimiter();

app.MapRazorPages().RateLimit();

void RunLoggingExceptionTests()
{
    var loggerSettings = new LoggerSettings();
    loggerSettings.FileLoggerOptions.UseLocalTime = true;
    loggerSettings.UseLocalTime = true;
    loggerSettings.MaxLogType = ELogType.TRACE;
    var logger = new LogManager(loggerSettings);

    for (int i = 0; i < 10; i++)
    {
        try
        {
            throw new Exception($"Normal Exception {i}");
        }
        catch (Exception exception)
        {
            logger.Write(exception);
            Console.WriteLine($"Normal ExceptionLogged: {i}");
        }
        Task.Delay(1);
    }
}

Task.Run(RunWebLoggerTests);
Task.Run(RunWebLoggingTests);
Task.Run(RunLoggingTests);
Task.Run(RunLoggingExceptionTests);
Task.Run(RunWebLoggingExceptionTests);

void RunWebLoggingExceptionTests()
{
    for (int i = 0; i < 10; i++)
    {
        try
        {
            throw new Exception($"WebException {i}");
        }
        catch (Exception exception)
        {
            app.Logger.LogCritical(exception, "CRITICAL");
            app.Logger.LogDebug(exception, "DEBUG");
            app.Logger.LogError(exception, "ERROR");
            app.Logger.LogTrace(exception, "TRACE");
            app.Logger.LogWarning(exception, "WARNING");
            app.Logger.LogInformation(exception, "INFORMATION");
            Console.WriteLine($"WebExceptionLogged: {i}");
        }
        Task.Delay(1);
    }
}

void RunWebLoggingTests()
{
    if (!Directory.Exists(Logger.LogFolder))
    {
        Directory.CreateDirectory(Logger.LogFolder);
    }

    for (int i = 0; i < 9000000; i++)
    {
        app.Logger.LogInformation($"web-test {i}");
        File.AppendAllText(Path.Combine(Logger.LogFolder, "test.log"), $"WebLogged: {i}{Environment.NewLine}");
        Console.WriteLine($"WebLogged: {i}");
        Task.Delay(1);
    }
}

void RunLoggingTests()
{
    var loggerSettings = new LoggerSettings();
    loggerSettings.UseLocalTime = true;
    loggerSettings.FileLoggerOptions.UseLocalTime = true;
    loggerSettings.MaxLogType = ELogType.TRACE;
    loggerSettings.FileLoggerOptions.FileSizeLimit = 1024 * 1024 * 1;
    loggerSettings.FileLoggerOptions.FileNamePrefix = "AllTypes";
    loggerSettings.FileLoggerOptions.MaxRolloverFiles = 5;
    loggerSettings.MaxLogType = ELogType.TRACE;
    var logger = new LogManager(loggerSettings);

    for (int i = 0; i < 9000000; i++)
    {
        logger.Write($"test to file {i} INFO", ELogType.INFO);
        logger.Write($"test to file {i} CRITICAL", ELogType.CRITICAL);
        logger.Write($"test to file {i} DEBUG", ELogType.DEBUG);
        logger.Write($"test to file {i} ERROR", ELogType.ERROR);
        logger.Write($"test to file {i} TRACE", ELogType.TRACE);
        logger.Write($"test to file {i} TRAFFIC", ELogType.TRAFFIC);
        logger.Write($"test to file {i} WARNING", ELogType.WARNING);
        logger.Write($"test to file {i} NONE", ELogType.NONE);
        Console.WriteLine($"Logged: {i}");
        Task.Delay(1);
    }
}

void RunWebLoggerTests()
{
    for (int i = 0; i < 9000000; i++)
    {
        Logger.Log($"test via logger {i} INFO", ELogType.INFO);
        Logger.Log($"test via logger {i} CRITICAL", ELogType.CRITICAL);
        Logger.Log($"test via logger {i} DEBUG", ELogType.DEBUG);
        Logger.Log($"test via logger {i} ERROR", ELogType.ERROR);
        Logger.Log($"test via logger {i} TRACE", ELogType.TRACE);
        Logger.Log($"test via logger {i} TRAFFIC", ELogType.TRAFFIC);
        Logger.Log($"test via logger {i} WARNING", ELogType.WARNING);
        Logger.Log($"test via logger {i} NONE", ELogType.NONE);
        Console.WriteLine($"Logger: {i}");
        Task.Delay(1);
    }
}

app.Run();
