using System.Collections.Generic;
using System.Globalization;
using UnityEngine;

namespace IGP.UnitySDK.Core
{
    /// <summary>
    /// RTT (Round-Trip Time) 统计信息
    /// 用于测量和监控网络延迟
    /// </summary>
    public class IGPRTTStats
    {
        private readonly List<float> samples = new List<float>();
        private const int MaxSamples = 100; // 保留最近100个样本

        private float cumulativeSum = 0f;

        /// <summary>
        /// 最小RTT（秒）
        /// </summary>
        public float MinRTT { get; private set; } = float.MaxValue;

        /// <summary>
        /// 最大RTT（秒）
        /// </summary>
        public float MaxRTT { get; private set; } = 0f;

        /// <summary>
        /// 平均RTT（秒）
        /// </summary>
        public float AvgRTT { get; private set; } = 0f;

        /// <summary>
        /// 最后一次RTT（秒）
        /// </summary>
        public float LastRTT { get; private set; } = 0f;

        /// <summary>
        /// 样本数量
        /// </summary>
        public int SampleCount => samples.Count;

        /// <summary>
        /// 添加RTT样本
        /// </summary>
        /// <param name="rtt">RTT值（秒）</param>
        public void AddSample(float rtt)
        {
            LastRTT = rtt;
            MinRTT = Mathf.Min(MinRTT, rtt);
            MaxRTT = Mathf.Max(MaxRTT, rtt);

            samples.Add(rtt);
            cumulativeSum += rtt;

            // 保持样本数量在限制内
            if (samples.Count > MaxSamples)
            {
                var removed = samples[0];
                cumulativeSum -= removed;
                samples.RemoveAt(0);
            }

            AvgRTT = cumulativeSum / samples.Count;
        }

        /// <summary>
        /// 重置所有统计信息
        /// </summary>
        public void Reset()
        {
            samples.Clear();
            cumulativeSum = 0f;
            MinRTT = float.MaxValue;
            MaxRTT = 0f;
            AvgRTT = 0f;
            LastRTT = 0f;
        }
        
        /// <summary>
        /// 获取统计信息摘要
        /// </summary>
        /// <returns>(min, max, avg, last, count)</returns>
        public (float min, float max, float avg, float last, int count) GetStats()
        {
            return (MinRTT, MaxRTT, AvgRTT, LastRTT, SampleCount);
        }
        
        /// <summary>
        /// 获取网络质量评级
        /// </summary>
        /// <returns>优秀/良好/一般/较差/很差</returns>
        public string GetQuality()
        {
            float avgMs = AvgRTT * 1000f;
            
            if (avgMs < 20f) return "优秀";
            if (avgMs < 50f) return "良好";
            if (avgMs < 100f) return "一般";
            if (avgMs < 200f) return "较差";
            return "很差";
        }
        
        /// <summary>
        /// 获取质量颜色
        /// </summary>
        /// <returns>Unity Color</returns>
        public Color GetQualityColor()
        {
            float avgMs = AvgRTT * 1000f;
            
            if (avgMs < 20f) return Color.green;        // 优秀
            if (avgMs < 50f) return Color.yellow;       // 良好
            if (avgMs < 100f) return new Color(1f, 0.5f, 0f); // 一般（橙色）
            if (avgMs < 200f) return new Color(1f, 0.3f, 0f); // 较差（深橙）
            return Color.red;                            // 很差
        }
        
        /// <summary>
        /// 转换为字符串（用于日志）
        /// </summary>
        public override string ToString()
        {
            if (SampleCount == 0)
            {
                return "RTT: No samples";
            }

            return $"RTT: last={LastRTT*1000:F1}ms, avg={AvgRTT*1000:F1}ms, " +
                   $"min={MinRTT*1000:F1}ms, max={MaxRTT*1000:F1}ms, samples={SampleCount}";
        }
    }

