// ============================================================================
// mb_clouseau - Metrics Snapshot Data Model
// Uncovering clues with MusicBee Clouseau
// ============================================================================

using System;

namespace MusicBeePlugin.Clouseau.Metrics
{
    /// <summary>
    /// Point-in-time snapshot of all collected metrics.
    /// Immutable data transfer object for thread-safe access.
    /// </summary>
    public class MetricsSnapshot
    {
        // ====================================================================
        // Timestamp
        // ====================================================================

        /// <summary>
        /// When this snapshot was captured.
        /// </summary>
        public DateTime Timestamp { get; set; }

        // ====================================================================
        // System Metrics
        // ====================================================================

        /// <summary>
        /// System-wide CPU usage percentage (0-100).
        /// </summary>
        public float CpuPercent { get; set; }

        /// <summary>
        /// Available physical memory in megabytes.
        /// </summary>
        public long AvailableMemoryMB { get; set; }

        /// <summary>
        /// Total physical memory in megabytes.
        /// </summary>
        public long TotalMemoryMB { get; set; }

        /// <summary>
        /// Memory usage percentage (used/total * 100).
        /// </summary>
        public float MemoryPercent { get; set; }

        /// <summary>
        /// Number of CPU cores available.
        /// </summary>
        public int CpuCoreCount { get; set; }

        /// <summary>
        /// Per-core CPU usage percentages (if available).
        /// </summary>
        public float[] PerCoreCpuPercent { get; set; }

        // ====================================================================
        // MusicBee Process Metrics (CRITICAL for leak detection)
        // ====================================================================

        /// <summary>
        /// MusicBee working set (physical memory) in megabytes.
        /// </summary>
        public long MBWorkingSetMB { get; set; }

        /// <summary>
        /// MusicBee working set in bytes (full precision).
        /// </summary>
        public long MBWorkingSetBytes { get; set; }

        /// <summary>
        /// MusicBee private bytes in megabytes.
        /// KEY METRIC for memory leak detection!
        /// </summary>
        public long MBPrivateBytesMB { get; set; }

        /// <summary>
        /// MusicBee private bytes (full precision).
        /// </summary>
        public long MBPrivateBytesRaw { get; set; }

        /// <summary>
        /// MusicBee virtual memory size in megabytes.
        /// </summary>
        public long MBVirtualMemoryMB { get; set; }

        /// <summary>
        /// MusicBee handle count.
        /// KEY METRIC for handle leak detection!
        /// Steadily increasing = LEAK!
        /// </summary>
        public int MBHandleCount { get; set; }

        /// <summary>
        /// GDI object count (fonts, brushes, pens, bitmaps, DCs, etc.)
        /// Leaking GDI = graphics/drawing code not disposing properly
        /// </summary>
        public int GdiObjectCount { get; set; }

        /// <summary>
        /// USER object count (windows, menus, cursors, icons, etc.)
        /// Leaking USER = UI controls/windows not being destroyed
        /// </summary>
        public int UserObjectCount { get; set; }

        /// <summary>
        /// Peak GDI objects used (lifetime high water mark).
        /// </summary>
        public int GdiObjectPeak { get; set; }

        /// <summary>
        /// Peak USER objects used (lifetime high water mark).
        /// </summary>
        public int UserObjectPeak { get; set; }

        /// <summary>
        /// Kernel handles (files, registry, events, mutexes, etc.)
        /// Calculated as: Total - GDI - USER
        /// Leaking Kernel = file handles, events, or sync objects not closed
        /// </summary>
        public int KernelHandleCount { get; set; }

        /// <summary>
        /// GDI object delta from previous sample.
        /// </summary>
        public int GdiObjectDelta { get; set; }

        /// <summary>
        /// USER object delta from previous sample.
        /// </summary>
        public int UserObjectDelta { get; set; }

        /// <summary>
        /// Kernel handle delta from previous sample.
        /// </summary>
        public int KernelHandleDelta { get; set; }

        /// <summary>
        /// MusicBee thread count.
        /// </summary>
        public int MBThreadCount { get; set; }

        /// <summary>
        /// Total CPU time consumed by MusicBee since process start.
        /// </summary>
        public TimeSpan MBCpuTime { get; set; }

        /// <summary>
        /// User-mode CPU time consumed by MusicBee.
        /// </summary>
        public TimeSpan MBUserCpuTime { get; set; }

