using EonaCat.LogStack.Configuration;
using EonaCat.LogStack.Core;
using EonaCat.LogStack.EonaCatLogStackCore;
using EonaCat.LogStack.Flows;
using EonaCat.LogStack.LogClient;
//using EonaCat.MemoryGuard;
using EonaCat.Web.RateLimiter;
using EonaCat.Web.RateLimiter.Endpoints.Extensions;
using EonaCat.LogStack.Flows.WindowsEventLog;
using EonaCat.LogStack.LogClient.Models;
using EonaCat.LogStack.Extensions;

namespace EonaCat.LogStack.Test.Web
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            await using var logger = LogBuilder.CreateDefault("MyApp");

            logger.Information("Application started");
            logger.Warning("Low memory warning");
            logger.Error(new Exception("DIT IS MIJN TEST!"), "Unexpected error occurred");

            // Configure the client
            var centralOptions = new LogCentralOptions
            {
                ServerUrl = "https://localhost:62299",
                ApiKey = "716a964de381979df4303bf93fc091d3",
                ApplicationName = "MyApp",
                ApplicationVersion = "1.0.0",
                Environment = "Production",
                FlushIntervalSeconds = 5
            };

            var logClient = new LogCentralClient(centralOptions);
            logClient.LogAsync(new LogEntry
            {
                Timestamp = DateTime.UtcNow,
                Level = Core.LogLevel.Critical.ToString(),
                Message = "Hello, LogCentral!",
                Properties = new Dictionary<string, object>
                {
                    { "UserId", 123 },
                    { "Operation", "TestLogging" }
                }.ToJson()
            }).ConfigureAwait(false);
            Console.ReadKey();
            _ = Task.Run(async () =>
            {
                var logBuilder = new LogBuilder();
                logBuilder.WithTimestampMode(TimestampMode.Local);
                logBuilder.WriteToConsole();
                logBuilder.WriteToFile("./logs", outputFormat: FileOutputFormat.Csv);
                logBuilder.WriteToFile("./logs", outputFormat: FileOutputFormat.StructuredJson);
                logBuilder.WriteToFile("./logs", outputFormat: FileOutputFormat.Text);
                logBuilder.WriteToFile("./logs", outputFormat: FileOutputFormat.Json);
                logBuilder.WriteToFile("./logs", outputFormat: FileOutputFormat.Xml);
                logBuilder.WriteToTcp("127.0.0.1", 514);
                //logBuilder.WriteToEncryptedFile("./logs");
                //logBuilder.WriteDiagnostics();
                logBuilder.WriteToAudit(
                    directory: "./audit",
                    auditLevel: AuditLevel.WarningAndAbove,   // only Warn+ go to audit trail
                    includeProperties: true);
                //logBuilder.WriteToRollingBuffer();
                var consoleFlow = logBuilder.GetFlow(typeof(ConsoleFlow));
                logBuilder.WriteToThrottled(consoleFlow);
                logBuilder.WriteToStatusFlow(new List<ServiceMonitoring.ServiceStatus> { new ServiceMonitoring.ServiceStatus { Host = "google.com", Port = 443, ServiceType = ServiceMonitoring.ServiceType.HTTPS } }, checkInterval: TimeSpan.FromSeconds(5));
                //logBuilder.WriteToSignalR();
                //logBuilder.WriteToEmailFlow();
                //logBuilder.WriteToWindowsEventLog();
                logBuilder.WriteToHttp("https://localhost:62299/api/logs/eonacat");
                var logger = logBuilder.Build();

                logger.AddModifier((ref LogEventBuilder b) =>
                {
                    b.WithProperty("User", "Bob");
                });

                var i = 0;
                while (true)
                {
                    i++;
                    logger.Log($"test to file {i}");
                    logger.Log($"test to file {i}", Core.LogLevel.Critical);
                    logger.Log($"test to file {i}", Core.LogLevel.Debug);
                    logger.Log($"test to file {i}", Core.LogLevel.Error);
                    logger.Log($"test to file {i}", Core.LogLevel.Trace);
                    await Task.Delay(1).ConfigureAwait(false);
                }
            });
            Console.ReadKey();

            //var _config = new MemoryGuardConfiguration
            //{
            //    MonitoringInterval = TimeSpan.FromSeconds(5),
            //    AnalysisInterval = TimeSpan.FromSeconds(10),
            //    PredictionInterval = TimeSpan.FromSeconds(15),
            //    LeakDetectionThreshold = TimeSpan.FromSeconds(5),
            //    SuspiciousObjectThreshold = TimeSpan.FromSeconds(3),
            //    BackgroundReportingInterval = TimeSpan.FromMinutes(1.5),
            //    CaptureStackTraces = true,
            //    EnableAutoRemediation = true,
            //    AutoSaveReports = true,
            //    MemoryPressureThreshold = 500 * 1024 * 1024, // 500MB
            //    BackgroundAnalysisInterval = TimeSpan.FromMinutes(1),
            //    OptimizationInterval = TimeSpan.FromMinutes(10),
            //    PatternDetectionInterval = TimeSpan.FromMinutes(3)
            //};

            //MemoryGuard.Start(_config);

            _ = Task.Run(async () =>
            {
                var logBuilder = new LogBuilder();
                logBuilder.WriteToConsole();
                var logger = logBuilder.Build();

                logger.AddModifier((ref LogEventBuilder b) =>
                {
                    b.WithProperty("User", "Alice");
                });

                var i = 0;
                while (true)
                {
                    i++;
                    logger.Log($"test to file {i}");
                    logger.Log($"test to file {i}", Core.LogLevel.Critical);
                    logger.Log($"test to file {i}", Core.LogLevel.Debug);
                    logger.Log($"test to file {i}", Core.LogLevel.Error);
                    logger.Log($"test to file {i}", Core.LogLevel.Trace);
                    await Task.Delay(1).ConfigureAwait(false);
                }
            });

            var builder = WebApplication.CreateBuilder(args);
            int onLogCounter = 0;
            var defaultColor = Console.ForegroundColor;
            builder.Services.AddEonaCatLogging();


            //_ = Task.Run(() =>
            //{
            //    var logman = LogManager.Instance;
            //    var i = 0;
            //    while (true)
            //    {
            //        logman.WriteAsync($"Logman test {++i}", ELogType.TRACE).ConfigureAwait(false);
            //        Task.Delay(10).ConfigureAwait(false);
            //    }
            //}).ConfigureAwait(false);

            // Add services to the container.
            //Logger logger = new Logger();
            //logger.UseLocalTime = true;
            //logger.LoggerSettings.Id = "TEST";
            //logger.LoggerSettings.LogInfo();
            //logger.LoggerSettings.LogWarning();
            //logger.LoggerSettings.LogError();
            //logger.LoggerSettings.LogCritical();
            //logger.LoggerSettings.LogDebug();
            //logger.LoggerSettings.LogTrace();
            //logger.LoggerSettings.LogTraffic();
            //logger.LoggerSettings.OnLog += LoggerSettings_OnLog;

            //LoggerSettings.CustomHeaderFormatter = ctx =>
            //{
            //    if (ctx.LogType == ELogType.ERROR)
            //    {
            //        return $"{ctx.Timestamp:HH:mm:ss} [{ctx.LogType}]";
            //    }

            //    return $"{ctx.Timestamp:HH:mm:ss} [{ctx.LogType}]";
            //};

            //logger.LoggerSettings.CustomHeaderFormatter = null; // remove the lambda
            //logger.LoggerSettings.HeaderTokens.AddCustomToken("AppName", x => "[ALL YOUR BASE ARE BELONG TO US!]");
            //logger.LoggerSettings.HeaderFormat = "{AppName} {logtype} {ts}";

            // Create the adapter
            //var adapter = new LogCentralEonaCatAdapter(logger.LoggerSettings, logClient);
            //await LogManager.Instance.WriteAsync("LogCentral adapter initialized", ELogType.INFO).ConfigureAwait(false);

            //// Now all EonaCat.LogStack logs will be sent to LogCentral automatically
            //await logger.LogAsync("This is a test log message sent to LogCentral!", ELogType.INFO).ConfigureAwait(false);

            //var jsonLogger = new  JsonFileLogger("Category", new JsonFileLoggerOptions { FileName = "test.json" });
            //jsonLogger?.SetContext("CorrelationId", "abc-123");
            //jsonLogger?.SetContext("UserId", "john.doe");
            //jsonLogger?.LogInformation("User logged in");

            //Console.WriteLine(DllInfo.EonaCatVersion);
            //Console.Title = VersionHelper.GetInformationalVersion();

            //void LoggerSettings_OnLog(EonaCatLogMessage message)
            //{
            //    Console.ForegroundColor = ConsoleColor.Yellow;
            //    //Console.WriteLine($"LogCounter: {++onLogCounter} {message}");
            //    Console.ForegroundColor = defaultColor;
            //}

            //var options = new FileLoggerOptions();
            //options.MaxRolloverFiles = 5;
            ////options.FileSizeLimit = 1 * 1024 * 1024 / 4;
            //options.UseLocalTime = true;
            //builder.Logging.AddEonaCatFileLogger(fileLoggerOptions: options, filenamePrefix: "web");
            //builder.Logging.AddEonaCatConsoleLogger();

            //TcpLoggerOptions tcpLoggerOptions = new TcpLoggerOptions
            //{
            //    Host = "192.168.1.1",
            //    Port = 12345,
            //};

            //builder.Logging.AddEonaCatTcpLogger((tcpLoggerOptions) =>
            //{
            //    tcpLoggerOptions.Port = 12345;
            //    tcpLoggerOptions.Host = "192.168.1.1";
            //});

            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();

            // 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");
            //}

            //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.Id = "TEST";
            //    loggerSettings.FileLoggerOptions.Category = "ExceptionTests";
            //    loggerSettings.FileLoggerOptions.EnableCategoryRouting = true;
            //    loggerSettings.TypesToLog.Add(ELogType.INFO);

            //    var logger = new LogManager(loggerSettings);
            //    for (var i = 0; i < 10; i++)
            //    {
            //        try
            //        {
            //            throw new Exception($"Normal Exception {i}");
            //        }
            //        catch (Exception exception)
            //        {
            //            logger.WriteAsync(exception).ConfigureAwait(false);
            //            Console.WriteLine($"Normal ExceptionLogged: {i}");
            //        }

            //        Task.Delay(1);
            //    }
            //}

            ////MemoryLeakTester.Start(logger);
            ////_ = Task.Run(RunMemoryReportTask).ConfigureAwait(false);
            //_ = Task.Run(RunWebLoggerTestsAsync).ConfigureAwait(false);
            //_ = Task.Run(RunWebLoggingTests).ConfigureAwait(false);
            //_ = Task.Run(RunLoggingTestsAsync).ConfigureAwait(false);
            //_ = Task.Run(RunLoggingExceptionTests).ConfigureAwait(false);
            //_ = Task.Run(RunWebLoggingExceptionTests).ConfigureAwait(false);

            ////async Task RunMemoryReportTask()
            ////{
            ////    while (true)
            ////    {
            ////        await MemoryGuard.PrintReportAsync().ConfigureAwait(false);
            ////        await Task.Delay(60000).ConfigureAwait(false);
            ////        Console.ReadKey();
            ////    }
            ////}

            //void RunWebLoggingExceptionTests()
            //{
            //    for (var 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);
            //    }
            //}

            //async Task RunWebLoggingTests()
            //{
            //    if (!Directory.Exists(logger.LogFolder))
            //    {
            //        Directory.CreateDirectory(logger.LogFolder);
            //    }

            //    for (var i = 0; i < 9000000; i++)
            //    {
            //        app.Logger.LogInformation($"web-test {i}");
            //        using (var file = new StreamWriter(Path.Combine(logger.LogFolder, "test.log"), true))
            //        {
            //            await file.WriteAsync($"WebLogged: {i}{Environment.NewLine}").ConfigureAwait(false);
            //        }
            //        Console.WriteLine($"WebLogged: {i}");
            //        await Task.Delay(1);
            //    }
            //}

            //async Task RunLoggingTestsAsync()
            //{
            //    var loggerSettings = new LoggerSettings();
            //    loggerSettings.Id = "TEST";
            //    loggerSettings.UseLocalTime = true;
            //    loggerSettings.FileLoggerOptions.UseLocalTime = true;
            //    loggerSettings.TypesToLog.Add(ELogType.INFO);
            //    loggerSettings.TypesToLog.Add(ELogType.WARNING);
            //    loggerSettings.TypesToLog.Add(ELogType.ERROR);
            //    loggerSettings.TypesToLog.Add(ELogType.TRAFFIC);
            //    loggerSettings.TypesToLog.Add(ELogType.DEBUG);
            //    loggerSettings.LogDebug();
            //    loggerSettings.LogInfo();
            //    loggerSettings.LogWarning();
            //    loggerSettings.LogError();
            //    loggerSettings.LogCritical();
            //    loggerSettings.LogTrace();
            //    loggerSettings.LogTraffic();
            //    loggerSettings.FileLoggerOptions.FileSizeLimit = 1024 * 1024 * 1;
            //    loggerSettings.FileLoggerOptions.FileNamePrefix = "AllTypes";
            //    loggerSettings.FileLoggerOptions.MaxRolloverFiles = 5;
            //    var logger = new LogManager(loggerSettings);

            //    for (var i = 0; i < 9000000; i++)
            //    {
            //        await logger.WriteAsync($"test to file {i}").ConfigureAwait(false);
            //        await logger.WriteAsync($"test to file {i}", ELogType.CRITICAL).ConfigureAwait(false);
            //        await logger.WriteAsync($"test to file {i}", ELogType.DEBUG).ConfigureAwait(false);
            //        await logger.WriteAsync($"test to file {i}", ELogType.ERROR).ConfigureAwait(false);
            //        await logger.WriteAsync($"test to file {i}", ELogType.TRACE).ConfigureAwait(false);
            //        await logger.WriteAsync($"test to file {i}", ELogType.TRAFFIC).ConfigureAwait(false);
            //        await logger.WriteAsync($"test to file {i}", ELogType.WARNING).ConfigureAwait(false);
            //        await logger.WriteAsync($"test to file {i}", ELogType.NONE).ConfigureAwait(false);
            //        Console.WriteLine($"Logged: {i}");
            //        await Task.Delay(1).ConfigureAwait(false);
            //    }
            //}

            //async Task RunWebLoggerTestsAsync()
            //{
            //    var i = 0;
            //    while (true)
            //    {
            //        i++;
            //        await Task.Run(async () =>
            //        {
            //            await logger.($"test via logger {i}").ConfigureAwait(false);
            //            await logger.LogAsync($"test via logger {i}", ELogType.CRITICAL).ConfigureAwait(false);
            //            await logger.LogAsync($"test via logger {i}", ELogType.DEBUG).ConfigureAwait(false);
            //            await logger.LogAsync($"test via logger {i}", ELogType.ERROR).ConfigureAwait(false);
            //            await logger.LogAsync($"test via logger {i}", ELogType.TRAFFIC).ConfigureAwait(false);
            //            await logger.LogAsync($"test via logger {i}", ELogType.WARNING).ConfigureAwait(false);
            //            await logger.LogAsync($"test via logger {i}", ELogType.NONE).ConfigureAwait(false);
            //        }).ConfigureAwait(false);
            //        await Task.Delay(1).ConfigureAwait(false);
            //    }
            //}
            app.Run();
        }

        //private static void Instance_LeakDetected(object? sender, EonaCat.MemoryGuard.EventArguments.MemoryLeakDetectedEventArgs e)
        //{
        //    // Leak detected            
        //}
    }

    //static class MemoryLeakTester
    //{
    //    // Rooted forever → GC can never collect
    //    private static readonly List<byte[]> _managedLeak = new();
    //    private static readonly List<GCHandle> _handles = new();

    //    public static void Start(Logger logger)
    //    {
    //        // Leak triggered via logging (very realistic)
    //        logger.LoggerSettings.OnLog += OnLogLeak;

    //        // Optional background unmanaged leak
    //        StartUnmanagedLeak();

    //        Console.ForegroundColor = ConsoleColor.Red;
    //        Console.WriteLine("⚠ MEMORY LEAK TEST ENABLED");
    //        Console.ResetColor();
    //    }

    //    private static void OnLogLeak(EonaCatLogMessage message)
    //    {
    //        // 5 MB per log
    //        var data = new byte[5_000_000];
    //        _managedLeak.Add(data);

    //        // GCHandle leak (advanced / nasty)
    //        _handles.Add(GCHandle.Alloc(data, GCHandleType.Normal));
    //    }

    //    private static void StartUnmanagedLeak()
    //    {
    //        _ = Task.Run(async () =>
    //        {
    //            while (true)
    //            {
    //                Marshal.AllocHGlobal(10_000_000); // 10 MB unmanaged
    //                await Task.Delay(500).ConfigureAwait(false);
    //            }
    //        });
    //    }
    //}

}