using EonaCat.LogStack.Analytics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace EonaCat.LogStack;

// 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>
/// Advanced metrics collector that provides comprehensive analytics across loggers
/// </summary>
public sealed class AdvancedMetricsCollector
{
    private readonly List<EonaCatLogStack> _loggers = new();
    private readonly object _lock = new();

    /// <summary>
    /// Registers a logger for metrics collection
    /// </summary>
    public void RegisterLogger(EonaCatLogStack logger)
    {
        if (logger != null)
        {
            lock (_lock)
            {
                if (!_loggers.Contains(logger))
                {
                    _loggers.Add(logger);
                }
            }
        }
    }

    /// <summary>
    /// Unregisters a logger
    /// </summary>
    public void UnregisterLogger(EonaCatLogStack logger)
    {
        if (logger != null)
        {
            lock (_lock)
            {
                _loggers.Remove(logger);
            }
        }
    }

    /// <summary>
    /// Gets aggregated metrics across all registered loggers
    /// </summary>
    public AggregatedMetrics GetAggregatedMetrics()
    {
        lock (_lock)
        {
            var aggregated = new AggregatedMetrics
            {
                Timestamp = DateTime.UtcNow,
                LoggerMetrics = new List<LoggerMetrics>()
            };

            foreach (var logger in _loggers)
            {
                try
                {
                    var metrics = logger.GetMetrics();
                    aggregated.LoggerMetrics.Add(metrics);
                }
                catch { }
            }

            // Aggregate totals
            aggregated.TotalLoggedAcrossAll = aggregated.LoggerMetrics.Sum(m => m.TotalLogged);
            aggregated.TotalDroppedAcrossAll = aggregated.LoggerMetrics.Sum(m => m.TotalDropped);
            aggregated.TotalExceptionsAcrossAll = aggregated.LoggerMetrics.Sum(m => m.TotalExceptions);
            aggregated.TotalBytesAcrossAll = aggregated.LoggerMetrics.Sum(m => m.TotalBytes);
            aggregated.ActiveLoggers = _loggers.Count;

            return aggregated;
        }
    }

    /// <summary>
    /// Gets a performance comparison across loggers
    /// </summary>
    public PerformanceComparison GetPerformanceComparison()
    {
        var aggregated = GetAggregatedMetrics();

        return new PerformanceComparison
        {
            Timestamp = aggregated.Timestamp,
            TotalLoggers = aggregated.ActiveLoggers,
            HighestThroughputLogger = aggregated.LoggerMetrics.OrderByDescending(m => m.WritesPerSecond).FirstOrDefault(),
            LowestSuccessRateLogger = aggregated.LoggerMetrics.OrderBy(m => m.SuccessRate).FirstOrDefault(),
            AverageBytesPerEvent = aggregated.LoggerMetrics.Count > 0 
                ? aggregated.LoggerMetrics.Average(m => m.AverageBytesPerEvent)
                : 0,
            AverageWritesPerSecond = aggregated.LoggerMetrics.Count > 0
                ? aggregated.LoggerMetrics.Average(m => m.WritesPerSecond)
                : 0
        };
    }

    /// <summary>
    /// Gets a health report
    /// </summary>
    public HealthReport GetHealthReport()
    {
        var aggregated = GetAggregatedMetrics();

        var report = new HealthReport
        {
            Timestamp = aggregated.Timestamp,
            OverallStatus = "Healthy",
            Warnings = new List<string>(),
            Errors = new List<string>()
        };

        foreach (var logger in aggregated.LoggerMetrics)
        {
            if (logger.SuccessRate < 95)
            {
                report.Warnings.Add($"{logger.GetType().Name}: Low success rate ({logger.SuccessRate:F1}%)");
            }

            if (logger.TotalExceptions > logger.TotalLogged * 0.05) // More than 5% exceptions
            {
                report.Warnings.Add($"Logger: High exception rate ({logger.TotalExceptions} exceptions)");
            }
        }

        if (report.Warnings.Count > 0)
        {
            report.OverallStatus = "Warning";
        }

        if (report.Errors.Count > 0)
        {
            report.OverallStatus = "Error";
        }

        return report;
    }

