using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using ActorCore;
using Server.Core.Extend;

namespace Server.Core
{
    /// <summary>
    /// 主线程调度器
    /// </summary>
    public class MainThreadScheduler : IScheduler
    {
        private readonly ConcurrentQueue<int> idQueue = new ConcurrentQueue<int>();
        /// <summary>
        /// 等待加入的
        /// </summary>
        private readonly ConcurrentQueue<int> addIds = new ConcurrentQueue<int>();
        
        private readonly ActorManager _actorManager;

        private readonly ThreadSynchronizationContext
            _threadSynchronizationContext = new ThreadSynchronizationContext();

        private bool IsDisposed;
        
        public MainThreadScheduler(ActorManager actorManager)
        {
            SynchronizationContext.SetSynchronizationContext(_threadSynchronizationContext);
            this._actorManager = actorManager;
        }

        public void Update()
        {
            if (IsDisposed)
            {
                return;
            }
            SynchronizationContext.SetSynchronizationContext(_threadSynchronizationContext);
            this._threadSynchronizationContext.Update();

            int count = this.idQueue.Count;
            while (count -- > 0)
            {
                if (!this.idQueue.TryDequeue(out int id))
                {
                    continue;
                }

                IActor actor = this._actorManager.Get(id);
                if (actor == null)
                {
                    continue;
                }

                if (actor.IsDisposed)
                {
                    continue;
                }

                ActorManager.Current = actor;
                SynchronizationContext.SetSynchronizationContext(actor.ThreadSynchronizationContext);
                actor.IUpdate();
                ActorManager.Current = null;
                
                this.idQueue.Enqueue(id);
            }
        }

        public void LateUpdate()
        {
            if (IsDisposed)
            {
                return;
            }
            int count = this.idQueue.Count;
            while (count -- > 0)
            {
                if (!this.idQueue.TryDequeue(out int id))
                {
                    continue;
                }

                IActor actor = this._actorManager.Get(id);
                if (actor == null)
                {
                    continue;
                }

                if (actor.IsDisposed)
                {
                    continue;
                }
                
                ActorManager.Current = actor;
                SynchronizationContext.SetSynchronizationContext(actor.ThreadSynchronizationContext);
                actor.ILateUpdate();
                actor.ThreadSynchronizationContext.Update();
                ActorManager.Current = null;
                
                this.idQueue.Enqueue(id);
            }

            while (this.addIds.Count > 0)
            {
                this.addIds.TryDequeue(out int result);
                this.idQueue.Enqueue(result);
            }
        }

        public void Add(int actorTypeId)
        {
            this.addIds.Enqueue(actorTypeId);
        }

        public void Dispose()
        {
            IsDisposed = true;
            //.Net 才有这个方法
            this.idQueue.Clear();
            this.addIds.Clear();
        }
    }
}