        /// <summary>
        /// Privileged (kernel) CPU time consumed by MusicBee.
        /// </summary>
        public TimeSpan MBPrivilegedCpuTime { get; set; }

        /// <summary>
        /// MusicBee process ID.
        /// </summary>
        public int MBProcessId { get; set; }

        /// <summary>
        /// Whether MusicBee process was found.
        /// </summary>
        public bool MBProcessFound { get; set; }

        // ====================================================================
        // Self-Monitoring (mb_clouseau plugin process)
        // ====================================================================

        /// <summary>
        /// Plugin's own working set in megabytes.
        /// </summary>
        public long SelfWorkingSetMB { get; set; }

        /// <summary>
        /// Plugin's own private bytes in megabytes.
        /// </summary>
        public long SelfPrivateBytesMB { get; set; }

        /// <summary>
        /// Plugin's own handle count.
        /// </summary>
        public int SelfHandleCount { get; set; }

        /// <summary>
        /// Plugin's own thread count.
        /// </summary>
        public int SelfThreadCount { get; set; }

        // ====================================================================
        // CLR / GC Metrics
        // ====================================================================

        /// <summary>
        /// Generation 0 garbage collection count.
        /// Frequent Gen0 collections are normal.
        /// </summary>
        public int GCGen0Collections { get; set; }

        /// <summary>
        /// Generation 1 garbage collection count.
        /// </summary>
        public int GCGen1Collections { get; set; }

        /// <summary>
        /// Generation 2 garbage collection count.
        /// Frequent Gen2 collections may indicate memory pressure.
        /// </summary>
        public int GCGen2Collections { get; set; }

        /// <summary>
        /// Total managed heap size in bytes.
        /// </summary>
        public long ManagedHeapBytes { get; set; }

        /// <summary>
        /// Total managed heap size in megabytes.
        /// </summary>
        public long ManagedHeapMB { get; set; }

        /// <summary>
        /// Percentage of time spent in GC (from perf counter, if available).
        /// High values indicate GC pressure.
        /// </summary>
        public float GCTimePercent { get; set; }

        /// <summary>
        /// Gen 0 heap size in bytes (from perf counter).
        /// </summary>
        public long Gen0HeapSize { get; set; }

        /// <summary>
        /// Gen 1 heap size in bytes (from perf counter).
        /// </summary>
        public long Gen1HeapSize { get; set; }

        /// <summary>
        /// Gen 2 heap size in bytes (from perf counter).
        /// </summary>
        public long Gen2HeapSize { get; set; }

        /// <summary>
        /// Large Object Heap size in bytes (from perf counter).
        /// </summary>
        public long LargeObjectHeapSize { get; set; }

        // ====================================================================
        // Audio Metrics (Full MusicBee API Integration)
        // ====================================================================

        /// <summary>
        /// Current audio output device name.
        /// </summary>
        public string AudioOutputDevice { get; set; }

        /// <summary>
        /// Current sample rate in Hz (e.g., 44100, 48000).
        /// </summary>
        public int SampleRate { get; set; }

        /// <summary>
        /// Current bit depth (e.g., 16, 24, 32).
        /// </summary>
        public int BitDepth { get; set; }

        /// <summary>
        /// Number of audio channels (e.g., 2 for stereo).
        /// </summary>
        public int AudioChannels { get; set; }

        /// <summary>
        /// Audio format/codec (e.g., "MP3", "FLAC", "AAC").
        /// </summary>
        public string AudioFormat { get; set; }

        /// <summary>
        /// Audio bitrate string (e.g., "320 kbps").
        /// </summary>
        public string AudioBitrate { get; set; }

        /// <summary>
        /// Current volume level (0.0 to 1.0).
        /// </summary>
        public float Volume { get; set; }

        /// <summary>
        /// Whether audio is muted.
        /// </summary>
        public bool IsMuted { get; set; }

        /// <summary>
        /// Whether DSP processing is enabled.
        /// </summary>
        public bool DspEnabled { get; set; }

        /// <summary>
        /// Whether the equalizer is enabled.
        /// </summary>
        public bool EqualizerEnabled { get; set; }

        /// <summary>
        /// Whether crossfade is enabled.
        /// </summary>
        public bool CrossfadeEnabled { get; set; }

        /// <summary>
        /// Current ReplayGain mode.
        /// </summary>
        public Plugin.ReplayGainMode ReplayGainMode { get; set; }

