using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;


namespace AdvChkSys.Threading
{
    /// <summary>
    /// Monitors and reports on threading performance in the chunk system.
    /// </summary>
    public class ChunkThreadingPerformanceMonitor : IDisposable
    {
        // Performance metrics
        private readonly ConcurrentDictionary<string, PerformanceMetric> _metrics = new();

        // Sampling timer
        private readonly Timer _samplingTimer;

        // Sampling interval
        private readonly TimeSpan _samplingInterval;

        // Maximum history to keep
        private readonly int _maxHistory;

        // Whether monitoring is enabled
        private bool _isEnabled;

        /// <summary>
        /// Initializes a new instance of the ChunkThreadingPerformanceMonitor class.
        /// </summary>
        /// <param name="samplingIntervalMs">Sampling interval in milliseconds</param>
        /// <param name="maxHistory">Maximum number of samples to keep</param>
        public ChunkThreadingPerformanceMonitor(int samplingIntervalMs = 1000, int maxHistory = 60)
        {
            _samplingInterval = TimeSpan.FromMilliseconds(samplingIntervalMs);
            _maxHistory = maxHistory;
            _samplingTimer = new Timer(SamplePerformance, null, Timeout.Infinite, Timeout.Infinite);
        }

        /// <summary>
        /// Starts monitoring performance.
        /// </summary>
        public void Start()
        {
            if (!_isEnabled)
            {
                _isEnabled = true;
                _samplingTimer.Change(TimeSpan.Zero, _samplingInterval);
            }
        }

        /// <summary>
        /// Stops monitoring performance.
        /// </summary>
        public void Stop()
        {
            if (_isEnabled)
            {
                _isEnabled = false;
                _samplingTimer.Change(Timeout.Infinite, Timeout.Infinite);
            }
        }

        /// <summary>
        /// Samples performance metrics.
        /// </summary>
        private void SamplePerformance(object? state)
        {
            if (!_isEnabled)
                return;

            // Sample thread pool information
            ThreadPool.GetAvailableThreads(out int workerThreads, out int completionPortThreads);
            ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxCompletionPortThreads);

            // Calculate thread pool usage
            double workerThreadUsage = 1.0 - ((double)workerThreads / maxWorkerThreads);
            double ioThreadUsage = 1.0 - ((double)completionPortThreads / maxCompletionPortThreads);

            // Update metrics
            UpdateMetric("ThreadPool.WorkerThreadUsage", workerThreadUsage);
            UpdateMetric("ThreadPool.IOThreadUsage", ioThreadUsage);

            // Sample operation queue information
            var operationQueue = ChunkThreadingManager.Instance.OperationQueue;
            UpdateMetric("OperationQueue.PendingOperations", operationQueue.PendingOperationCount);
            UpdateMetric("OperationQueue.ActiveOperations", operationQueue.ActiveOperationCount);

            // Sample diagnostics information
            UpdateMetric("Diagnostics.ActiveOperations", ChunkThreadingDiagnostics.GetActiveOperationCount());
            UpdateMetric("Diagnostics.LockContentions", ChunkThreadingDiagnostics.GetTotalLockContentionCount());

            // Sample process information
            var process = Process.GetCurrentProcess();
            // Fix: Use process.TotalProcessorTime and calculate uptime manually
            TimeSpan upTime = DateTime.Now - process.StartTime;
            UpdateMetric("Process.CPU", process.TotalProcessorTime.TotalMilliseconds / Environment.ProcessorCount / upTime.TotalMilliseconds);
            UpdateMetric("Process.Memory", process.WorkingSet64 / 1024.0 / 1024.0); // MB
            UpdateMetric("Process.Threads", process.Threads.Count);
        }

        /// <summary>
        /// Updates a performance metric.
        /// </summary>
        private void UpdateMetric(string name, double value)
        {
            if (!_metrics.TryGetValue(name, out var metric))
            {
                metric = new PerformanceMetric(_maxHistory);
                _metrics[name] = metric;
            }

            metric.AddSample(value);
        }

        /// <summary>
        /// Gets a performance report.
        /// </summary>
        public Dictionary<string, PerformanceReport> GetPerformanceReport()
        {
            var report = new Dictionary<string, PerformanceReport>();

            foreach (var kvp in _metrics)
            {
                report[kvp.Key] = kvp.Value.GetReport();
            }

            return report;
        }

        /// <summary>
        /// Gets a formatted performance report.
        /// </summary>
        public string GetFormattedReport()
        {
            var report = new System.Text.StringBuilder();

            report.AppendLine("=== Chunk Threading Performance Report ===");
            report.AppendLine($"Generated: {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC");
            report.AppendLine();

            var metrics = _metrics.OrderBy(m => m.Key).ToList();
            foreach (var kvp in metrics)
            {
                var metricReport = kvp.Value.GetReport();
                report.AppendLine($"{kvp.Key}:");
                report.AppendLine($"  Current: {metricReport.Current:F3}");
                report.AppendLine($"  Average: {metricReport.Average:F3}");
                report.AppendLine($"  Min: {metricReport.Min:F3}");
                report.AppendLine($"  Max: {metricReport.Max:F3}");
                report.AppendLine();
            }

            return report.ToString();
        }

        /// <summary>
        /// Disposes resources.
        /// </summary>
        public void Dispose()
        {
            Stop();
            _samplingTimer.Dispose();
        }

        /// <summary>
        /// Represents a performance metric with history.
        /// </summary>
        private class PerformanceMetric
        {
            private readonly Queue<double> _samples;
            private readonly int _maxSamples;

            public PerformanceMetric(int maxSamples)
            {
                _maxSamples = maxSamples;
                _samples = new Queue<double>(maxSamples);
            }

            public void AddSample(double value)
            {
                lock (_samples)
                {
                    _samples.Enqueue(value);

                    while (_samples.Count > _maxSamples)
                    {
                        _samples.Dequeue();
                    }
                }
            }

            public PerformanceReport GetReport()
            {
                lock (_samples)
                {
                    if (_samples.Count == 0)
                    {
                        return new PerformanceReport(0, 0, 0, 0, Array.Empty<double>());
                    }

                    var samplesArray = _samples.ToArray();
                    return new PerformanceReport(
                        samplesArray.Last(),
                        samplesArray.Average(),
                        samplesArray.Min(),
                        samplesArray.Max(),
                        samplesArray
                    );
                }
            }
        }

        /// <summary>
        /// Represents a performance report.
        /// </summary>
        public class PerformanceReport
        {
            /// <summary>
            /// The current value.
            /// </summary>
            public double Current { get; }

            /// <summary>
            /// The average value.
            /// </summary>
            public double Average { get; }

            /// <summary>
            /// The minimum value.
            /// </summary>
            public double Min { get; }

            /// <summary>
            /// The maximum value.
            /// </summary>
            public double Max { get; }

            /// <summary>
            /// The history of values.
            /// </summary>
            public double[] History { get; }

            /// <summary>
            /// 
            /// </summary>
            /// <param name="current"></param>
            /// <param name="average"></param>
            /// <param name="min"></param>
            /// <param name="max"></param>
            /// <param name="history"></param>
            public PerformanceReport(double current, double average, double min, double max, double[] history)
            {
                Current = current;
                Average = average;
                Min = min;
                Max = max;
                History = history;
            }
        }
    }
}