    /// <summary>
    /// Snapshot of the underlying KCP transport state. Values come from KCP ACK timing
    /// and queues, so they are independent from the app-level ping/pong RTT samples.
    /// </summary>
    public readonly struct IGPKcpTransportStats
    {
        public static IGPKcpTransportStats Unavailable => default;

        public IGPKcpTransportStats(
            bool isAvailable,
            int smoothedRttMs,
            int rtoMs,
            int rttVarMs,
            int waitSnd,
            int sndQueue,
            int sndBuf,
            int rcvQueue,
            int rcvBuf,
            int ackList,
            uint cwnd,
            uint remoteWindow,
            long datagramsIn = 0,
            long datagramsOut = 0,
            float datagramsInPerSecond = 0f,
            float datagramsOutPerSecond = 0f,
            long datagramBytesIn = 0,
            long datagramBytesOut = 0)
        {
            IsAvailable = isAvailable;
            SmoothedRttMs = smoothedRttMs;
            RtoMs = rtoMs;
            RttVarMs = rttVarMs;
            WaitSnd = waitSnd;
            SndQueue = sndQueue;
            SndBuf = sndBuf;
            RcvQueue = rcvQueue;
            RcvBuf = rcvBuf;
            AckList = ackList;
            Cwnd = cwnd;
            RemoteWindow = remoteWindow;
            DatagramsIn = datagramsIn;
            DatagramsOut = datagramsOut;
            DatagramsInPerSecond = datagramsInPerSecond;
            DatagramsOutPerSecond = datagramsOutPerSecond;
            DatagramBytesIn = datagramBytesIn;
            DatagramBytesOut = datagramBytesOut;
        }

        public bool IsAvailable { get; }
        public int SmoothedRttMs { get; }
        public int RtoMs { get; }
        public int RttVarMs { get; }
        public int WaitSnd { get; }
        public int SndQueue { get; }
        public int SndBuf { get; }
        public int RcvQueue { get; }
        public int RcvBuf { get; }
        public int AckList { get; }
        public uint Cwnd { get; }
        public uint RemoteWindow { get; }
        public long DatagramsIn { get; }
        public long DatagramsOut { get; }
        public float DatagramsInPerSecond { get; }
        public float DatagramsOutPerSecond { get; }
        public long DatagramBytesIn { get; }
        public long DatagramBytesOut { get; }

        public bool HasSmoothedRtt => IsAvailable && SmoothedRttMs > 0;
    }

    internal static class IGPRTTDisplayFormatting
    {
        internal static string FormatUdpDatagramCount(long value)
        {
            if (value >= 999_500_000L)
            {
                return (value / 1_000_000_000d).ToString("0.#", CultureInfo.InvariantCulture) + "b";
            }

            if (value >= 999_500L)
            {
                return (value / 1_000_000d).ToString("0.#", CultureInfo.InvariantCulture) + "m";
            }

            if (value >= 10_000L)
            {
                return (value / 1_000d).ToString("0.#", CultureInfo.InvariantCulture) + "k";
            }

            return value.ToString("N0", CultureInfo.InvariantCulture);
        }

        internal static string FormatByteCount(long value)
        {
            if (value >= 1_099_511_627_776L)
            {
                return FormatByteUnit(value, 1_099_511_627_776d, "TB");
            }

            if (value >= 1_073_741_824L)
            {
                return FormatByteUnit(value, 1_073_741_824d, "GB");
            }

            if (value >= 1_048_576L)
            {
                return FormatByteUnit(value, 1_048_576d, "MB");
            }

            if (value >= 1024L)
            {
                return FormatByteUnit(value, 1024d, "KB");
            }

            return value.ToString("N0", CultureInfo.InvariantCulture) + " B";
        }

        private static string FormatByteUnit(long value, double unitBytes, string unit)
        {
            return (value / unitBytes).ToString("0.#", CultureInfo.InvariantCulture) + " " + unit;
        }
    }
}
