using System.Collections.Concurrent;

namespace ZB.MOM.WW.LmxProxy.Client;

public partial class LmxProxyClient
{
    /// <summary>
    /// Tracks per-operation counts, errors, and latency with rolling buffer and percentile support.
    /// </summary>
    internal class ClientMetrics
    {
        private readonly ConcurrentDictionary<string, long> _operationCounts = new();
        private readonly ConcurrentDictionary<string, long> _errorCounts = new();
        private readonly ConcurrentDictionary<string, List<long>> _latencies = new();
        private readonly Lock _latencyLock = new();

        public void IncrementOperationCount(string operation)
        {
            _operationCounts.AddOrUpdate(operation, 1, (_, count) => count + 1);
        }

        public void IncrementErrorCount(string operation)
        {
            _errorCounts.AddOrUpdate(operation, 1, (_, count) => count + 1);
        }

        public void RecordLatency(string operation, long milliseconds)
        {
            lock (_latencyLock)
            {
                if (!_latencies.TryGetValue(operation, out var list))
                {
                    list = [];
                    _latencies[operation] = list;
                }
                list.Add(milliseconds);
                if (list.Count > 1000)
                {
                    list.RemoveAt(0);
                }
            }
        }

        public Dictionary<string, object> GetSnapshot()
        {
            var snapshot = new Dictionary<string, object>();

            foreach (var kvp in _operationCounts)
            {
                snapshot[$"{kvp.Key}_count"] = kvp.Value;
            }

            foreach (var kvp in _errorCounts)
            {
                snapshot[$"{kvp.Key}_errors"] = kvp.Value;
            }

            lock (_latencyLock)
            {
                foreach (var kvp in _latencies)
                {
                    var values = kvp.Value;
                    if (values.Count == 0) continue;

                    double avg = values.Average();
                    snapshot[$"{kvp.Key}_avg_latency_ms"] = Math.Round(avg, 2);
                    snapshot[$"{kvp.Key}_p95_latency_ms"] = GetPercentile(values, 95);
                    snapshot[$"{kvp.Key}_p99_latency_ms"] = GetPercentile(values, 99);
                }
            }

            return snapshot;
        }

        private static long GetPercentile(List<long> values, int percentile)
        {
            var sorted = values.OrderBy(v => v).ToList();
            int index = Math.Max(0, (int)Math.Ceiling(percentile / 100.0 * sorted.Count) - 1);
            return sorted[index];
        }
    }
}
