using System;
using System.IO;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Text;
using AdvChkSys;
using AdvChkSys.Chunk;
using AdvChkSys.Manager;
using AdvChkSys.Constraints;
using AdvChkSys.Diagnostics;

namespace ChunkMark
{
    public static class Program
    {
        private static readonly ConsoleColor _headerColor = ConsoleColor.Cyan;
        private static readonly ConsoleColor _resultColor = ConsoleColor.Green;
        private static readonly ConsoleColor _memoryColor = ConsoleColor.Yellow;
        private static readonly ConsoleColor _errorColor = ConsoleColor.Red;
        private static readonly ConsoleColor _infoColor = ConsoleColor.Gray;
        
        private static List<BenchmarkResult> _results = new List<BenchmarkResult>();
        private static bool _verboseMode = false;

        public static void Main(string[] args)
        {
            int cpuCount = Environment.ProcessorCount;
            int num2DChunks = 10000;
            int chunk2DSize = 32;
            int num3DChunks = 500;
            int chunk3DWidth = 16, chunk3DHeight = 16, chunk3DDepth = 16;
            int maxLoaded = 100000;
            bool run2D = true, run3D = true;
            bool runMemoryTest = false;
            bool runStressTest = false;

            // Parse args
            foreach (var arg in args)
            {
                if (arg.StartsWith("--cpus=")) cpuCount = int.Parse(arg.Substring(7));
                if (arg.StartsWith("--2d-chunks=")) num2DChunks = int.Parse(arg.Substring(12));
                if (arg.StartsWith("--2d-size=")) chunk2DSize = int.Parse(arg.Substring(10));
                if (arg.StartsWith("--3d-chunks=")) num3DChunks = int.Parse(arg.Substring(12));
                if (arg.StartsWith("--3d-width=")) chunk3DWidth = int.Parse(arg.Substring(11));
                if (arg.StartsWith("--3d-height=")) chunk3DHeight = int.Parse(arg.Substring(12));
                if (arg.StartsWith("--3d-depth=")) chunk3DDepth = int.Parse(arg.Substring(11));
                if (arg.StartsWith("--3d-size="))
                {
                    int val = int.Parse(arg.Substring(10));
                    chunk3DWidth = chunk3DHeight = chunk3DDepth = val;
                }
                if (arg.StartsWith("--max-loaded=")) maxLoaded = int.Parse(arg.Substring(13));
                if (arg == "--2d-only") { run3D = false; }
                if (arg == "--3d-only") { run2D = false; }
                if (arg == "--memory-test") { runMemoryTest = true; }
                if (arg == "--stress-test") { runStressTest = true; }
                if (arg == "--verbose") { _verboseMode = true; }
            }

            PrintHeader();

            if (run2D)
                Benchmark2D(cpuCount, num2DChunks, chunk2DSize, maxLoaded);

            if (run3D)
            {
                while (true)
                {
                    if (!CanAllocateChunks(num3DChunks, chunk3DWidth, chunk3DHeight, chunk3DDepth, 0.82))
                    {
                        long bytesPerChunk = (long)chunk3DWidth * chunk3DHeight * chunk3DDepth;
                        long totalBytes = bytesPerChunk * num3DChunks;
                        long available = GetAvailableMemoryBytes();
                        long safeLimit = (long)(available * 0.82);

                        Console.ForegroundColor = _errorColor;
                        Console.WriteLine($"ERROR: Requested 3D chunks would use {totalBytes / (1024 * 1024):N0} MB, but only {safeLimit / (1024 * 1024):N0} MB is safely available.");
                        Console.WriteLine("Please input new values for 3D chunks and size within your system's memory capacity.");
                        Console.ResetColor();

                        Console.ForegroundColor = _infoColor;  // Using _infoColor here
                        Console.Write("Enter number of 3D chunks (or blank to exit): ");
                        Console.ResetColor();
                        
                        var chunksInput = Console.ReadLine();
                        if (string.IsNullOrWhiteSpace(chunksInput))
                        {
                            Console.WriteLine("Exiting benchmark.");
                            break;
                        }
                        if (!int.TryParse(chunksInput, out num3DChunks) || num3DChunks <= 0)
                        {
                            Console.WriteLine("Invalid input. Exiting.");
                            break;
                        }

                        Console.ForegroundColor = _infoColor;  // Using _infoColor here
                        Console.Write("Enter 3D chunk width: ");
                        Console.ResetColor();
                        
                        var widthInput = Console.ReadLine();
                        if (string.IsNullOrWhiteSpace(widthInput) || !int.TryParse(widthInput, out chunk3DWidth) || chunk3DWidth <= 0)
                        {
                            Console.WriteLine("Invalid input. Exiting.");
                            break;
                        }

                        Console.ForegroundColor = _infoColor;  // Using _infoColor here
                        Console.Write("Enter 3D chunk height: ");
                        Console.ResetColor();
                        
                        var heightInput = Console.ReadLine();
                        if (string.IsNullOrWhiteSpace(heightInput) || !int.TryParse(heightInput, out chunk3DHeight) || chunk3DHeight <= 0)
                        {
                            Console.WriteLine("Invalid input. Exiting.");
                            break;
                        }

                        Console.ForegroundColor = _infoColor;  // Using _infoColor here
                        Console.Write("Enter 3D chunk depth: ");
                        Console.ResetColor();
                        
                        var depthInput = Console.ReadLine();
                        if (string.IsNullOrWhiteSpace(depthInput) || !int.TryParse(depthInput, out chunk3DDepth) || chunk3DDepth <= 0)
                        {
                            Console.WriteLine("Invalid input. Exiting.");
                            break;
                        }
                        Console.WriteLine();
                        // Loop will re-check with new values
                    }
                    else
                    {
                        try
                        {
                            Benchmark3D(cpuCount, num3DChunks, chunk3DWidth, chunk3DHeight, chunk3DDepth, maxLoaded);
                        }
                        catch (OutOfMemoryException)
                        {
                            Console.ForegroundColor = _errorColor;
                            Console.WriteLine("ERROR: Out of memory during 3D chunk allocation. Reduce chunk size or count.");
                            Console.ResetColor();
                        }
                        break;
                    }
                }
            }

            if (runMemoryTest)
            {
                RunMemoryTest(cpuCount, chunk2DSize, chunk3DWidth, chunk3DHeight, chunk3DDepth);
            }

            if (runStressTest)
            {
                RunStressTest(cpuCount, chunk2DSize, chunk3DWidth, chunk3DHeight, chunk3DDepth);
            }

            PrintSummary();
            PrintDetailedChunkInfo();
            // Save benchmark results to log file
            SaveBenchmarkLog();

            Console.ForegroundColor = _infoColor;  // Using _infoColor here
            Console.WriteLine("\nDone. Press any key to exit.");
            Console.ResetColor();
            Console.ReadKey();
        }

