using FishNet.Managing;
using FishNet.Managing.Timing;
using System;
using UnityEngine;
namespace FishNet.Connection
{
    /// 
    /// A container for a connected client used to perform actions on and gather information for the declared client.
    /// 
    public partial class NetworkConnection : IEquatable
    {
#pragma warning disable CS0414
        #region Private.
        /// 
        /// Last tick this connection sent a ping.
        /// 
        private uint _lastPingTick;
        /// 
        /// Number of times client has excessively sent a ping.
        /// 
        private float _excessivePingCount;
        /// 
        /// Ticks expected between each ping.
        /// 
        private uint _requiredPingTicks;
        #endregion
        #region Const.
        /// 
        /// Number of times a ping may occur excessively before server will punish connection.
        /// 
        private const byte EXCESSIVE_PING_LIMIT = 10;
        #endregion
#pragma warning restore CS0414
        /// 
        /// Initializes for ping.
        /// 
        private void InitializePing()
        {
            //Give the client some room for error.
            float requiredInterval = (NetworkManager.TimeManager.PingInterval * 0.85f);
            //Round down so required ticks is lower.
            _requiredPingTicks = NetworkManager.TimeManager.TimeToTicks(requiredInterval, TickRounding.RoundDown);
        }
        /// 
        /// Resets PingPong values.
        /// 
        private void ResetPingPong()
        {
            _excessivePingCount = 0;
            _lastPingTick = 0;
        }
        /// 
        /// Called when a ping is received from this connection. Returns if can respond to ping.
        /// 
        /// True to respond to ping, false to kick connection.
        internal bool CanPingPong()
        {
            /* Only check ping conditions in build. Editors are prone to pausing which can
             * improperly kick clients. */
#if UNITY_EDITOR
            return true;
#else
            TimeManager tm = (NetworkManager == null) ? InstanceFinder.TimeManager : NetworkManager.TimeManager;
            //Server FPS is running low, timing isn't reliable enough to kick clients.
            if (tm.LowFrameRate)
                return true;
            uint currentTick = tm.Tick;
            uint difference = (currentTick - _lastPingTick);
            _lastPingTick = currentTick;
            //Ping sent too quickly.
            if (difference < _requiredPingTicks)
            {
                _excessivePingCount += 1f;
                //Ping limit hit.
                if (_excessivePingCount >= EXCESSIVE_PING_LIMIT)
                {
                    NetworkManager.LogWarning($"Kicked connectionId {ClientId} for excessive pings.");
                    Disconnect(true);
                }
                //Return to not send pong back.
                return false;
            }
            //Ping isnt too fast.
            else
            {
                _excessivePingCount = UnityEngine.Mathf.Max(0f, _excessivePingCount - 0.5f);
                return true;
            }
#endif
        }
    }
}