    /// <summary>
    /// Resets all metrics
    /// </summary>
    public void Reset()
    {
        lock (_lock)
        {
            _loggers.Clear();
        }
    }
}

/// <summary>
/// Aggregated metrics across multiple loggers
/// </summary>
public sealed class AggregatedMetrics
{
    public DateTime Timestamp { get; set; }
    public List<LoggerMetrics> LoggerMetrics { get; set; } = new();
    public long TotalLoggedAcrossAll { get; set; }
    public long TotalDroppedAcrossAll { get; set; }
    public long TotalExceptionsAcrossAll { get; set; }
    public long TotalBytesAcrossAll { get; set; }
    public int ActiveLoggers { get; set; }

    public double OverallSuccessRate
    {
        get
        {
            var total = TotalLoggedAcrossAll + TotalDroppedAcrossAll;
            return total > 0 ? (TotalLoggedAcrossAll * 100.0) / total : 100;
        }
    }

    public override string ToString()
    {
        var sb = new StringBuilder();
        sb.AppendLine("===== AGGREGATED METRICS =====");
        sb.AppendLine($"Timestamp: {Timestamp:O}");
        sb.AppendLine($"Active Loggers: {ActiveLoggers}");
        sb.AppendLine($"Total Logged: {TotalLoggedAcrossAll:N0}");
        sb.AppendLine($"Total Dropped: {TotalDroppedAcrossAll:N0}");
        sb.AppendLine($"Overall Success Rate: {OverallSuccessRate:F2}%");
        sb.AppendLine($"Total Exceptions: {TotalExceptionsAcrossAll:N0}");
        sb.AppendLine($"Total Bytes: {TotalBytesAcrossAll:N0}");
        sb.AppendLine("==============================");
        return sb.ToString();
    }
}

/// <summary>
/// Performance comparison across loggers
/// </summary>
public sealed class PerformanceComparison
{
    public DateTime Timestamp { get; set; }
    public int TotalLoggers { get; set; }
    public LoggerMetrics HighestThroughputLogger { get; set; }
    public LoggerMetrics LowestSuccessRateLogger { get; set; }
    public double AverageBytesPerEvent { get; set; }
    public double AverageWritesPerSecond { get; set; }

    public override string ToString()
    {
        var sb = new StringBuilder();
        sb.AppendLine("===== PERFORMANCE COMPARISON =====");
        sb.AppendLine($"Timestamp: {Timestamp:O}");
        sb.AppendLine($"Total Loggers: {TotalLoggers}");
        sb.AppendLine($"Highest Throughput: {HighestThroughputLogger?.WritesPerSecond:F2} events/sec");
        sb.AppendLine($"Lowest Success Rate: {LowestSuccessRateLogger?.SuccessRate:F2}%");
        sb.AppendLine($"Average Bytes/Event: {AverageBytesPerEvent:F2}");
        sb.AppendLine($"Average Writes/Second: {AverageWritesPerSecond:F2}");
        sb.AppendLine("==================================");
        return sb.ToString();
    }
}

/// <summary>
/// Health report for logging system
/// </summary>
public sealed class HealthReport
{
    public DateTime Timestamp { get; set; }
    public string OverallStatus { get; set; } = "Unknown";
    public List<string> Warnings { get; set; } = new();
    public List<string> Errors { get; set; } = new();

    public override string ToString()
    {
        var sb = new StringBuilder();
        sb.AppendLine("===== HEALTH REPORT =====");
        sb.AppendLine($"Timestamp: {Timestamp:O}");
        sb.AppendLine($"Status: {OverallStatus}");

        if (Warnings.Count > 0)
        {
            sb.AppendLine("\nWarnings:");
            foreach (var warning in Warnings)
            {
                sb.AppendLine($"  - {warning}");
            }
        }

        if (Errors.Count > 0)
        {
            sb.AppendLine("\nErrors:");
            foreach (var error in Errors)
            {
                sb.AppendLine($"  - {error}");
            }
        }

        sb.AppendLine("========================");
        return sb.ToString();
    }
}