        private static void PrintHeader()
        {
            Console.ForegroundColor = _headerColor;
            Console.WriteLine("╔═══════════════════════════════════════════════════════════════╗");
            Console.WriteLine("║                 ChunkMark: AdvChkSys Benchmark                ║");
            Console.WriteLine("╚═══════════════════════════════════════════════════════════════╝");
            Console.ResetColor();
            
            Console.WriteLine($"Library version: {AdvChkSys.AdvChkSys.Version}");
            Console.WriteLine($"CPU threads: {Environment.ProcessorCount}");
            Console.WriteLine($"System memory: {FormatByteSize(AdvChkSys.AdvChkSys.GetMemoryUsage().TotalSystemMemoryBytes)}");
            Console.WriteLine($"Available memory: {FormatByteSize(AdvChkSys.AdvChkSys.GetMemoryUsage().AvailableSystemMemoryBytes)}");
            Console.WriteLine();
        }

        private static void PrintSummary()
        {
            Console.WriteLine();
            Console.ForegroundColor = _headerColor;
            Console.WriteLine("╔═══════════════════════════════════════════════════════════════╗");
            Console.WriteLine("║                      Benchmark Summary                         ║");
            Console.WriteLine("╚═══════════════════════════════════════════════════════════════╝");
            Console.ResetColor();

            if (_results.Count == 0)
            {
                Console.WriteLine("No benchmark results to display.");
                return;
            }

            // Standard benchmark results table
            var table = new StringBuilder();
            table.AppendLine("┌────────────────┬─────────────┬────────────┬────────────┬────────────┬────────────┐");
            table.AppendLine("│ Test           │ Chunks      │ Create     │ Access     │ Unload     │ Memory     │");
            table.AppendLine("├────────────────┼─────────────┼────────────┼────────────┼────────────┼────────────┤");

            foreach (var result in _results)
            {
                string testName = result.TestName.PadRight(14).Substring(0, 14);
                string chunkInfo = result.ChunkCount.ToString("N0").PadRight(11).Substring(0, 11);
                string createTime = $"{result.CreateTime:F3} s".PadRight(10).Substring(0, 10);
                string accessTime = $"{result.AccessTime:F3} s".PadRight(10).Substring(0, 10);
                string unloadTime = $"{result.UnloadTime:F3} s".PadRight(10).Substring(0, 10);
                string memoryUsed = FormatByteSize(result.MemoryUsed).PadRight(10).Substring(0, 10);

                table.AppendLine($"│ {testName} │ {chunkInfo} │ {createTime} │ {accessTime} │ {unloadTime} │ {memoryUsed} │");
            }

            table.AppendLine("└────────────────┴─────────────┴────────────┴────────────┴────────────┴────────────┘");
            Console.WriteLine(table.ToString());

            // Calculate and display performance metrics
            if (_results.Count > 0)
            {
                Console.ForegroundColor = _resultColor;
                Console.WriteLine("Performance Metrics:");
                Console.ResetColor();

                var create2DRate = _results.Where(r => r.TestName.Contains("2D")).Select(r => r.ChunkCount / r.CreateTime).FirstOrDefault();
                var create3DRate = _results.Where(r => r.TestName.Contains("3D")).Select(r => r.ChunkCount / r.CreateTime).FirstOrDefault();
                var access2DRate = _results.Where(r => r.TestName.Contains("2D")).Select(r => r.ChunkCount / r.AccessTime).FirstOrDefault();
                var access3DRate = _results.Where(r => r.TestName.Contains("3D")).Select(r => r.ChunkCount / r.AccessTime).FirstOrDefault();

                if (create2DRate > 0)
                    Console.WriteLine($"2D Chunk Creation Rate: {create2DRate:N0} chunks/second");
                if (create3DRate > 0)
                    Console.WriteLine($"3D Chunk Creation Rate: {create3DRate:N0} chunks/second");
                if (access2DRate > 0)
                    Console.WriteLine($"2D Chunk Access Rate: {access2DRate:N0} chunks/second");
                if (access3DRate > 0)
                    Console.WriteLine($"3D Chunk Access Rate: {access3DRate:N0} chunks/second");
            }

            // Memory usage summary
            Console.ForegroundColor = _memoryColor;
            Console.WriteLine("\nMemory Usage Summary:");
            Console.ResetColor();

            var memoryReport = AdvChkSys.AdvChkSys.GetMemoryUsage();
            Console.WriteLine($"Current Memory Usage: {FormatByteSize(memoryReport.EstimatedChunkMemoryBytes)}");
            Console.WriteLine($"Active Chunks: {memoryReport.ActiveChunkCount:N0}");
            Console.WriteLine($"Available System Memory: {FormatByteSize(memoryReport.AvailableSystemMemoryBytes)}");
            Console.WriteLine($"Memory Usage: {memoryReport.MemoryUsagePercentage:F2}% of total system memory");

            // System information
            Console.ForegroundColor = _headerColor;
            Console.WriteLine("\nSystem Information:");
            Console.ResetColor();
            Console.WriteLine($"CPU Threads: {Environment.ProcessorCount}");
            Console.WriteLine($"Total System Memory: {FormatByteSize(memoryReport.TotalSystemMemoryBytes)}");
            Console.WriteLine($"AdvChkSys Version: {AdvChkSys.AdvChkSys.Version}");
            
            // Memory efficiency metrics
            if (_results.Count > 0)
            {
                var result2D = _results.FirstOrDefault(r => r.TestName.Contains("2D"));
                var result3D = _results.FirstOrDefault(r => r.TestName.Contains("3D"));

                if (result2D != null && result2D.ChunkCount > 0)
                {
                    ulong bytesPerChunk2D = result2D.MemoryUsed / (ulong)result2D.ChunkCount;
                    Console.WriteLine($"2D Memory Efficiency: {FormatByteSize(bytesPerChunk2D)}/chunk");
                }

                if (result3D != null && result3D.ChunkCount > 0)
                {
                    ulong bytesPerChunk3D = result3D.MemoryUsed / (ulong)result3D.ChunkCount;
                    Console.WriteLine($"3D Memory Efficiency: {FormatByteSize(bytesPerChunk3D)}/chunk");
                }
            }

            // If stress test was run, show its results
            var stressResult = _results.FirstOrDefault(r => r.TestName.Contains("Stress"));
            if (stressResult != null)
            {
                Console.ForegroundColor = _headerColor;
                Console.WriteLine("\nStress Test Results:");
                Console.ResetColor();
                Console.WriteLine($"Chunks Processed: {stressResult.ChunkCount:N0}");
                Console.WriteLine($"Processing Time: {stressResult.CreateTime:F2} seconds");
                Console.WriteLine($"Processing Rate: {stressResult.ChunkCount / stressResult.CreateTime:N0} chunks/second");
                Console.WriteLine($"Peak Memory Usage: {FormatByteSize(stressResult.MemoryUsed)}");
            }


        }

