using EonaCat.LogStack.Core;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace EonaCat.LogStack.Diagnostics;

// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.

/// <summary>
/// Comprehensive logging diagnostics and metrics collection
/// </summary>
public sealed class LoggerDiagnosticsCollector
{
    private readonly Stopwatch _uptime = Stopwatch.StartNew();
    private long _totalEventsProcessed;
    private long _totalEventsSampled;
    private long _totalEventsFiltered;
    private long _totalErrors;
    private DateTime _startTime = DateTime.UtcNow;
    private readonly object _lock = new object();

    private readonly Dictionary<string, FlowMetrics> _flowMetrics = new();
    private readonly Dictionary<string, BoosterMetrics> _boosterMetrics = new();
    private readonly Dictionary<LogLevel, long> _levelCounts = new();
    private readonly List<EventLatency> _recentLatencies = new();
    private const int MaxLatencyHistory = 1000;

    public LoggerDiagnosticsCollector()
    {
        foreach (LogLevel level in Enum.GetValues(typeof(LogLevel)))
        {
            _levelCounts[level] = 0;
        }
    }

    /// <summary>
    /// Records an event being processed
    /// </summary>
    public void RecordEventProcessed(LogEvent logEvent, long elapsedMilliseconds)
    {
        lock (_lock)
        {
            _totalEventsProcessed++;

            if (_levelCounts.ContainsKey(logEvent.Level))
            {
                _levelCounts[logEvent.Level]++;
            }

            // Track latency
            _recentLatencies.Add(new EventLatency
            {
                Level = logEvent.Level,
                ElapsedMs = elapsedMilliseconds,
                Timestamp = DateTime.UtcNow
            });

            if (_recentLatencies.Count > MaxLatencyHistory)
            {
                _recentLatencies.RemoveAt(0);
            }
        }
    }

    /// <summary>
    /// Records a sampled event
    /// </summary>
    public void RecordSampled()
    {
        lock (_lock)
        {
            _totalEventsSampled++;
        }
    }

    /// <summary>
    /// Records a filtered event
    /// </summary>
    public void RecordFiltered()
    {
        lock (_lock)
        {
            _totalEventsFiltered++;
        }
    }

    /// <summary>
    /// Records an error
    /// </summary>
    public void RecordError()
    {
        lock (_lock)
        {
            _totalErrors++;
        }
    }

    /// <summary>
    /// Records metrics for a flow
    /// </summary>
    public void RecordFlowMetrics(string flowName, int eventsProcessed, int eventsFailed, long bytesWritten)
    {
        lock (_lock)
        {
            if (!_flowMetrics.TryGetValue(flowName, out var metrics))
            {
                metrics = new FlowMetrics { Name = flowName };
                _flowMetrics[flowName] = metrics;
            }

            metrics.EventsProcessed += eventsProcessed;
            metrics.EventsFailed += eventsFailed;
            metrics.BytesWritten += bytesWritten;
            metrics.LastUpdated = DateTime.UtcNow;
        }
    }

    /// <summary>
    /// Records metrics for a booster
    /// </summary>
    public void RecordBoosterMetrics(string boosterName, int eventsProcessed, int eventsFiltered)
    {
        lock (_lock)
        {
            if (!_boosterMetrics.TryGetValue(boosterName, out var metrics))
            {
                metrics = new BoosterMetrics { Name = boosterName };
                _boosterMetrics[boosterName] = metrics;
            }

            metrics.EventsProcessed += eventsProcessed;
            metrics.EventsFiltered += eventsFiltered;
            metrics.LastUpdated = DateTime.UtcNow;
        }
    }

    /// <summary>
    /// Gets comprehensive diagnostics
    /// </summary>
    public DiagnosticsReport GetReport()
    {
        lock (_lock)
        {
            var latencies = _recentLatencies.Count > 0 ? _recentLatencies.ToList() : new List<EventLatency>();

            return new DiagnosticsReport
            {
                StartTime = _startTime,
                Uptime = _uptime.Elapsed,
                TotalEventsProcessed = _totalEventsProcessed,
                TotalEventsSampled = _totalEventsSampled,
                TotalEventsFiltered = _totalEventsFiltered,
                TotalErrors = _totalErrors,
                EventsByLevel = new Dictionary<LogLevel, long>(_levelCounts),
                FlowMetrics = _flowMetrics.Values.ToList(),
                BoosterMetrics = _boosterMetrics.Values.ToList(),
                RecentLatencies = latencies,
                MemoryUsage = GC.GetTotalMemory(false),
                ManagedThreadCount = System.Diagnostics.Process.GetCurrentProcess().Threads.Count
            };
        }
    }

    /// <summary>
    /// Gets a summary report
    /// </summary>
    public DiagnosticsSummary GetSummary()
    {
        var report = GetReport();

        double successRate = report.TotalEventsProcessed > 0
            ? ((report.TotalEventsProcessed - report.TotalErrors) * 100.0) / report.TotalEventsProcessed
            : 0.0;

        double samplingRate = report.TotalEventsProcessed > 0
            ? (report.TotalEventsSampled * 100.0) / report.TotalEventsProcessed
            : 0.0;

        var avgLatency = report.RecentLatencies.Count > 0
            ? report.RecentLatencies.Average(l => l.ElapsedMs)
            : 0.0;

        var maxLatency = report.RecentLatencies.Count > 0
            ? report.RecentLatencies.Max(l => l.ElapsedMs)
            : 0L;

        return new DiagnosticsSummary
        {
            Uptime = report.Uptime,
            TotalEvents = report.TotalEventsProcessed,
            SuccessRate = successRate,
            ErrorRate = 100.0 - successRate,
            SamplingRate = samplingRate,
            FilteringRate = report.TotalEventsFiltered > 0
                ? (report.TotalEventsFiltered * 100.0) / report.TotalEventsProcessed
                : 0.0,
            EventsPerSecond = report.Uptime.TotalSeconds > 0
                ? report.TotalEventsProcessed / report.Uptime.TotalSeconds
                : 0.0,
            AverageLatencyMs = avgLatency,
            MaxLatencyMs = maxLatency,
            MemoryUsageMb = report.MemoryUsage / (1024 * 1024.0),
            ThreadCount = report.ManagedThreadCount
        };
    }