        /// <summary>
        /// Number of available output devices.
        /// </summary>
        public int AvailableDeviceCount { get; set; }

        // ====================================================================
        // Trend Analysis (Calculated Deltas)
        // ====================================================================

        /// <summary>
        /// Handle count change since previous sample.
        /// Positive value trending upward = potential handle leak!
        /// </summary>
        public int HandleCountDelta { get; set; }

        /// <summary>
        /// Private bytes change since previous sample.
        /// Consistently positive = potential memory leak!
        /// </summary>
        public long PrivateBytesDelta { get; set; }

        /// <summary>
        /// Working set change since previous sample.
        /// </summary>
        public long WorkingSetDelta { get; set; }

        /// <summary>
        /// Thread count change since previous sample.
        /// </summary>
        public int ThreadCountDelta { get; set; }

        /// <summary>
        /// Managed heap change since previous sample.
        /// </summary>
        public long ManagedHeapDelta { get; set; }

        /// <summary>
        /// Cumulative handle count change over tracking period.
        /// Used to detect slow leaks over time.
        /// </summary>
        public int HandleCountTrendTotal { get; set; }

        /// <summary>
        /// Cumulative private bytes change over tracking period.
        /// Used to detect slow memory leaks over time.
        /// </summary>
        public long PrivateBytesTrendTotal { get; set; }

        /// <summary>
        /// Number of samples in the trend tracking window.
        /// </summary>
        public int TrendSampleCount { get; set; }

        // ====================================================================
        // Alert Flags
        // ====================================================================

        /// <summary>
        /// True if handle leak is suspected (consistent increase).
        /// </summary>
        public bool HandleLeakSuspected { get; set; }

        /// <summary>
        /// True if memory leak is suspected (consistent increase in private bytes).
        /// </summary>
        public bool MemoryLeakSuspected { get; set; }

        /// <summary>
        /// True if GC pressure is high (frequent Gen2 collections or high % time in GC).
        /// </summary>
        public bool GCPressureHigh { get; set; }

        /// <summary>
        /// True if system memory is low.
        /// </summary>
        public bool LowMemoryWarning { get; set; }

        // ====================================================================
        // Constructors
        // ====================================================================

        /// <summary>
        /// Creates a new empty metrics snapshot with current timestamp.
        /// </summary>
        public MetricsSnapshot()
        {
            Timestamp = DateTime.Now;
            AudioOutputDevice = string.Empty;
            AudioFormat = string.Empty;
            AudioBitrate = string.Empty;
            PerCoreCpuPercent = Array.Empty<float>();
        }

        // ====================================================================
        // Formatting Methods
        // ====================================================================

        /// <summary>
        /// Formats the snapshot as a compact metrics log line.
        /// Format: CPU=15%|MEM=4.2GB/16GB(26%)|MB_WS=245MB|MB_PB=312MB|MB_Handles=1847(+3)|GC0=142|GC1=23|GC2=3
        /// </summary>
        public string ToLogLine()
        {
            var handleDeltaStr = HandleCountDelta >= 0 ? $"+{HandleCountDelta}" : HandleCountDelta.ToString();
            var privateBytesDeltaStr = PrivateBytesDelta >= 0
                ? $"+{FormatBytes(PrivateBytesDelta)}"
                : $"-{FormatBytes(Math.Abs(PrivateBytesDelta))}";

            var usedMemoryGB = (TotalMemoryMB - AvailableMemoryMB) / 1024.0;
            var totalMemoryGB = TotalMemoryMB / 1024.0;

            var line = $"CPU={CpuPercent:F0}%|" +
                       $"MEM={usedMemoryGB:F1}GB/{totalMemoryGB:F1}GB({MemoryPercent:F0}%)|" +
                       $"MB_WS={MBWorkingSetMB}MB|" +
                       $"MB_PB={MBPrivateBytesMB}MB({privateBytesDeltaStr})|" +
                       $"MB_Handles={MBHandleCount}({handleDeltaStr})|" +
                       $"MB_Threads={MBThreadCount}|" +
                       $"GC0={GCGen0Collections}|GC1={GCGen1Collections}|GC2={GCGen2Collections}|" +
                       $"Heap={ManagedHeapMB}MB";

            // Add warning flags if present
            if (HandleLeakSuspected)
                line += "|[!HANDLE_LEAK]";
            if (MemoryLeakSuspected)
                line += "|[!MEM_LEAK]";
            if (GCPressureHigh)
                line += "|[!GC_PRESSURE]";
            if (LowMemoryWarning)
                line += "|[!LOW_MEM]";

            return line;
        }

