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


namespace AdvChkSys.Threading
{
    /// <summary>
    /// Provides diagnostic information about threading operations in the chunk system.
    /// </summary>
    public static class ChunkThreadingDiagnostics
    {
        // Track operation durations
        private static readonly ConcurrentDictionary<string, List<long>> _operationDurations = new();

        // Track lock contention
        private static readonly ConcurrentDictionary<IChunk, int> _lockContentionCount = new();

        // Track active operations
        private static readonly ConcurrentDictionary<Guid, (string Operation, DateTime StartTime, IChunk Chunk)> _activeOperations = new();

        // Lock for thread safety
        private static readonly object _lock = new();

        // Stopwatch for timing
        private static readonly Stopwatch _stopwatch = Stopwatch.StartNew();

        /// <summary>
        /// Tracks the duration of an operation.
        /// </summary>
        /// <param name="operationName">The name of the operation</param>
        /// <param name="action">The action to perform</param>
        public static void TrackOperation(string operationName, Action action)
        {
            _ = Guid.NewGuid();
            var startTime = _stopwatch.ElapsedMilliseconds;

            try
            {
                action();
            }
            finally
            {
                var duration = _stopwatch.ElapsedMilliseconds - startTime;

                lock (_lock)
                {
                    if (!_operationDurations.TryGetValue(operationName, out var durations))
                    {
                        durations = new List<long>();
                        _operationDurations[operationName] = durations;
                    }

                    durations.Add(duration);

                    // Keep only the last 1000 durations
                    if (durations.Count > 1000)
                    {
                        durations.RemoveAt(0);
                    }
                }
            }
        }

        /// <summary>
        /// Tracks the start of an operation on a chunk.
        /// </summary>
        /// <param name="operationName">The name of the operation</param>
        /// <param name="chunk">The chunk being operated on</param>
        /// <returns>An operation ID for tracking</returns>
        public static Guid TrackOperationStart(string operationName, IChunk chunk)
        {
            var operationId = Guid.NewGuid();
            _activeOperations[operationId] = (operationName, DateTime.UtcNow, chunk);
            return operationId;
        }

        /// <summary>
        /// Tracks the end of an operation.
        /// </summary>
        /// <param name="operationId">The operation ID from TrackOperationStart</param>
        public static void TrackOperationEnd(Guid operationId)
        {
            if (_activeOperations.TryRemove(operationId, out var info))
            {
                var duration = (DateTime.UtcNow - info.StartTime).TotalMilliseconds;

                lock (_lock)
                {
                    if (!_operationDurations.TryGetValue(info.Operation, out var durations))
                    {
                        durations = new List<long>();
                        _operationDurations[info.Operation] = durations;
                    }

                    durations.Add((long)duration);

                    // Keep only the last 1000 durations
                    if (durations.Count > 1000)
                    {
                        durations.RemoveAt(0);
                    }
                }
            }
        }

        /// <summary>
        /// Tracks lock contention on a chunk.
        /// </summary>
        /// <param name="chunk">The chunk that had lock contention</param>
        public static void TrackLockContention(IChunk chunk)
        {
            _lockContentionCount.AddOrUpdate(chunk, 1, (_, count) => count + 1);
        }

        /// <summary>
        /// Gets statistics about operation durations.
        /// </summary>
        public static Dictionary<string, (long Min, long Max, double Average, int Count)> GetOperationStatistics()
        {
            var result = new Dictionary<string, (long Min, long Max, double Average, int Count)>();

            lock (_lock)
            {
                foreach (var kvp in _operationDurations)
                {
                    var durations = kvp.Value;
                    if (durations.Count > 0)
                    {
                        result[kvp.Key] = (
                            durations.Min(),
                            durations.Max(),
                            durations.Average(),
                            durations.Count
                        );
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// Gets the chunks with the most lock contention.
        /// </summary>
        /// <param name="topCount">Number of chunks to return</param>
        public static List<(IChunk Chunk, int ContentionCount)> GetTopContentionChunks(int topCount = 10)
        {
            return _lockContentionCount
                .OrderByDescending(kvp => kvp.Value)
                .Take(topCount)
                .Select(kvp => (kvp.Key, kvp.Value))
                .ToList();
        }

        /// <summary>
        /// Gets information about currently active operations.
        /// </summary>
        public static List<(string Operation, TimeSpan Duration, IChunk Chunk)> GetActiveOperations()
        {
            var now = DateTime.UtcNow;
            return _activeOperations
                .Select(kvp => (
                    kvp.Value.Operation,
                    now - kvp.Value.StartTime,
                    kvp.Value.Chunk
                ))
                .OrderByDescending(x => x.Item2)
                .ToList();
        }

        /// <summary>
        /// Gets the total number of tracked operations.
        /// </summary>
        public static int GetTotalOperationCount()
        {
            lock (_lock)
            {
                return _operationDurations.Values.Sum(list => list.Count);
            }
        }

        /// <summary>
        /// Gets the number of active operations.
        /// </summary>
        public static int GetActiveOperationCount()
        {
            return _activeOperations.Count;
        }

        /// <summary>
        /// Gets the total number of lock contentions.
        /// </summary>
        public static int GetTotalLockContentionCount()
        {
            return _lockContentionCount.Values.Sum();
        }

        /// <summary>
        /// Clears all diagnostic data.
        /// </summary>
        public static void ClearDiagnosticData()
        {
            lock (_lock)
            {
                _operationDurations.Clear();
                _lockContentionCount.Clear();
                // Don't clear active operations as they're still in progress
            }
        }

        /// <summary>
        /// Gets a comprehensive diagnostic report.
        /// </summary>
        public static string GenerateDiagnosticReport()
        {
            var report = new System.Text.StringBuilder();

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

            // Operation statistics
            report.AppendLine("== Operation Statistics ==");
            var stats = GetOperationStatistics();
            foreach (var kvp in stats.OrderByDescending(s => s.Value.Average))
            {
                report.AppendLine($"{kvp.Key}:");
                report.AppendLine($"  Count: {kvp.Value.Count}");
                report.AppendLine($"  Min: {kvp.Value.Min}ms");
                report.AppendLine($"  Max: {kvp.Value.Max}ms");
                report.AppendLine($"  Avg: {kvp.Value.Average:F2}ms");
            }
            report.AppendLine();

            // Lock contention
            report.AppendLine("== Lock Contention ==");
            var contentions = GetTopContentionChunks(10);
            foreach (var (chunk, count) in contentions)
            {
                report.AppendLine($"Chunk ({chunk.X}, {chunk.Y}): {count} contentions");
            }
            report.AppendLine($"Total contentions: {GetTotalLockContentionCount()}");
            report.AppendLine();

            // Active operations
            report.AppendLine("== Active Operations ==");
            var activeOps = GetActiveOperations();
            foreach (var (operation, duration, chunk) in activeOps)
            {
                report.AppendLine($"{operation} on Chunk ({chunk.X}, {chunk.Y}): {duration.TotalMilliseconds:F2}ms");
            }
            report.AppendLine($"Total active operations: {GetActiveOperationCount()}");

            return report.ToString();
        }

        /// <summary>
        /// Logs a diagnostic event.
        /// </summary>
        /// <param name="eventName">The name of the event</param>
        /// <param name="details">Additional details</param>
        public static void LogEvent(string eventName, string details)
        {
            // This could be expanded to log to a file or other destination
            Debug.WriteLine($"[{DateTime.UtcNow:HH:mm:ss.fff}] {eventName}: {details}");
        }
    }
}