using FishNet.Component.ColliderRollback;
using FishNet.Managing;
using FishNet.Managing.Client;
using FishNet.Managing.Predicting;
using FishNet.Managing.Scened;
using FishNet.Managing.Server;
using FishNet.Managing.Statistic;
using FishNet.Managing.Timing;
using FishNet.Managing.Transporting;
using FishNet.Utility;
using System;
using System.Linq;
using UnityEngine;
namespace FishNet
{
    /// 
    /// Used to globally get information from the first found instance of NetworkManager.
    /// 
    public static class InstanceFinder
    {
        #region Public.
        /// 
        /// Returns the first found NetworkManager instance.
        /// 
        public static NetworkManager NetworkManager
        {
            get
            {
                if (_networkManager == null)
                {
                    int managersCount = NetworkManager.Instances.Count;
                    //At least one manager.
                    if (managersCount > 0)
                    {
                        _networkManager = NetworkManager.Instances.First();
                        if (managersCount > 1)
                            _networkManager.LogWarning($"Multiple NetworkManagers found, the first result will be returned. If you only wish to have one NetworkManager then uncheck 'Allow Multiple' within your NetworkManagers.");
                    }
                    //No managers.
                    else
                    {
                        //If application is quitting return null without logging.
                        if (ApplicationState.IsQuitting())
                            return null;
                        Debug.Log($"NetworkManager not found in any open scenes.");
                    }
                }
                return _networkManager;
            }
        }
        /// 
        /// Returns the first instance of ServerManager.
        /// 
        public static ServerManager ServerManager
        {
            get
            {
                NetworkManager nm = NetworkManager;
                return (nm == null) ? null : nm.ServerManager;
            }
        }
        /// 
        /// Returns the first instance of ClientManager.
        /// 
        public static ClientManager ClientManager
        {
            get
            {
                NetworkManager nm = NetworkManager;
                return (nm == null) ? null : nm.ClientManager;
            }
        }
        /// 
        /// Returns the first instance of TransportManager.
        /// 
        public static TransportManager TransportManager
        {
            get
            {
                NetworkManager nm = NetworkManager;
                return (nm == null) ? null : nm.TransportManager;
            }
        }
        /// 
        /// Returns the first instance of TimeManager.
        /// 
        public static TimeManager TimeManager
        {
            get
            {
                NetworkManager nm = NetworkManager;
                return (nm == null) ? null : nm.TimeManager;
            }
        }
        /// 
        /// Returns the first instance of SceneManager.
        /// 
        public static SceneManager SceneManager
        {
            get
            {
                NetworkManager nm = NetworkManager;
                return (nm == null) ? null : nm.SceneManager;
            }
        }
        /// 
        /// Returns the first instance of RollbackManager.
        /// 
        public static RollbackManager RollbackManager
        {
            get
            {
                NetworkManager nm = NetworkManager;
                return (nm == null) ? null : nm.RollbackManager;
            }
        }
        /// 
        /// Returns the first instance of PredictionManager.
        /// 
        public static PredictionManager PredictionManager
        {
            get
            {
                NetworkManager nm = NetworkManager;
                return (nm == null) ? null : nm.PredictionManager;
            }
        }
        /// 
        /// Returns the first instance of StatisticsManager.
        /// 
        public static StatisticsManager StatisticsManager
        {
            get
            {
                NetworkManager nm = NetworkManager;
                return (nm == null) ? null : nm.StatisticsManager;
            }
        }
        /// 
        /// True if the server is active.
        /// 
        public static bool IsServer => (NetworkManager == null) ? false : NetworkManager.IsServer;
        /// 
        /// True if only the server is active.
        /// 
        public static bool IsServerOnly => (NetworkManager == null) ? false : NetworkManager.IsServerOnly;
        /// 
        /// True if the client is active and authenticated.
        /// 
        public static bool IsClient => (NetworkManager == null) ? false : NetworkManager.IsClient;
        /// 
        /// True if only the client is active and authenticated.
        /// 
        public static bool IsClientOnly => (NetworkManager == null) ? false : NetworkManager.IsClientOnly;
        /// 
        /// True if client and server are active.
        /// 
        public static bool IsHost => (NetworkManager == null) ? false : NetworkManager.IsHost;
        /// 
        /// True if client nor server are active.
        /// 
        public static bool IsOffline => (_networkManager == null) ? true : (!NetworkManager.IsServer && !NetworkManager.IsClient);
        #endregion
        #region Private.
        /// 
        /// NetworkManager instance.
        /// 
        private static NetworkManager _networkManager;
        #endregion
        #region Registered components
        /// 
        /// Registers to invoke an action when a specified component becomes registered. Action will invoke immediately if already registered.
        /// 
        /// Component type.
        /// Action to invoke.
        public static void RegisterInvokeOnInstance(Action handler) where T : UnityEngine.Component => NetworkManager?.RegisterInvokeOnInstance(handler);
        /// 
        /// Unrgisters to invoke an action when a specified component becomes registered. Action will invoke immediately if already registered.
        /// 
        /// Component type.
        /// Action to invoke.
        public static void UnregisterInvokeOnInstance(Action handler) where T : UnityEngine.Component => NetworkManager?.UnregisterInvokeOnInstance(handler);
        /// 
        /// Returns class of type if found within CodegenBase classes.
        /// 
        /// 
        /// 
        public static T GetInstance() where T : UnityEngine.Component => NetworkManager?.GetInstance();
        /// 
        /// Registers a new component to this NetworkManager.
        /// 
        /// Type to register.
        /// Reference of the component being registered.
        /// True to replace existing references.
        public static void RegisterInstance(T component, bool replace = true) where T : UnityEngine.Component => NetworkManager?.RegisterInstance(component, replace);
        /// 
        /// Unregisters a component from this NetworkManager.
        /// 
        /// Type to unregister.
        public static void UnregisterInstance() where T : UnityEngine.Component => NetworkManager?.UnregisterInstance();
        #endregion
    }
}