        private static void Benchmark2D(int cpuCount, int numChunks, int chunkSize, int maxLoaded)
        {
            Console.ForegroundColor = _headerColor;
            Console.WriteLine($"[2D] {numChunks:N0} chunks of size {chunkSize}x{chunkSize}, maxLoaded={maxLoaded:N0}");
            Console.ResetColor();

            var constraints = new WorldConstraints
            {
                MinChunkX = 0,
                MaxChunkX = 9999,
                MinChunkY = 0,
                MaxChunkY = 9999,
                MaxLoadedChunks = maxLoaded
            };
            var manager = new ChunkManager2D<byte>(constraints, maxLoaded);

            // Memory before test
            var memoryBefore = AdvChkSys.AdvChkSys.GetMemoryUsage();
            if (_verboseMode)
            {
                Console.ForegroundColor = _memoryColor;
                Console.WriteLine($"  Memory before: {FormatByteSize(memoryBefore.EstimatedChunkMemoryBytes)}");
                Console.ResetColor();
            }

            // Create and fill
            var sw = Stopwatch.StartNew();
            Parallel.For(0, numChunks, new ParallelOptions { MaxDegreeOfParallelism = cpuCount }, i =>
            {
                int x = i % 1000, y = i / 1000;
                var chunk = manager.LoadOrCreateChunk(x, y, chunkSize, chunkSize);
                for (int cx = 0; cx < chunkSize; cx++)
                    for (int cy = 0; cy < chunkSize; cy++)
                        chunk[cx, cy] = (byte)((cx + cy) % 256);
            });
            sw.Stop();
            double createTime = sw.Elapsed.TotalSeconds;
            Console.WriteLine($"  Created and filled {numChunks:N0} chunks in {createTime:F3} s");

            // Memory after creation
            var memoryAfterCreate = AdvChkSys.AdvChkSys.GetMemoryUsage();
            if (_verboseMode)
            {
                Console.ForegroundColor = _memoryColor;
                Console.WriteLine($"  Memory after creation: {FormatByteSize(memoryAfterCreate.EstimatedChunkMemoryBytes)} " +
                                 $"(+{FormatByteSize(memoryAfterCreate.EstimatedChunkMemoryBytes - memoryBefore.EstimatedChunkMemoryBytes)})");
                Console.ResetColor();
            }

            // Access (sum all cells)
            sw.Restart();
            long total = 0;
            Parallel.For(0, numChunks, new ParallelOptions { MaxDegreeOfParallelism = cpuCount }, () => 0L,
                (i, state, localSum) =>
                {
                    int x = i % 1000, y = i / 1000;
                    var chunk = manager.GetChunk(x, y);
                    if (chunk != null)
                    {
                        for (int cx = 0; cx < chunkSize; cx++)
                            for (int cy = 0; cy < chunkSize; cy++)
                                localSum += chunk[cx, cy];
                    }
                    return localSum;
                },
                localSum => Interlocked.Add(ref total, localSum)
            );
            sw.Stop();
            double accessTime = sw.Elapsed.TotalSeconds;
            Console.WriteLine($"  Accessed {numChunks:N0} chunks in {accessTime:F3} s (sum: {total:N0})");

            // Unload
            sw.Restart();
            Parallel.For(0, numChunks, new ParallelOptions { MaxDegreeOfParallelism = cpuCount }, i =>
            {
                int x = i % 1000, y = i / 1000;
                manager.UnloadChunk(x, y);
            });
            sw.Stop();
            double unloadTime = sw.Elapsed.TotalSeconds;
            Console.WriteLine($"  Unloaded {numChunks:N0} chunks in {unloadTime:F3} s");

            // Memory after test
            var memoryAfter = AdvChkSys.AdvChkSys.GetMemoryUsage();
            if (_verboseMode)
            {
                Console.ForegroundColor = _memoryColor;
                Console.WriteLine($"  Memory after unload: {FormatByteSize(memoryAfter.EstimatedChunkMemoryBytes)} " +
                                 $"(change: {FormatByteSize(memoryAfter.EstimatedChunkMemoryBytes - memoryBefore.EstimatedChunkMemoryBytes)})");
                Console.ResetColor();
            }

            // Store results
            _results.Add(new BenchmarkResult
            {
                TestName = "2D Chunks",
                ChunkCount = numChunks,
                ChunkSize = $"{chunkSize}x{chunkSize}",
                CreateTime = createTime,
                AccessTime = accessTime,
                UnloadTime = unloadTime,
                MemoryUsed = memoryAfterCreate.EstimatedChunkMemoryBytes - memoryBefore.EstimatedChunkMemoryBytes
            });

            // Force GC to clean up
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }

        private static void Benchmark3D(int cpuCount, int numChunks, int width, int height, int depth, int maxLoaded)
        {
            Console.ForegroundColor = _headerColor;
            Console.WriteLine($"[3D] {numChunks:N0} chunks of size {width}x{height}x{depth}, maxLoaded={maxLoaded:N0}");
            Console.ResetColor();

            var constraints = new WorldConstraints
            {
                MinChunkX = 0,
                MaxChunkX = 50000,
                MinChunkY = 0,
                MaxChunkY = 50000,
                MinChunkZ = 0,
                MaxChunkZ = 50000,
                MaxLoadedChunks = maxLoaded
            };
            var manager = new ChunkManager3D<byte>(constraints, maxLoaded);

            // Memory before test
            var memoryBefore = AdvChkSys.AdvChkSys.GetMemoryUsage();
            if (_verboseMode)
            {
                Console.ForegroundColor = _memoryColor;
                Console.WriteLine($"  Memory before: {FormatByteSize(memoryBefore.EstimatedChunkMemoryBytes)}");
                Console.ResetColor();
            }

            // Create and fill
            var sw = Stopwatch.StartNew();
            Parallel.For(0, numChunks, new ParallelOptions { MaxDegreeOfParallelism = cpuCount }, i =>
            {
                int x = i % 100, y = i / 100 % 100, z = i / 10000;
                var chunk = manager.LoadOrCreateChunk(x, y, z, width, height, depth);
                for (int cx = 0; cx < width; cx++)
                    for (int cy = 0; cy < height; cy++)
                        for (int cz = 0; cz < depth; cz++)
                            chunk[cx, cy, cz] = (byte)((cx + cy + cz) % 256);
            });
            sw.Stop();
            double createTime = sw.Elapsed.TotalSeconds;
            Console.WriteLine($"  Created and filled {numChunks:N0} chunks in {createTime:F3} s");

            // Memory after creation
            var memoryAfterCreate = AdvChkSys.AdvChkSys.GetMemoryUsage();
            if (_verboseMode)
            {
                Console.ForegroundColor = _memoryColor;
                Console.WriteLine($"  Memory after creation: {FormatByteSize(memoryAfterCreate.EstimatedChunkMemoryBytes)} " +
                                 $"(+{FormatByteSize(memoryAfterCreate.EstimatedChunkMemoryBytes - memoryBefore.EstimatedChunkMemoryBytes)})");
                Console.ResetColor();
            }

            // Access (sum all cells)
            sw.Restart();
            long total = 0;
            Parallel.For(0, numChunks, new ParallelOptions { MaxDegreeOfParallelism = cpuCount }, () => 0L,
                (i, state, localSum) =>
                {
                    int x = i % 100, y = i / 100 % 100, z = i / 10000;
                    var chunk = manager.GetChunk(x, y, z);
                    if (chunk != null)
                    {
                        for (int cx = 0; cx < width; cx++)
                            for (int cy = 0; cy < height; cy++)
                                for (int cz = 0; cz < depth; cz++)
                                    localSum += chunk[cx, cy, cz];
                    }
                    return localSum;
                },
                localSum => Interlocked.Add(ref total, localSum)
            );
            sw.Stop();
            double accessTime = sw.Elapsed.TotalSeconds;
            Console.WriteLine($"  Accessed {numChunks:N0} chunks in {accessTime:F3} s (sum: {total:N0})");

            // Unload
            sw.Restart();
            Parallel.For(0, numChunks, new ParallelOptions { MaxDegreeOfParallelism = cpuCount }, i =>
            {
                int x = i % 100, y = i / 100 % 100, z = i / 10000;
                manager.UnloadChunk(x, y, z);
            });
            sw.Stop();
            double unloadTime = sw.Elapsed.TotalSeconds;
            Console.WriteLine($"  Unloaded {numChunks:N0} chunks in {unloadTime:F3} s");

            // Memory after test
            var memoryAfter = AdvChkSys.AdvChkSys.GetMemoryUsage();
            if (_verboseMode)
            {
                Console.ForegroundColor = _memoryColor;
                Console.WriteLine($"  Memory after unload: {FormatByteSize(memoryAfter.EstimatedChunkMemoryBytes)} " +
                                 $"(change: {FormatByteSize(memoryAfter.EstimatedChunkMemoryBytes - memoryBefore.EstimatedChunkMemoryBytes)})");
                Console.ResetColor();
            }

            // Store results
            _results.Add(new BenchmarkResult
            {
                TestName = "3D Chunks",
                ChunkCount = numChunks,
                ChunkSize = $"{width}x{height}x{depth}",
                CreateTime = createTime,
                AccessTime = accessTime,
                UnloadTime = unloadTime,
                MemoryUsed = memoryAfterCreate.EstimatedChunkMemoryBytes - memoryBefore.EstimatedChunkMemoryBytes
            });

            // Force GC to clean up
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }

