namespace TPSBR
{
	using UnityEngine;
	using Fusion;
	/// 
	/// This component serves as an AoI position proxy. It is useful for objects which don't need their own NetworkTransform component, but still need to be filtered by AoI.
	/// Example: Player + Weapon. Each Weapon is a separate dynamically spawned NetworkObject with NetworkAreaOfInterestProxy component. Upon spawn Weapon is parented under Player object (usually under a hand bone).
	/// There is no need to synchronize Weapon position because it is driven locally. But if a Player runs out of AoI, we want to stop updating both objects Player and Weapon.
	/// 
	[DisallowMultipleComponent]
	[DefaultExecutionOrder(10000)]
	public sealed unsafe class NetworkAreaOfInterestProxy : NetworkTRSP
	{
		// PUBLIC MEMBERS
		public Transform PositionSource => _positionSource;
		// PRIVATE MEMBERS
		[SerializeField]
		private Transform _positionSource;
		private Transform _defaultPositionSource;
		private bool      _hasExplicitPositionSource;
		private bool      _isSpawned;
		// PUBLIC METHODS
		public void SetPosition(Vector3 position)
		{
			if (_isSpawned == true)
			{
				State.Position = position;
			}
		}
		public void SetPositionSource(Transform positionSource)
		{
			_positionSource = positionSource;
			_hasExplicitPositionSource = true;
			Synchronize();
		}
		public void ResetPositionSource()
		{
			_positionSource = _defaultPositionSource;
			_hasExplicitPositionSource = false;
			Synchronize();
		}
		public void FindPositionSourceInParent()
		{
			FindPositionSourceInParent(true);
			Synchronize();
		}
		public void Synchronize()
		{
			if (_isSpawned == true && _positionSource != null)
			{
				State.Position = _positionSource.position;
			}
		}
		// NetworkBehaviour INTERFACE
		public override void Spawned()
		{
			_isSpawned = true;
			ReplicateToAll(false);
			if (_hasExplicitPositionSource == false && _positionSource == null)
			{
				State.Position = default;
				FindPositionSourceInParent(false);
			}
			Synchronize();
		}
		public override void Despawned(NetworkRunner runner, bool hasState)
		{
			_isSpawned = false;
			ResetPositionSource();
		}
		public override void FixedUpdateNetwork()
		{
			Synchronize();
		}
		// MonoBehaviour INTERFACE
		private void Awake()
		{
			_defaultPositionSource = _positionSource;
		}
		// PRIVATE METHODS
		private void FindPositionSourceInParent(bool isExplicit)
		{
			Transform parentTransform = transform.parent;
			while (parentTransform != null)
			{
				NetworkObject networkObject = parentTransform.GetComponent();
				if (networkObject != null)
				{
					_positionSource = parentTransform;
					_hasExplicitPositionSource = isExplicit;
					break;
				}
				parentTransform = parentTransform.parent;
			}
		}
	}
}