using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using AdvChkSys.Diagnostics;

namespace ChunkMark
{
    /// <summary>
    /// Provides detailed memory reporting and visualization for benchmarks.
    /// </summary>
    public class MemoryReporter
    {
        private readonly List<MemorySnapshot> _snapshots = new List<MemorySnapshot>();
        private readonly Stopwatch _timer = new Stopwatch();
        private readonly string _reportName;

        public MemoryReporter(string reportName)
        {
            _reportName = reportName;
            _timer.Start();
        }

        /// <summary>
        /// Takes a memory snapshot with the given label.
        /// </summary>
        public void TakeSnapshot(string label)
        {
            var report = AdvChkSys.AdvChkSys.GetMemoryUsage();
            _snapshots.Add(new MemorySnapshot
            {
                Label = label,
                TimeSeconds = _timer.Elapsed.TotalSeconds,
                Report = report
            });
        }

        /// <summary>
        /// Generates a detailed memory report as a string.
        /// </summary>
        public string GenerateReport()
        {
            if (_snapshots.Count == 0)
                return "No memory snapshots recorded.";

            var sb = new StringBuilder();
            sb.AppendLine($"Memory Report: {_reportName}");
            sb.AppendLine("=".PadRight(50, '='));
            sb.AppendLine();

            sb.AppendLine("Snapshots:");
            sb.AppendLine("┌─────────────────┬──────────┬─────────────────┬─────────────┬───────────┐");
            sb.AppendLine("│ Label           │ Time (s) │ Chunk Memory    │ Active      │ Usage %   │");
            sb.AppendLine("├─────────────────┼──────────┼─────────────────┼─────────────┼───────────┤");

            foreach (var snapshot in _snapshots)
            {
                string label = snapshot.Label.PadRight(15).Substring(0, 15);
                string time = $"{snapshot.TimeSeconds:F2}".PadRight(8).Substring(0, 8);
                string memory = FormatByteSize(snapshot.Report.EstimatedChunkMemoryBytes).PadRight(15).Substring(0, 15);
                string active = $"{snapshot.Report.ActiveChunkCount:N0}".PadRight(11).Substring(0, 11);
                string usage = $"{snapshot.Report.MemoryUsagePercentage:F2}%".PadRight(9).Substring(0, 9);

                sb.AppendLine($"│ {label} │ {time} │ {memory} │ {active} │ {usage} │");
            }
            sb.AppendLine("└─────────────────┴──────────┴─────────────────┴─────────────┴───────────┘");
            sb.AppendLine();

            // Memory change analysis
            if (_snapshots.Count >= 2)
            {
                var first = _snapshots.First();
                var last = _snapshots.Last();
                var maxMem = _snapshots.Max(s => s.Report.EstimatedChunkMemoryBytes);
                var minMem = _snapshots.Min(s => s.Report.EstimatedChunkMemoryBytes);

                sb.AppendLine("Memory Analysis:");
                sb.AppendLine($"  Initial Memory: {FormatByteSize(first.Report.EstimatedChunkMemoryBytes)}");
                sb.AppendLine($"  Final Memory: {FormatByteSize(last.Report.EstimatedChunkMemoryBytes)}");
                sb.AppendLine($"  Net Change: {FormatByteSize(last.Report.EstimatedChunkMemoryBytes - first.Report.EstimatedChunkMemoryBytes)}");
                sb.AppendLine($"  Peak Memory: {FormatByteSize(maxMem)}");
                sb.AppendLine($"  Minimum Memory: {FormatByteSize(minMem)}");
                sb.AppendLine($"  Memory Volatility: {FormatByteSize(maxMem - minMem)}");
            }

            return sb.ToString();
        }

        /// <summary>
        /// Saves the memory report to a file.
        /// </summary>
        public void SaveReportToFile(string filePath)
        {
            string report = GenerateReport();
            File.WriteAllText(filePath, report);
        }

        /// <summary>
        /// Formats a byte size into a human-readable string (KB, MB, GB).
        /// </summary>
        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 class MemorySnapshot
        {
            public string Label { get; set; } = "";
            public double TimeSeconds { get; set; }
            public MemoryUsageReport Report { get; set; } = null!;
        }
    }
}