        /// <summary>
        /// Formats bytes as human-readable string (KB, MB, GB).
        /// </summary>
        private static string FormatBytes(long bytes)
        {
            if (bytes < 0) bytes = Math.Abs(bytes);

            if (bytes >= 1024 * 1024 * 1024)
                return $"{bytes / (1024.0 * 1024 * 1024):F1}GB";
            if (bytes >= 1024 * 1024)
                return $"{bytes / (1024.0 * 1024):F1}MB";
            if (bytes >= 1024)
                return $"{bytes / 1024.0:F1}KB";
            return $"{bytes}B";
        }

        /// <summary>
        /// Creates a detailed multi-line summary for diagnostics.
        /// </summary>
        public string ToDetailedString()
        {
            return $@"=== Metrics Snapshot at {Timestamp:yyyy-MM-dd HH:mm:ss.fff} ===

SYSTEM:
  CPU: {CpuPercent:F1}% ({CpuCoreCount} cores)
  Memory: {TotalMemoryMB - AvailableMemoryMB}MB used / {TotalMemoryMB}MB total ({MemoryPercent:F1}%)
  Available: {AvailableMemoryMB}MB

MUSICBEE PROCESS (PID: {MBProcessId}):
  Found: {MBProcessFound}
  Working Set: {MBWorkingSetMB}MB ({MBWorkingSetBytes:N0} bytes)
  Private Bytes: {MBPrivateBytesMB}MB ({MBPrivateBytesRaw:N0} bytes) [Delta: {PrivateBytesDelta:+#;-#;0}]
  Virtual Memory: {MBVirtualMemoryMB}MB
  Handles: {MBHandleCount} [Delta: {HandleCountDelta:+#;-#;0}]
  Threads: {MBThreadCount}
  CPU Time: {MBCpuTime:hh\:mm\:ss\.fff} (User: {MBUserCpuTime:hh\:mm\:ss}, Kernel: {MBPrivilegedCpuTime:hh\:mm\:ss})

CLR / GC:
  Gen 0 Collections: {GCGen0Collections}
  Gen 1 Collections: {GCGen1Collections}
  Gen 2 Collections: {GCGen2Collections}
  Managed Heap: {ManagedHeapMB}MB ({ManagedHeapBytes:N0} bytes)
  % Time in GC: {GCTimePercent:F1}%
  Gen 0 Heap: {Gen0HeapSize / (1024 * 1024)}MB
  Gen 1 Heap: {Gen1HeapSize / (1024 * 1024)}MB
  Gen 2 Heap: {Gen2HeapSize / (1024 * 1024)}MB
  LOH: {LargeObjectHeapSize / (1024 * 1024)}MB

TRENDS ({TrendSampleCount} samples):
  Handle Trend: {HandleCountTrendTotal:+#;-#;0} total change
  Private Bytes Trend: {FormatBytes(PrivateBytesTrendTotal)} total change

ALERTS:
  Handle Leak Suspected: {HandleLeakSuspected}
  Memory Leak Suspected: {MemoryLeakSuspected}
  GC Pressure High: {GCPressureHigh}
  Low Memory Warning: {LowMemoryWarning}

AUDIO:
  Output Device: {AudioOutputDevice} ({AvailableDeviceCount} available)
  Sample Rate: {SampleRate}Hz
  Bit Depth: {BitDepth}-bit
  Channels: {AudioChannels}
  Format: {AudioFormat}
  Bitrate: {AudioBitrate}
  Volume: {Volume:P0} {(IsMuted ? "(MUTED)" : "")}
  DSP: {DspEnabled}, EQ: {EqualizerEnabled}, Crossfade: {CrossfadeEnabled}
  ReplayGain: {ReplayGainMode}
";
        }

        /// <summary>
        /// Creates a shallow copy of this snapshot.
        /// </summary>
        public MetricsSnapshot Clone()
        {
            var clone = (MetricsSnapshot)MemberwiseClone();
            if (PerCoreCpuPercent != null)
            {
                clone.PerCoreCpuPercent = new float[PerCoreCpuPercent.Length];
                Array.Copy(PerCoreCpuPercent, clone.PerCoreCpuPercent, PerCoreCpuPercent.Length);
            }
            return clone;
        }
    }
}
