using Microsoft.Extensions.Options;
using System.Diagnostics;
using System.Runtime;

namespace QRRapidoApp.Services.Monitoring
{
    public class ResourceMonitoringService : BackgroundService
    {
        private readonly ILogger<ResourceMonitoringService> _logger;
        private readonly IConfiguration _configuration;
        private readonly string _applicationName;
        
        // Configuration values
        private readonly int _intervalSeconds;
        private readonly double _cpuThresholdPercent;
        private readonly long _memoryThresholdMB;
        private readonly int _consecutiveAlertsBeforeError;
        private readonly int _gcCollectionThreshold;
        
        // Monitoring state
        private int _consecutiveHighCpuAlerts = 0;
        private int _consecutiveHighMemoryAlerts = 0;
        private readonly Dictionary<int, long> _previousGcCounts = new();
        private DateTime _lastMeasurement = DateTime.UtcNow;
        private double _previousCpuTime = 0;
        
        public ResourceMonitoringService(
            ILogger<ResourceMonitoringService> logger, 
            IConfiguration configuration)
        {
            _logger = logger;
            _configuration = configuration;
            _applicationName = configuration["ApplicationName"] ?? "QRRapido";
            
            // Load configuration
            _intervalSeconds = configuration.GetValue<int>("ResourceMonitoring:IntervalSeconds", 30);
            _cpuThresholdPercent = configuration.GetValue<double>("ResourceMonitoring:CpuThresholdPercent", 80.0);
            _memoryThresholdMB = configuration.GetValue<long>("ResourceMonitoring:MemoryThresholdMB", 512);
            _consecutiveAlertsBeforeError = configuration.GetValue<int>("ResourceMonitoring:ConsecutiveAlertsBeforeError", 4);
            _gcCollectionThreshold = configuration.GetValue<int>("ResourceMonitoring:GcCollectionThreshold", 10);
            
            _logger.LogInformation("ResourceMonitoringService initialized for {ApplicationName} - Interval: {IntervalSeconds}s, CPU Threshold: {CpuThreshold}%, Memory Threshold: {MemoryThreshold}MB",
                _applicationName, _intervalSeconds, _cpuThresholdPercent, _memoryThresholdMB);
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation("ResourceMonitoringService started for {ApplicationName}", _applicationName);
            
            while (!stoppingToken.IsCancellationRequested)
            {
                try
                {
                    await MonitorResourcesAsync();
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error in ResourceMonitoringService for {ApplicationName}", _applicationName);
                }
                
                await Task.Delay(TimeSpan.FromSeconds(_intervalSeconds), stoppingToken);
            }
            
            _logger.LogInformation("ResourceMonitoringService stopped for {ApplicationName}", _applicationName);
        }

        private async Task MonitorResourcesAsync()
        {
            var currentProcess = Process.GetCurrentProcess();
            var now = DateTime.UtcNow;
            
            // CPU Usage calculation
            var currentCpuTime = currentProcess.TotalProcessorTime.TotalMilliseconds;
            var elapsedTime = (now - _lastMeasurement).TotalMilliseconds;
            var cpuUsagePercent = 0.0;
            
            if (_previousCpuTime > 0 && elapsedTime > 0)
            {
                var cpuTimeDelta = currentCpuTime - _previousCpuTime;
                var coreCount = Environment.ProcessorCount;
                cpuUsagePercent = (cpuTimeDelta / (elapsedTime * coreCount)) * 100;
            }
            
            _previousCpuTime = currentCpuTime;
            _lastMeasurement = now;

            // Memory Usage
            var workingSetMB = currentProcess.WorkingSet64 / (1024 * 1024);
            var privateMemoryMB = currentProcess.PrivateMemorySize64 / (1024 * 1024);
            var virtualMemoryMB = currentProcess.VirtualMemorySize64 / (1024 * 1024);
            
            // GC Statistics
            var gen0Collections = GC.CollectionCount(0);
            var gen1Collections = GC.CollectionCount(1);
            var gen2Collections = GC.CollectionCount(2);
            var totalMemoryMB = GC.GetTotalMemory(false) / (1024 * 1024);
            
            // Calculate GC pressure (collections since last measurement)
            var gen0Pressure = CalculateGcPressure(0, gen0Collections);
            var gen1Pressure = CalculateGcPressure(1, gen1Collections);
            var gen2Pressure = CalculateGcPressure(2, gen2Collections);
            var totalGcPressure = gen0Pressure + gen1Pressure + gen2Pressure;
            
            // Thread and Handle counts
            var threadCount = currentProcess.Threads.Count;
            var handleCount = currentProcess.HandleCount;
            
            // Determine status and log level
            var status = DetermineResourceStatus(cpuUsagePercent, workingSetMB, totalGcPressure);
            
            // Log structured resource metrics
            using (_logger.BeginScope(new Dictionary<string, object>
            {
                ["ApplicationName"] = _applicationName,
                ["ResourceMonitoring"] = true,
                ["CpuUsagePercent"] = Math.Round(cpuUsagePercent, 2),
                ["WorkingSetMB"] = workingSetMB,
                ["PrivateMemoryMB"] = privateMemoryMB,
                ["VirtualMemoryMB"] = virtualMemoryMB,
                ["GcTotalMemoryMB"] = totalMemoryMB,
                ["Gen0Collections"] = gen0Collections,
                ["Gen1Collections"] = gen1Collections,
                ["Gen2Collections"] = gen2Collections,
                ["GcPressure"] = totalGcPressure,
                ["ThreadCount"] = threadCount,
                ["HandleCount"] = handleCount,
                ["ProcessId"] = currentProcess.Id,
                ["Uptime"] = (DateTime.UtcNow - Process.GetCurrentProcess().StartTime).ToString(@"dd\.hh\:mm\:ss"),
                ["Status"] = status
            }))
            {
                var logLevel = status switch
                {
                    "Critical" => LogLevel.Error,
                    "Warning" => LogLevel.Warning,
                    _ => LogLevel.Information
                };

                _logger.Log(logLevel, 
                    "Resource monitoring - CPU: {CpuUsage:F1}%, Memory: {Memory}MB, GC Pressure: {GcPressure}, Threads: {Threads}, Status: {Status}",
                    cpuUsagePercent, workingSetMB, totalGcPressure, threadCount, status);
            }
            
            // Check for alerts
            await CheckResourceAlertsAsync(cpuUsagePercent, workingSetMB, totalGcPressure);
        }

