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

namespace EonaCat.LogStack.PerformanceInsights
{
    /// <summary>
    /// Collects performance insights from multiple flows and operations.
    /// Detects bottlenecks and provides recommendations.
    /// </summary>
    public sealed class PerformanceInsightsCollector
    {
        private readonly ConcurrentDictionary<string, PerformanceTracker> _trackers = new();
        private long _totalOperations;
        private long _totalErrors;
        private DateTime _startTime = DateTime.UtcNow;

        /// <summary>
        /// Gets or creates a tracker for the given name
        /// </summary>
        public PerformanceTracker GetOrCreateTracker(string name)
        {
            return _trackers.GetOrAdd(name, _ => new PerformanceTracker(name));
        }

        /// <summary>
        /// Gets a tracker if it exists
        /// </summary>
        public PerformanceTracker? GetTracker(string name)
        {
            return _trackers.TryGetValue(name, out var tracker) ? tracker : null;
        }

        /// <summary>
        /// Records an operation
        /// </summary>
        public void RecordOperation(string name, long durationTicks, long byteCount = 0, bool isError = false)
        {
            var tracker = GetOrCreateTracker(name);
            tracker.RecordOperation(durationTicks, byteCount, isError);

            _totalOperations++;
            if (isError) _totalErrors++;
        }

        /// <summary>
        /// Gets all current trackers
        /// </summary>
        public IReadOnlyCollection<PerformanceTracker> GetAllTrackers()
        {
            return _trackers.Values.ToList().AsReadOnly();
        }

        /// <summary>
        /// Gets current insights snapshot
        /// </summary>
        public PerformanceInsightsSnapshot GetSnapshot()
        {
            var uptime = DateTime.UtcNow - _startTime;
            var metrics = _trackers.Values.Select(t => t.GetMetrics()).ToList();

            var slowestOps = metrics
                .OrderByDescending(m => m.AverageDurationMs)
                .Take(5)
                .ToList();

            var mostErrors = metrics
                .OrderByDescending(m => m.ErrorCount)
                .Take(5)
                .ToList();

            var topThroughput = metrics
                .OrderByDescending(m => m.ThroughputOpsPerSec)
                .Take(5)
                .ToList();

            return new PerformanceInsightsSnapshot
            {
                Uptime = uptime,
                TotalOperations = _totalOperations,
                TotalErrors = _totalErrors,
                ErrorRatePercent = _totalOperations > 0 ? (_totalErrors * 100.0) / _totalOperations : 0,
                AllMetrics = metrics,
                SlowestOperations = slowestOps,
                MostErrorsOperations = mostErrors,
                HighestThroughputOperations = topThroughput,
                CapturedAt = DateTime.UtcNow
            };
        }

        /// <summary>
        /// Gets performance recommendations based on current metrics
        /// </summary>
        public List<PerformanceRecommendation> GetRecommendations()
        {
            var recommendations = new List<PerformanceRecommendation>();
            var snapshot = GetSnapshot();

            // Check for high error rates
            if (snapshot.ErrorRatePercent > 5)
            {
                recommendations.Add(new PerformanceRecommendation
                {
                    Category = "ErrorRate",
                    Severity = Severity.High,
                    Message = $"Error rate is {snapshot.ErrorRatePercent:F2}%. Consider investigating error causes.",
                    AffectedOperations = snapshot.MostErrorsOperations.Select(m => m.Name).ToList()
                });
            }

            // Check for slow operations
            var verySlowOps = snapshot.AllMetrics
                .Where(m => m.AverageDurationMs > 1000)
                .ToList();

            if (verySlowOps.Any())
            {
                recommendations.Add(new PerformanceRecommendation
                {
                    Category = "SlowOperations",
                    Severity = Severity.Medium,
                    Message = "Some operations are very slow (>1000ms avg). Consider optimization or async batching.",
                    AffectedOperations = verySlowOps.Select(m => m.Name).ToList()
                });
            }

            // Check for high variance
            var highVarianceOps = snapshot.AllMetrics
                .Where(m => m.MaxDurationMs > m.AverageDurationMs * 10)
                .ToList();

            if (highVarianceOps.Any())
            {
                recommendations.Add(new PerformanceRecommendation
                {
                    Category = "HighVariance",
                    Severity = Severity.Low,
                    Message = "High variance detected in operation times. May indicate GC pauses or resource contention.",
                    AffectedOperations = highVarianceOps.Select(m => m.Name).ToList()
                });
            }

            return recommendations;
        }

        /// <summary>
        /// Resets all trackers
        /// </summary>
        public void Reset()
        {
            foreach (var tracker in _trackers.Values)
            {
                tracker.Reset();
            }
            _totalOperations = 0;
            _totalErrors = 0;
            _startTime = DateTime.UtcNow;
        }
    }

    /// <summary>
    /// Snapshot of performance insights
    /// </summary>
    public sealed class PerformanceInsightsSnapshot
    {
        public TimeSpan Uptime { get; set; }
        public long TotalOperations { get; set; }
        public long TotalErrors { get; set; }
        public double ErrorRatePercent { get; set; }
        public List<PerformanceMetrics> AllMetrics { get; set; } = new();
        public List<PerformanceMetrics> SlowestOperations { get; set; } = new();
        public List<PerformanceMetrics> MostErrorsOperations { get; set; } = new();
        public List<PerformanceMetrics> HighestThroughputOperations { get; set; } = new();
        public DateTime CapturedAt { get; set; }
    }

    /// <summary>
    /// Performance recommendation
    /// </summary>
    public sealed class PerformanceRecommendation
    {
        public string Category { get; set; }
        public Severity Severity { get; set; }
        public string Message { get; set; }
        public List<string> AffectedOperations { get; set; } = new();
    }

    /// <summary>
    /// Severity level
    /// </summary>
    public enum Severity
    {
        Low,
        Medium,
        High,
        Critical
    }
}