        private static void RunMemoryTest(int cpuCount, int chunk2DSize, int chunk3DWidth, int chunk3DHeight, int chunk3DDepth)
        {
            Console.ForegroundColor = _headerColor;
            Console.WriteLine("╔═══════════════════════════════════════════════════════════════╗");
            Console.WriteLine("║                      Memory Usage Test                         ║");
            Console.WriteLine("╚═══════════════════════════════════════════════════════════════╝");
            Console.ResetColor();

            // Initial memory state
            var initialMemory = AdvChkSys.AdvChkSys.GetMemoryUsage();
            Console.WriteLine($"Initial memory state: {FormatByteSize(initialMemory.EstimatedChunkMemoryBytes)}");

            // Test 2D memory scaling
            Console.ForegroundColor = _headerColor;
            Console.WriteLine("\n[2D Memory Scaling Test]");
            Console.ResetColor();

            var manager2D = new ChunkManager2D<byte>(null, 1000000);
            var memoryPoints2D = new List<(int chunkCount, ulong memoryUsed)>();

            for (int i = 1; i <= 10; i++)
            {
                int chunkCount = i * 1000;
                Console.WriteLine($"  Loading {chunkCount:N0} 2D chunks...");
                
                for (int j = (i - 1) * 1000; j < i * 1000; j++)
                {
                    int x = j % 1000, y = j / 1000;
                    var chunk = manager2D.LoadOrCreateChunk(x, y, chunk2DSize, chunk2DSize);
                    // Fill with some data
                    for (int cx = 0; cx < chunk2DSize; cx++)
                        for (int cy = 0; cy < chunk2DSize; cy++)
                            chunk[cx, cy] = (byte)((cx + cy) % 256);
                }

                var memoryReport = AdvChkSys.AdvChkSys.GetMemoryUsage();
                memoryPoints2D.Add((chunkCount, memoryReport.EstimatedChunkMemoryBytes));
                Console.WriteLine($"  Memory used: {FormatByteSize(memoryReport.EstimatedChunkMemoryBytes)}");
            }

            // Clean up 2D chunks
            manager2D = null;
            GC.Collect();
            GC.WaitForPendingFinalizers();

            // Test 3D memory scaling
            Console.ForegroundColor = _headerColor;
            Console.WriteLine("\n[3D Memory Scaling Test]");
            Console.ResetColor();

            var manager3D = new ChunkManager3D<byte>(null, 1000000);
            var memoryPoints3D = new List<(int chunkCount, ulong memoryUsed)>();

            for (int i = 1; i <= 5; i++)
            {
                int chunkCount = i * 10;
                Console.WriteLine($"  Loading {chunkCount:N0} 3D chunks...");
                
                for (int j = (i - 1) * 10; j < i * 10; j++)
                {
                    int x = j % 10, y = j / 10 % 10, z = j / 100;
                    var chunk = manager3D.LoadOrCreateChunk(x, y, z, chunk3DWidth, chunk3DHeight, chunk3DDepth);
                    // Fill with some data
                    for (int cx = 0; cx < chunk3DWidth; cx++)
                        for (int cy = 0; cy < chunk3DHeight; cy++)
                            for (int cz = 0; cz < chunk3DDepth; cz++)
                                chunk[cx, cy, cz] = (byte)((cx + cy + cz) % 256);
                }

                var memoryReport = AdvChkSys.AdvChkSys.GetMemoryUsage();
                memoryPoints3D.Add((chunkCount, memoryReport.EstimatedChunkMemoryBytes));
                Console.WriteLine($"  Memory used: {FormatByteSize(memoryReport.EstimatedChunkMemoryBytes)}");
            }

            // Clean up 3D chunks
            manager3D = null;
            GC.Collect();
            GC.WaitForPendingFinalizers();

            // Display memory scaling results
            Console.ForegroundColor = _headerColor;
            Console.WriteLine("\n[Memory Scaling Results]");
            Console.ResetColor();

            Console.WriteLine("2D Memory Scaling:");
            for (int i = 0; i < memoryPoints2D.Count; i++)
            {
                var point = memoryPoints2D[i];
                ulong bytesPerChunk = i > 0 
                    ? (point.memoryUsed - memoryPoints2D[i - 1].memoryUsed) / (ulong)(point.chunkCount - memoryPoints2D[i - 1].chunkCount)
                    : point.memoryUsed / (ulong)point.chunkCount;
                
                Console.WriteLine($"  {point.chunkCount:N0} chunks: {FormatByteSize(point.memoryUsed)} " +
                                 $"(~{FormatByteSize(bytesPerChunk)}/chunk)");
            }

            Console.WriteLine("\n3D Memory Scaling:");
            for (int i = 0; i < memoryPoints3D.Count; i++)
            {
                var point = memoryPoints3D[i];
                ulong bytesPerChunk = i > 0 
                    ? (point.memoryUsed - memoryPoints3D[i - 1].memoryUsed) / (ulong)(point.chunkCount - memoryPoints3D[i - 1].chunkCount)
                    : point.memoryUsed / (ulong)point.chunkCount;
                
                Console.WriteLine($"  {point.chunkCount:N0} chunks: {FormatByteSize(point.memoryUsed)} " +
                                 $"(~{FormatByteSize(bytesPerChunk)}/chunk)");
            }

            // Final memory state
            var finalMemory = AdvChkSys.AdvChkSys.GetMemoryUsage();
            Console.WriteLine($"\nFinal memory state: {FormatByteSize(finalMemory.EstimatedChunkMemoryBytes)}");
            Console.WriteLine($"Memory change: {FormatByteSize(finalMemory.EstimatedChunkMemoryBytes - initialMemory.EstimatedChunkMemoryBytes)}");
        }

