using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;

namespace ZB.MOM.WW.LmxProxy.Client
{
    /// <summary>
    /// Metrics collection for client operations
    /// </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 object _latencyLock = new();

        /// <summary>
        /// Increments the operation count for a specific operation.
        /// </summary>
        /// <param name="operation">The operation name.</param>
        public void IncrementOperationCount(string operation)
        {
            _operationCounts.AddOrUpdate(operation, 1, (_, oldValue) => oldValue + 1);
        }

        /// <summary>
        /// Increments the error count for a specific operation.
        /// </summary>
        /// <param name="operation">The operation name.</param>
        public void IncrementErrorCount(string operation)
        {
            _errorCounts.AddOrUpdate(operation, 1, (_, oldValue) => oldValue + 1);
        }

        /// <summary>
        /// Records latency for a specific operation.
        /// </summary>
        /// <param name="operation">The operation name.</param>
        /// <param name="milliseconds">The latency in milliseconds.</param>
        public void RecordLatency(string operation, long milliseconds)
        {
            lock (_latencyLock)
            {
                if (!_latencies.ContainsKey(operation))
                {
                    _latencies[operation] = [];
                }
                _latencies[operation].Add(milliseconds);

                // Keep only last 1000 entries to prevent memory growth
                if (_latencies[operation].Count > 1000)
                {
                    _latencies[operation].RemoveAt(0);
                }
            }
        }

        /// <summary>
        /// Gets a snapshot of current metrics.
        /// </summary>
        /// <returns>A dictionary containing metric data.</returns>
        public Dictionary<string, object> GetSnapshot()
        {
            var snapshot = new Dictionary<string, object>();

            foreach (KeyValuePair<string, long> kvp in _operationCounts)
            {
                snapshot[$"{kvp.Key}_count"] = kvp.Value;
            }

            foreach (KeyValuePair<string, long> kvp in _errorCounts)
            {
                snapshot[$"{kvp.Key}_errors"] = kvp.Value;
            }

            lock (_latencyLock)
            {
                foreach (KeyValuePair<string, List<long>> kvp in _latencies)
                {
                    if (kvp.Value.Any())
                    {
                        snapshot[$"{kvp.Key}_avg_latency_ms"] = kvp.Value.Average();
                        snapshot[$"{kvp.Key}_p95_latency_ms"] = GetPercentile(kvp.Value, 95);
                        snapshot[$"{kvp.Key}_p99_latency_ms"] = GetPercentile(kvp.Value, 99);
                    }
                }
            }

            return snapshot;
        }

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