#nullable enable
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using AdvChkSys.Resources;
using AdvChkSys.Util;

namespace AdvChkSys.Diagnostics
{
    /// <summary>
    /// Provides memory usage statistics and reporting for the AdvChkSys library.
    /// Helps client code monitor memory consumption of chunks and related resources.
    /// </summary>
    public static class MemoryUsageReporter
    {
        /// <summary>
        /// Gets the current memory usage statistics for the AdvChkSys library.
        /// </summary>
        /// <returns>A MemoryUsageReport containing detailed memory statistics</returns>
        public static MemoryUsageReport GetMemoryUsage()
        {
            var report = new MemoryUsageReport
            {
                ActiveChunkCount = ChunkResourceManager.GetActiveChunkCount(),
                TotalSystemMemoryBytes = GetTotalSystemMemory(),
                AvailableSystemMemoryBytes = MemoryHelper.GetAvailableMemoryBytes(),
                Timestamp = DateTime.UtcNow
            };

            // Calculate estimated chunk memory usage
            report.EstimatedChunkMemoryBytes = EstimateChunkMemoryUsage(report.ActiveChunkCount);

            return report;
        }

        /// <summary>
        /// Estimates the memory usage of chunks based on the active chunk count and average chunk size.
        /// </summary>
        private static ulong EstimateChunkMemoryUsage(int chunkCount)
        {
            // This is an estimate based on typical chunk sizes
            // For more accurate reporting, we would need to track actual sizes
            const int averageChunkSizeBytes = 32 * 32 * 4; // Assuming 32x32 chunks with 4 bytes per cell on average
            return (ulong)chunkCount * (ulong)averageChunkSizeBytes;
        }

        /// <summary>
        /// Gets the total system memory in bytes.
        /// </summary>
        private static ulong GetTotalSystemMemory()
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                var memStatus = new MemoryHelper.MEMORYSTATUSEX
                {
                    dwLength = (uint)Marshal.SizeOf(typeof(MemoryHelper.MEMORYSTATUSEX))
                };
                if (MemoryHelper.GlobalMemoryStatusEx(ref memStatus))
                {
                    return memStatus.ullTotalPhys;
                }
            }

            // For non-Windows platforms or if Windows call fails, use a fallback
            return 8UL * 1024 * 1024 * 1024; // Assume 8GB as fallback
        }

        /// <summary>
        /// Logs memory usage information to the provided action.
        /// </summary>
        /// <param name="logAction">Action to handle the log message</param>
        public static void LogMemoryUsage(Action<string> logAction)
        {
            var report = GetMemoryUsage();

            logAction($"--- AdvChkSys Memory Report ({report.Timestamp:yyyy-MM-dd HH:mm:ss}) ---");
            logAction($"Active Chunks: {report.ActiveChunkCount:N0}");
            logAction($"Estimated Chunk Memory: {FormatByteSize(report.EstimatedChunkMemoryBytes)}");
            logAction($"Available System Memory: {FormatByteSize(report.AvailableSystemMemoryBytes)}");
            logAction($"Total System Memory: {FormatByteSize(report.TotalSystemMemoryBytes)}");
            logAction($"Memory Usage %: {report.MemoryUsagePercentage:F2}%");
            logAction("-------------------------------------------");
        }

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

    /// <summary>
    /// Contains detailed memory usage statistics for the AdvChkSys library.
    /// </summary>
    public class MemoryUsageReport
    {
        /// <summary>
        /// The number of active chunks currently being managed.
        /// </summary>
        public int ActiveChunkCount { get; internal set; }

        /// <summary>
        /// Estimated memory usage of all chunks in bytes.
        /// </summary>
        public ulong EstimatedChunkMemoryBytes { get; internal set; }

        /// <summary>
        /// Available system memory in bytes.
        /// </summary>
        public ulong AvailableSystemMemoryBytes { get; internal set; }

        /// <summary>
        /// Total system memory in bytes.
        /// </summary>
        public ulong TotalSystemMemoryBytes { get; internal set; }

        /// <summary>
        /// Timestamp when this report was generated.
        /// </summary>
        public DateTime Timestamp { get; internal set; }

        /// <summary>
        /// Percentage of total system memory used by chunks.
        /// </summary>
        public double MemoryUsagePercentage =>
            TotalSystemMemoryBytes > 0
                ? (double)EstimatedChunkMemoryBytes / TotalSystemMemoryBytes * 100
                : 0;
    }
}