        private static void RunStressTest(int cpuCount, int chunk2DSize, int chunk3DWidth, int chunk3DHeight, int chunk3DDepth)
        {
            Console.ForegroundColor = _headerColor;
            Console.WriteLine("╔═══════════════════════════════════════════════════════════════╗");
            Console.WriteLine("║                        Stress Test                             ║");
            Console.WriteLine("╚═══════════════════════════════════════════════════════════════╝");
            Console.ResetColor();

            // Initial memory state
            var initialMemory = AdvChkSys.AdvChkSys.GetMemoryUsage();
            
            // Create managers with small cache size to force evictions
            var manager2D = new ChunkManager2D<byte>(null, 100);
            var manager3D = new ChunkManager3D<byte>(null, 50);

            Console.WriteLine("Running load/unload stress test (rapid chunk cycling)...");
            
            var sw = Stopwatch.StartNew();
            int iterations = 5;
            int chunksPerIteration = 500;
            
            for (int iter = 0; iter < iterations; iter++)
            {
                Console.WriteLine($"  Iteration {iter + 1}/{iterations}...");
                
                // 2D stress
                Parallel.For(0, chunksPerIteration, new ParallelOptions { MaxDegreeOfParallelism = cpuCount }, i =>
                {
                    int x = i % 100, y = i / 100;
                    // Load chunk
                    var chunk = manager2D.LoadOrCreateChunk(x, y, chunk2DSize, chunk2DSize);
                    // Fill with data
                    for (int cx = 0; cx < chunk2DSize; cx++)
                        for (int cy = 0; cy < chunk2DSize; cy++)
                            chunk[cx, cy] = (byte)((cx + cy + i) % 256);
                    
                    // Access chunk
                    long sum = 0;
                    for (int cx = 0; cx < chunk2DSize; cx++)
                        for (int cy = 0; cy < chunk2DSize; cy++)
                            sum += chunk[cx, cy];
                    
                    // Force some evictions by loading other chunks
                    for (int j = 0; j < 3; j++)
                    {
                        int otherX = (i + j * 200) % 1000;
                        int otherY = (i + j * 200) / 1000;
                        var otherChunk = manager2D.LoadOrCreateChunk(otherX, otherY, chunk2DSize, chunk2DSize);
                        otherChunk[0, 0] = (byte)(i + j);
                    }
                });
                
                // 3D stress
                Parallel.For(0, chunksPerIteration / 10, new ParallelOptions { MaxDegreeOfParallelism = cpuCount }, i =>
                {
                    int x = i % 10, y = i / 10 % 10, z = i / 100;
                    // Load chunk
                    var chunk = manager3D.LoadOrCreateChunk(x, y, z, chunk3DWidth, chunk3DHeight, chunk3DDepth);
                    // Fill with data (just a portion to save time)
                    for (int cx = 0; cx < chunk3DWidth; cx++)
                        for (int cy = 0; cy < chunk3DHeight / 4; cy++)
                            for (int cz = 0; cz < chunk3DDepth; cz++)
                                chunk[cx, cy, cz] = (byte)((cx + cy + cz + i) % 256);
                    
                    // Access chunk
                    long sum = 0;
                    for (int cx = 0; cx < chunk3DWidth; cx++)
                        for (int cy = 0; cy < chunk3DHeight / 4; cy++)
                            for (int cz = 0; cz < chunk3DDepth; cz++)
                                sum += chunk[cx, cy, cz];
                    
                    // Force some evictions by loading other chunks
                    for (int j = 0; j < 2; j++)
                    {
                        int otherX = (i + j * 20) % 30;
                        int otherY = (i + j * 20) / 30 % 30;
                        int otherZ = (i + j * 20) / 900;
                        var otherChunk = manager3D.LoadOrCreateChunk(otherX, otherY, otherZ, chunk3DWidth, chunk3DHeight, chunk3DDepth);
                        otherChunk[0, 0, 0] = (byte)(i + j);
                    }
                });
                
                // Check memory after each iteration
                var memoryReport = AdvChkSys.AdvChkSys.GetMemoryUsage();
                Console.ForegroundColor = _memoryColor;
                Console.WriteLine($"    Memory: {FormatByteSize(memoryReport.EstimatedChunkMemoryBytes)} " +
                                 $"({memoryReport.MemoryUsagePercentage:F2}% of system memory)");
                Console.ResetColor();
                
                // Force GC between iterations
                GC.Collect();
                GC.WaitForPendingFinalizers();
            }
            
            sw.Stop();
            
            Console.WriteLine($"Stress test completed in {sw.Elapsed.TotalSeconds:F2} seconds");
            
            // Final memory state
            var finalMemory = AdvChkSys.AdvChkSys.GetMemoryUsage();
            Console.WriteLine($"Final memory state: {FormatByteSize(finalMemory.EstimatedChunkMemoryBytes)}");
            Console.WriteLine($"Memory change: {FormatByteSize(finalMemory.EstimatedChunkMemoryBytes - initialMemory.EstimatedChunkMemoryBytes)}");
            
            // Clean up
            manager2D = null;
            manager3D = null;
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }

