using System.Diagnostics;

namespace NexusShell.Services.Diagnostics;

public sealed class PerformanceMonitorService : IDisposable
{
    private readonly SystemStatusService _systemStatus;
    private readonly DiagnosticsService _diagnostics;
    private readonly Timer _sampleTimer;
    private readonly NexusTimerRegistration _timerRegistration;
    private readonly object _metricsLock = new();
    private long _uiLatencyMs;
    private long _apiLatencyMs;
    private int _uiLatencySamples;
    private int _apiLatencySamples;
    private int _lastCpuPercent;
    private int _lastMemoryPercent;
    private bool _enabled = true;
    private bool _performanceMode;

    public PerformanceMonitorService(SystemStatusService systemStatus, DiagnosticsService diagnostics)
    {
        _systemStatus = systemStatus;
        _diagnostics = diagnostics;
        _sampleTimer = new Timer(static state => ((PerformanceMonitorService)state!).SampleTick(), this,
            TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5));
        _timerRegistration = NexusTimerRegistry.Register(
            "performance-sampler",
            nameof(PerformanceMonitorService),
            TimeSpan.FromSeconds(5),
            uiThread: false,
            "CPU/RAM/UI/API latency sampler");
    }

    public bool PerformanceMode
    {
        get => _performanceMode;
        set
        {
            _performanceMode = value;
            var interval = SampleInterval;
            _sampleTimer.Change(interval, interval);
            _timerRegistration.UpdateInterval(interval);
            _diagnostics.LogPerformance("performance_mode_changed", value ? "Performance mode aktiveret" : "Performance mode deaktiveret");
        }
    }

    public int CpuPercent => _lastCpuPercent;
    public int MemoryPercent => _lastMemoryPercent;
    public long AverageUiLatencyMs => _uiLatencySamples == 0 ? 0 : _uiLatencyMs / _uiLatencySamples;
    public long AverageApiLatencyMs => _apiLatencySamples == 0 ? 0 : _apiLatencyMs / _apiLatencySamples;
    public TimeSpan SampleInterval => _performanceMode ? TimeSpan.FromSeconds(10) : TimeSpan.FromSeconds(5);

    public void SetEnabled(bool enabled)
    {
        _enabled = enabled;
        var interval = enabled ? SampleInterval : Timeout.InfiniteTimeSpan;
        _sampleTimer.Change(interval, interval);
        _timerRegistration.UpdateInterval(enabled ? SampleInterval : TimeSpan.Zero);
    }

    public void RecordUiLatency(long milliseconds)
    {
        if (!_enabled)
        {
            return;
        }

        lock (_metricsLock)
        {
            _uiLatencyMs += milliseconds;
            _uiLatencySamples++;
        }

        if (milliseconds > 120)
        {
            _diagnostics.LogPerformance("ui_latency_warning",
                $"UI-tråd forsinkelse: {milliseconds} ms",
                new Dictionary<string, string> { ["latencyMs"] = milliseconds.ToString() });
        }
    }

    public async Task<T> TrackApiCallAsync<T>(string operation, Func<Task<T>> action)
    {
        var sw = Stopwatch.StartNew();
        try
        {
            return await action();
        }
        finally
        {
            sw.Stop();
            RecordApiLatency(operation, sw.ElapsedMilliseconds);
        }
    }

    public void RecordApiLatency(string operation, long milliseconds)
    {
        if (!_enabled)
        {
            return;
        }

        lock (_metricsLock)
        {
            _apiLatencyMs += milliseconds;
            _apiLatencySamples++;
        }

        _diagnostics.LogApi(operation, $"{milliseconds} ms", milliseconds);
    }

    private void SampleTick()
    {
        if (!_enabled)
        {
            return;
        }

        try
        {
            var snapshot = _systemStatus.Capture();
            _lastCpuPercent = snapshot.CpuPercent;
            _lastMemoryPercent = snapshot.MemoryLoadPercent;

            _diagnostics.LogPerformance("resource_sample",
                $"CPU {snapshot.CpuPercent}% · RAM {snapshot.MemoryLoadPercent}%",
                new Dictionary<string, string>
                {
                    ["cpuPercent"] = snapshot.CpuPercent.ToString(),
                    ["memoryPercent"] = snapshot.MemoryLoadPercent.ToString(),
                    ["uiLatencyMs"] = AverageUiLatencyMs.ToString(),
                    ["apiLatencyMs"] = AverageApiLatencyMs.ToString(),
                });

            if (snapshot.CpuPercent > 85 || snapshot.MemoryLoadPercent > 90)
            {
                _diagnostics.LogPerformance("resource_pressure",
                    "Høj ressourcebelastning registreret",
                    new Dictionary<string, string>
                    {
                        ["cpuPercent"] = snapshot.CpuPercent.ToString(),
                        ["memoryPercent"] = snapshot.MemoryLoadPercent.ToString(),
                    });
            }
        }
        catch (Exception ex)
        {
            _diagnostics.LogError("performance_sample_failed", ex.Message);
        }
    }

    public void Dispose()
    {
        _timerRegistration.Dispose();
        _sampleTimer.Dispose();
    }
}
