using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Mirror
{
    /// 
    /// Component that controls visibility of networked objects between scenes.
    /// Any object with this component on it will only be visible to other objects in the same scene
    /// This would be used when the server has multiple additive subscenes loaded to isolate players to their respective subscenes
    /// 
    // Deprecated 2021-07-13
    [Obsolete(NetworkVisibilityObsoleteMessage.Message)]
    [DisallowMultipleComponent]
    [AddComponentMenu("Network/NetworkSceneChecker")]
    [RequireComponent(typeof(NetworkIdentity))]
    [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-scene-checker")]
    public class NetworkSceneChecker : NetworkVisibility
    {
        /// 
        /// Flag to force this object to be hidden from all observers.
        /// If this object is a player object, it will not be hidden for that client.
        /// 
        [Tooltip("Enable to force this object to be hidden from all observers.")]
        public bool forceHidden;
        // Use Scene instead of string scene.name because when additively loading multiples of a subscene the name won't be unique
        static readonly Dictionary> sceneCheckerObjects = new Dictionary>();
        Scene currentScene;
        [ServerCallback]
        void Awake()
        {
            currentScene = gameObject.scene;
            // Debug.Log($"NetworkSceneChecker.Awake currentScene: {currentScene}");
        }
        public override void OnStartServer()
        {
            if (!sceneCheckerObjects.ContainsKey(currentScene))
                sceneCheckerObjects.Add(currentScene, new HashSet());
            sceneCheckerObjects[currentScene].Add(netIdentity);
        }
        public override void OnStopServer()
        {
            if (sceneCheckerObjects.ContainsKey(currentScene) && sceneCheckerObjects[currentScene].Remove(netIdentity))
                RebuildSceneObservers();
        }
        [ServerCallback]
        void Update()
        {
            if (currentScene == gameObject.scene)
                return;
            // This object is in a new scene so observers in the prior scene
            // and the new scene need to rebuild their respective observers lists.
            // Remove this object from the hashset of the scene it just left
            sceneCheckerObjects[currentScene].Remove(netIdentity);
            // RebuildObservers of all NetworkIdentity's in the scene this object just left
            RebuildSceneObservers();
            // Set this to the new scene this object just entered
            currentScene = gameObject.scene;
            // Make sure this new scene is in the dictionary
            if (!sceneCheckerObjects.ContainsKey(currentScene))
                sceneCheckerObjects.Add(currentScene, new HashSet());
            // Add this object to the hashset of the new scene
            sceneCheckerObjects[currentScene].Add(netIdentity);
            // RebuildObservers of all NetworkIdentity's in the scene this object just entered
            RebuildSceneObservers();
        }
        void RebuildSceneObservers()
        {
            foreach (NetworkIdentity networkIdentity in sceneCheckerObjects[currentScene])
                if (networkIdentity != null)
                    networkIdentity.RebuildObservers(false);
        }
        /// 
        /// Callback used by the visibility system to determine if an observer (player) can see this object.
        /// If this function returns true, the network connection will be added as an observer.
        /// 
        /// Network connection of a player.
        /// True if the player can see this object.
        public override bool OnCheckObserver(NetworkConnection conn)
        {
            if (forceHidden)
                return false;
            return conn.identity.gameObject.scene == gameObject.scene;
        }
        /// 
        /// Callback used by the visibility system to (re)construct the set of observers that can see this object.
        /// Implementations of this callback should add network connections of players that can see this object to the observers set.
        /// 
        /// The new set of observers for this object.
        /// True if the set of observers is being built for the first time.
        public override void OnRebuildObservers(HashSet observers, bool initialize)
        {
            // If forceHidden then return without adding any observers.
            if (forceHidden)
                return;
            // Add everything in the hashset for this object's current scene
            foreach (NetworkIdentity networkIdentity in sceneCheckerObjects[currentScene])
                if (networkIdentity != null && networkIdentity.connectionToClient != null)
                    observers.Add(networkIdentity.connectionToClient);
        }
    }
}