        private static bool CanAllocateChunks(int numChunks, int width, int height, int depth, double safetyFactor)
        {
            long bytesPerChunk = (long)width * height * depth;
            long totalBytes = bytesPerChunk * numChunks;
            long available = GetAvailableMemoryBytes();
            long safeLimit = (long)(available * safetyFactor);
            
            return totalBytes <= safeLimit;
        }

        private static long GetAvailableMemoryBytes()
        {
            return (long)AdvChkSys.AdvChkSys.GetMemoryUsage().AvailableSystemMemoryBytes;
        }

        private static string FormatByteSize(ulong bytes)
        {
            string[] sizes = { "B", "KB", "MB", "GB", "TB" };
            double formattedSize = bytes;
            int order = 0;
            
            while (formattedSize >= 1024 && order < sizes.Length - 1)
            {
                order++;
                formattedSize /= 1024;
            }

            return $"{formattedSize:F2} {sizes[order]}";
        }

        private static void SaveBenchmarkLog()
        {
            // Create logs directory if it doesn't exist
            string logsDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
            Directory.CreateDirectory(logsDirectory);
            
            // Generate a unique filename with timestamp
            string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
            string logFileName = $"ChunkMark_{timestamp}.log";
            string logFilePath = Path.Combine(logsDirectory, logFileName);
            
            // Create a string builder to hold the log content
            var logContent = new StringBuilder();
            
            // Add header
            logContent.AppendLine("=================================================================");
            logContent.AppendLine($"ChunkMark Benchmark Results - {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
            logContent.AppendLine("=================================================================");
            logContent.AppendLine();
            
            // Add system information
            var memoryReport = AdvChkSys.AdvChkSys.GetMemoryUsage();
            logContent.AppendLine("System Information:");
            logContent.AppendLine($"CPU Threads: {Environment.ProcessorCount}");
            logContent.AppendLine($"Total System Memory: {FormatByteSize(memoryReport.TotalSystemMemoryBytes)}");
            logContent.AppendLine($"Available System Memory: {FormatByteSize(memoryReport.AvailableSystemMemoryBytes)}");
            logContent.AppendLine($"AdvChkSys Version: {AdvChkSys.AdvChkSys.Version}");
            logContent.AppendLine();
            
            // Add benchmark results
            logContent.AppendLine("Benchmark Results:");
            logContent.AppendLine("------------------------------------------------------------------");
            if (_results.Count == 0)
            {
                logContent.AppendLine("No benchmark results to display.");
            }
            else
            {
                // Header row
                logContent.AppendLine(
                    $"{"Test",-15} | {"Chunks",-10} | {"Size",-12} | {"Create (s)",-10} | {"Access (s)",-10} | {"Unload (s)",-10} | {"Memory",-12}");
                logContent.AppendLine(new string('-', 90));
                
                // Data rows
                foreach (var result in _results)
                {
                    logContent.AppendLine(
                        $"{result.TestName,-15} | {result.ChunkCount,-10:N0} | {result.ChunkSize,-12} | " +
                        $"{result.CreateTime,-10:F3} | {result.AccessTime,-10:F3} | {result.UnloadTime,-10:F3} | " +
                        $"{FormatByteSize(result.MemoryUsed),-12}");
                }
            }
            logContent.AppendLine();
            
            // Add performance metrics
            logContent.AppendLine("Performance Metrics:");
            logContent.AppendLine("------------------------------------------------------------------");
            if (_results.Count > 0)
            {
                var create2DRate = _results.Where(r => r.TestName.Contains("2D")).Select(r => r.ChunkCount / r.CreateTime).FirstOrDefault();
                var create3DRate = _results.Where(r => r.TestName.Contains("3D")).Select(r => r.ChunkCount / r.CreateTime).FirstOrDefault();
                var access2DRate = _results.Where(r => r.TestName.Contains("2D")).Select(r => r.ChunkCount / r.AccessTime).FirstOrDefault();
                var access3DRate = _results.Where(r => r.TestName.Contains("3D")).Select(r => r.ChunkCount / r.AccessTime).FirstOrDefault();

                if (create2DRate > 0)
                    logContent.AppendLine($"2D Chunk Creation Rate: {create2DRate:N0} chunks/second");
                if (create3DRate > 0)
                    logContent.AppendLine($"3D Chunk Creation Rate: {create3DRate:N0} chunks/second");
                if (access2DRate > 0)
                    logContent.AppendLine($"2D Chunk Access Rate: {access2DRate:N0} chunks/second");
                if (access3DRate > 0)
                    logContent.AppendLine($"3D Chunk Access Rate: {access3DRate:N0} chunks/second");
            }
            logContent.AppendLine();
            
            // Add memory usage summary
            logContent.AppendLine("Memory Usage Summary:");
            logContent.AppendLine("------------------------------------------------------------------");
            logContent.AppendLine($"Current Memory Usage: {FormatByteSize(memoryReport.EstimatedChunkMemoryBytes)}");
            logContent.AppendLine($"Active Chunks: {memoryReport.ActiveChunkCount:N0}");
            logContent.AppendLine($"Memory Usage: {memoryReport.MemoryUsagePercentage:F2}% of total system memory");
            
            // Memory efficiency metrics
            if (_results.Count > 0)
            {
                var result2D = _results.FirstOrDefault(r => r.TestName.Contains("2D"));
                var result3D = _results.FirstOrDefault(r => r.TestName.Contains("3D"));

                if (result2D != null && result2D.ChunkCount > 0)
                {
                    ulong bytesPerChunk2D = result2D.MemoryUsed / (ulong)result2D.ChunkCount;
                    logContent.AppendLine($"2D Memory Efficiency: {FormatByteSize(bytesPerChunk2D)}/chunk");
                }

                if (result3D != null && result3D.ChunkCount > 0)
                {
                    ulong bytesPerChunk3D = result3D.MemoryUsed / (ulong)result3D.ChunkCount;
                    logContent.AppendLine($"3D Memory Efficiency: {FormatByteSize(bytesPerChunk3D)}/chunk");
                }
            }
            // Detailed Chunk Info
            logContent.AppendLine();
            logContent.AppendLine("Detailed Chunk Information:");
            logContent.AppendLine("------------------------------------------------------------------");
            logContent.AppendLine($"Active Chunks (reported by ChunkResourceManager): {memoryReport.ActiveChunkCount:N0}");

            // Get counts from results
            int total2DChunks = _results.Where(r => r.TestName.Contains("2D")).Sum(r => r.ChunkCount);
            int total3DChunks = _results.Where(r => r.TestName.Contains("3D")).Sum(r => r.ChunkCount);
            int totalChunks = total2DChunks + total3DChunks;

            logContent.AppendLine($"Total 2D Chunks Created: {total2DChunks:N0}");
            logContent.AppendLine($"Total 3D Chunks Created: {total3DChunks:N0}");
            logContent.AppendLine($"Total Chunks Created: {totalChunks:N0}");

            if (memoryReport.ActiveChunkCount != totalChunks)
            {
                logContent.AppendLine();
                logContent.AppendLine("Possible reasons for the difference:");
                logContent.AppendLine("1. Chunk eviction due to LRU cache capacity limits");
                logContent.AppendLine("2. Chunks unloaded during benchmark cleanup");
                logContent.AppendLine("3. All-air chunks using flyweight pattern (counted once)");
                logContent.AppendLine("4. Garbage collection removing unreferenced chunks");
            }

            
            // Write the log to file
            File.WriteAllText(logFilePath, logContent.ToString());
            
            Console.ForegroundColor = _infoColor;
            Console.WriteLine($"\nBenchmark results saved to: {logFilePath}");
            Console.ResetColor();
        }

        private static void PrintDetailedChunkInfo()
        {
            Console.ForegroundColor = _headerColor;
            Console.WriteLine("\nDetailed Chunk Information:");
            Console.ResetColor();
            
            var memoryReport = AdvChkSys.AdvChkSys.GetMemoryUsage();
            
            Console.WriteLine($"Active Chunks (reported by ChunkResourceManager): {memoryReport.ActiveChunkCount:N0}");
            
            // Get counts from results
            int total2DChunks = _results.Where(r => r.TestName.Contains("2D")).Sum(r => r.ChunkCount);
            int total3DChunks = _results.Where(r => r.TestName.Contains("3D")).Sum(r => r.ChunkCount);
            int totalChunks = total2DChunks + total3DChunks;
            
            Console.WriteLine($"Total 2D Chunks Created: {total2DChunks:N0}");
            Console.WriteLine($"Total 3D Chunks Created: {total3DChunks:N0}");
            Console.WriteLine($"Total Chunks Created: {totalChunks:N0}");
            
            if (memoryReport.ActiveChunkCount != totalChunks)
            {
                Console.ForegroundColor = _infoColor;
                Console.WriteLine("\nPossible reasons for the difference:");
                Console.WriteLine("1. Chunk eviction due to LRU cache capacity limits");
                Console.WriteLine("2. Chunks unloaded during benchmark cleanup");
                Console.WriteLine("3. All-air chunks using flyweight pattern (counted once)");
                Console.WriteLine("4. Garbage collection removing unreferenced chunks");
                Console.ResetColor();
            }
        }
    }

    public class BenchmarkResult
    {
        public string TestName { get; set; } = "";
        public int ChunkCount { get; set; }
        public string ChunkSize { get; set; } = "";
        public double CreateTime { get; set; }
        public double AccessTime { get; set; }
        public double UnloadTime { get; set; }
        public ulong MemoryUsed { get; set; }
    }
}