using System.Threading;
using Cysharp.Threading.Tasks;
using RebootKit.Engine.Main;
using RebootKit.Engine.Simulation;
using UnityEngine;
using Logger = RebootKit.Engine.Foundation.Logger;

namespace RebootKit.Engine.Network {
    public abstract class NetworkPlayerController : MonoBehaviour {
        static readonly Logger s_Logger = new Logger(nameof(NetworkPlayerController));
        
        ushort m_ActorIDToPossess;
        CancellationTokenSource m_PossessionCancellationTokenSource = new CancellationTokenSource();

        public Actor PossessedActor { get; private set; }

        internal void SetPossessedActor(ushort actorID) {
            s_Logger.Info("Setting possessed actor to " + actorID);
            
            if (actorID == 0) {
                m_ActorIDToPossess = 0;

                if (PossessedActor != null) {
                    PossessedActor = null;
                    OnUnpossessActor(PossessedActor);
                }
            } else {
                m_PossessionCancellationTokenSource.Cancel();
                m_PossessionCancellationTokenSource.Dispose();
                m_PossessionCancellationTokenSource = new CancellationTokenSource();

                WaitForActorToSpawnThenPossessAsync(actorID, m_PossessionCancellationTokenSource.Token).Forget();
            }
        }
        
        async UniTask WaitForActorToSpawnThenPossessAsync(ushort actorID, CancellationToken cancellationToken) {
            Actor actor = null;
            while (actor == null) {
                actor = RR.FindSpawnedActor(actorID);
                await UniTask.WaitForSeconds(0.5f, cancellationToken: cancellationToken);

                if (cancellationToken.IsCancellationRequested) {
                    return;
                }
            }

            PossessedActor = actor;
            OnPossessActor(actor);
        }

        protected virtual void OnPossessActor(Actor actor) {
        }
        
        protected virtual void OnUnpossessActor(Actor actor) {
        }
    }
}