    /// <summary>
    /// Generates a text report
    /// </summary>
    public string GenerateTextReport()
    {
        var summary = GetSummary();
        var report = GetReport();

        var sb = new StringBuilder();
        sb.AppendLine("╔══════════════════════════════════════════════════════════╗");
        sb.AppendLine("║         EonaCat.LogStack Diagnostics Report              ║");
        sb.AppendLine("╚══════════════════════════════════════════════════════════╝");
        sb.AppendLine();

        sb.AppendLine("📊 Overview");
        sb.AppendLine($"  Uptime:              {summary.Uptime:hh\\:mm\\:ss}");
        sb.AppendLine($"  Total Events:        {summary.TotalEvents:N0}");
        sb.AppendLine($"  Events/Second:       {summary.EventsPerSecond:F2}");
        sb.AppendLine();

        sb.AppendLine("📈 Quality Metrics");
        sb.AppendLine($"  Success Rate:        {summary.SuccessRate:F2}%");
        sb.AppendLine($"  Error Rate:          {summary.ErrorRate:F2}%");
        sb.AppendLine($"  Sampling Rate:       {summary.SamplingRate:F2}%");
        sb.AppendLine($"  Filtering Rate:      {summary.FilteringRate:F2}%");
        sb.AppendLine();

        sb.AppendLine("⚡ Performance");
        sb.AppendLine($"  Avg Latency:         {summary.AverageLatencyMs:F2}ms");
        sb.AppendLine($"  Max Latency:         {summary.MaxLatencyMs}ms");
        sb.AppendLine($"  Memory Usage:        {summary.MemoryUsageMb:F2}MB");
        sb.AppendLine($"  Threads:             {summary.ThreadCount}");
        sb.AppendLine();

        sb.AppendLine("📋 Events by Level");
        foreach (var kvp in report.EventsByLevel.OrderByDescending(x => x.Value))
        {
            sb.AppendLine($"  {kvp.Key,-12} {kvp.Value:N0}");
        }
        sb.AppendLine();

        if (report.FlowMetrics.Count > 0)
        {
            sb.AppendLine("🚀 Flow Metrics");
            foreach (var flow in report.FlowMetrics)
            {
                sb.AppendLine($"  {flow.Name}");
                sb.AppendLine($"    Processed:  {flow.EventsProcessed:N0}");
                sb.AppendLine($"    Failed:     {flow.EventsFailed}");
                sb.AppendLine($"    Bytes:      {flow.BytesWritten:N0}");
            }
            sb.AppendLine();
        }

        if (report.BoosterMetrics.Count > 0)
        {
            sb.AppendLine("⚙️  Booster Metrics");
            foreach (var booster in report.BoosterMetrics)
            {
                sb.AppendLine($"  {booster.Name}");
                sb.AppendLine($"    Processed: {booster.EventsProcessed:N0}");
                sb.AppendLine($"    Filtered:  {booster.EventsFiltered:N0}");
            }
            sb.AppendLine();
        }

        return sb.ToString();
    }
}

/// <summary>
/// Individual flow metrics
/// </summary>
public class FlowMetrics
{
    public string Name { get; set; } = "";
    public long EventsProcessed { get; set; }
    public long EventsFailed { get; set; }
    public long BytesWritten { get; set; }
    public DateTime LastUpdated { get; set; }
}

/// <summary>
/// Individual booster metrics
/// </summary>
public class BoosterMetrics
{
    public string Name { get; set; } = "";
    public long EventsProcessed { get; set; }
    public long EventsFiltered { get; set; }
    public DateTime LastUpdated { get; set; }
}

/// <summary>
/// Detailed diagnostics report
/// </summary>
public class DiagnosticsReport
{
    public DateTime StartTime { get; set; }
    public TimeSpan Uptime { get; set; }
    public long TotalEventsProcessed { get; set; }
    public long TotalEventsSampled { get; set; }
    public long TotalEventsFiltered { get; set; }
    public long TotalErrors { get; set; }
    public Dictionary<LogLevel, long> EventsByLevel { get; set; } = new();
    public List<FlowMetrics> FlowMetrics { get; set; } = new();
    public List<BoosterMetrics> BoosterMetrics { get; set; } = new();
    public List<EventLatency> RecentLatencies { get; set; } = new();
    public long MemoryUsage { get; set; }
    public int ManagedThreadCount { get; set; }
}

/// <summary>
/// Summary diagnostics
/// </summary>
public class DiagnosticsSummary
{
    public TimeSpan Uptime { get; set; }
    public long TotalEvents { get; set; }
    public double SuccessRate { get; set; }
    public double ErrorRate { get; set; }
    public double SamplingRate { get; set; }
    public double FilteringRate { get; set; }
    public double EventsPerSecond { get; set; }
    public double AverageLatencyMs { get; set; }
    public long MaxLatencyMs { get; set; }
    public double MemoryUsageMb { get; set; }
    public int ThreadCount { get; set; }
}

/// <summary>
/// Individual event latency record
/// </summary>
public class EventLatency
{
    public LogLevel Level { get; set; }
    public long ElapsedMs { get; set; }
    public DateTime Timestamp { get; set; }
}