        private long CalculateGcPressure(int generation, long currentCount)
        {
            if (!_previousGcCounts.ContainsKey(generation))
            {
                _previousGcCounts[generation] = currentCount;
                return 0;
            }
            
            var pressure = currentCount - _previousGcCounts[generation];
            _previousGcCounts[generation] = currentCount;
            return pressure;
        }

        private string DetermineResourceStatus(double cpuUsage, long memoryMB, long gcPressure)
        {
            if (cpuUsage > _cpuThresholdPercent * 1.2 || 
                memoryMB > _memoryThresholdMB * 1.5 || 
                gcPressure > _gcCollectionThreshold * 2)
            {
                return "Critical";
            }
            
            if (cpuUsage > _cpuThresholdPercent || 
                memoryMB > _memoryThresholdMB || 
                gcPressure > _gcCollectionThreshold)
            {
                return "Warning";
            }
            
            return "Healthy";
        }

        private async Task CheckResourceAlertsAsync(double cpuUsage, long memoryMB, long gcPressure)
        {
            // CPU Alert Logic
            if (cpuUsage > _cpuThresholdPercent)
            {
                _consecutiveHighCpuAlerts++;
                
                if (_consecutiveHighCpuAlerts >= _consecutiveAlertsBeforeError)
                {
                    _logger.LogError("ALERT: High CPU usage detected for {ApplicationName} - {CpuUsage:F1}% for {ConsecutiveAlerts} consecutive measurements (threshold: {Threshold}%)",
                        _applicationName, cpuUsage, _consecutiveHighCpuAlerts, _cpuThresholdPercent);
                }
                else
                {
                    _logger.LogWarning("High CPU usage detected for {ApplicationName} - {CpuUsage:F1}% (threshold: {Threshold}%) - Alert {Current}/{Required}",
                        _applicationName, cpuUsage, _cpuThresholdPercent, _consecutiveHighCpuAlerts, _consecutiveAlertsBeforeError);
                }
            }
            else
            {
                if (_consecutiveHighCpuAlerts > 0)
                {
                    _logger.LogInformation("CPU usage normalized for {ApplicationName} - {CpuUsage:F1}% (was high for {PreviousAlerts} measurements)",
                        _applicationName, cpuUsage, _consecutiveHighCpuAlerts);
                }
                _consecutiveHighCpuAlerts = 0;
            }

            // Memory Alert Logic
            if (memoryMB > _memoryThresholdMB)
            {
                _consecutiveHighMemoryAlerts++;
                
                if (_consecutiveHighMemoryAlerts >= _consecutiveAlertsBeforeError)
                {
                    _logger.LogError("ALERT: High memory usage detected for {ApplicationName} - {MemoryMB}MB for {ConsecutiveAlerts} consecutive measurements (threshold: {Threshold}MB)",
                        _applicationName, memoryMB, _consecutiveHighMemoryAlerts, _memoryThresholdMB);
                        
                    // Suggest GC collection on persistent high memory
                    if (_consecutiveHighMemoryAlerts > _consecutiveAlertsBeforeError * 2)
                    {
                        _logger.LogWarning("Forcing garbage collection due to persistent high memory usage for {ApplicationName}", _applicationName);
                        GC.Collect();
                        GC.WaitForPendingFinalizers();
                        GC.Collect();
                    }
                }
                else
                {
                    _logger.LogWarning("High memory usage detected for {ApplicationName} - {MemoryMB}MB (threshold: {Threshold}MB) - Alert {Current}/{Required}",
                        _applicationName, memoryMB, _memoryThresholdMB, _consecutiveHighMemoryAlerts, _consecutiveAlertsBeforeError);
                }
            }
            else
            {
                if (_consecutiveHighMemoryAlerts > 0)
                {
                    _logger.LogInformation("Memory usage normalized for {ApplicationName} - {MemoryMB}MB (was high for {PreviousAlerts} measurements)",
                        _applicationName, memoryMB, _consecutiveHighMemoryAlerts);
                }
                _consecutiveHighMemoryAlerts = 0;
            }

            // GC Pressure Alert
            if (gcPressure > _gcCollectionThreshold)
            {
                _logger.LogWarning("High GC pressure detected for {ApplicationName} - {GcPressure} collections in last interval (threshold: {Threshold})",
                    _applicationName, gcPressure, _gcCollectionThreshold);
            }
        }
    }
}