using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MrWu.Debug;
using NetWorkMessage;
using Server.Core;

namespace ActorCore
{
    public abstract class Actor : IActor, ITimerManager, ICoroutineLockManager, IMailBox
    {
        public ActorId ActorId { get; private set; }

        public bool IsRegister { get; set; }

        public bool IsDisposed { get; private set; }

        public abstract SchedulerType SchedulerType { get; }

        public ThreadSynchronizationContext ThreadSynchronizationContext { get; private set; }

        private const int TIMEOUT_TIME = 40 * 1000;

        private uint RpcId;

        public int Id => ActorId.ActorTypeId;

        private readonly MailBox MailBox;

        protected readonly CoroutineLockManager CoroutineLockManager;

        private readonly TimerManager TimerManager;

        public Actor(byte moduleId, byte nodeNum, byte actorTypeId)
        {
            this.ActorId = new ActorId(moduleId, nodeNum, actorTypeId);
            this.ThreadSynchronizationContext = new ThreadSynchronizationContext(actorTypeId);
            this.CoroutineLockManager = new CoroutineLockManager();
            this.TimerManager = new TimerManager();
            this.MailBox = new MailBox(this);
        }

        void IActor.IUpdate()
        {
            MailBox.Update();
            CoroutineLockManager.Update();
            TimerManager.Update();
            Update();
        }

        void IActor.ILateUpdate()
        {
            LateUpdate();
        }

        protected virtual void Update()
        {
        }

        protected virtual void LateUpdate()
        {
        }

        public virtual void Dispose()
        {
            if (IsRegister)
            {
                //如果这个没有正确被Manager管理，这里将会移除错误的Id
                ActorMessageQueue.Instance.RemoveQueue(this.Id);
            }
        }

        public void Send(ActorId actorId, IMessage message)
        {
            MailBox.Send(actorId, (MessageObject)message);
        }

        public void Reply(ActorId actorId, IResponse response)
        {
            MailBox.Send(actorId, (MessageObject)response);
        }

        public async Task<IResponse> Call(ActorId actorId, IRequest request)
        {
            IResponse response;
            if (actorId.Process == this.ActorId.Process)
            {
                //内部Rpc
                response = await CallInner(actorId, request);
            }
            else
            {
                //外部Rpc
                NetInnerRequest netInnerRequest = NetInnerRequest.Create();
                netInnerRequest.FromActorId = this.ActorId;
                netInnerRequest.ActorId = actorId;
                netInnerRequest.MessageObject = request;

                NetInnerResponse innerResponse = (NetInnerResponse)await CallInner(
                    new ActorId(this.ActorId.Process, ActorTypeId.NetInner),
                    netInnerRequest);

                //把错误码传递给响应体
                if (innerResponse.MessageObject == null)
                {
                    innerResponse.MessageObject =
                        MessageHelper.CreateResponse(request.GetType(), request.RpcId, innerResponse.Error);
                }

                response = innerResponse.MessageObject;
                innerResponse.Dispose();
            }

            return response;
        }

        private async Task<IResponse> CallInner(ActorId actorId, IRequest request)
        {
            uint rpcId = GetRpcId();
            request.RpcId = rpcId;

            if (actorId == default)
            {
                throw new Exception($"acotr id is 0:{request}");
            }

            IResponse response;
            Type requestType = request.GetType();
            MessageSenderStruct messageSenderStruct = new MessageSenderStruct(actorId, requestType);
            Debug.Log($"CallInner:{request.GetType()} {rpcId}");
            if (!MailBox.AddActorRpcResponse(rpcId, messageSenderStruct))
            {
                Debug.Error("RpcId 竟然有重复的现象!!!");
                response = MessageHelper.CreateResponse(requestType, rpcId, NetErrorCode.ERR_RpcIdAddFail);
                return response;
            }
            
            if (!ActorMessageQueue.Instance.Send(this.ActorId, actorId, (MessageObject)request))
            {
                response = MessageHelper.CreateResponse(requestType, rpcId, NetErrorCode.ERR_NotFoundActor);
                return response;
            }

            async Task Timeout()
            {
                await WaitAsync(TIMEOUT_TIME);

                if (!MailBox.RemoveActorRpcResponse(rpcId, out MessageSenderStruct action))
                {
                    return;
                }

                //超时
                IResponse timeOutResponse = MessageHelper.CreateResponse(requestType, rpcId, NetErrorCode.ERR_Timeout);
                action.SetResult(timeOutResponse);
            }

            _ = Timeout();

            long beginTime = TimeInfo.Instance.FrameTime;

            response = await messageSenderStruct.Wait();
            long endTime = TimeInfo.Instance.FrameTime;
            long costTime = endTime - beginTime;
            if (costTime > 200)
            {
                Debug.Warning($"actor rpc time > 200： {costTime} {requestType.FullName}");
            }

            return response;
        }

        private uint GetRpcId()
        {
            return ++RpcId;
        }

        #region ITimerManager

        public Task WaitTillAsync(long tillTIme)
        {
            return TimerManager.WaitTillAsync(tillTIme);
        }

        public Task WaitFrameAsync()
        {
            return TimerManager.WaitFrameAsync();
        }

        public Task WaitAsync(long time)
        {
            return TimerManager.WaitAsync(time);
        }

        public long NewOnceTimer(long tillTime, Action<object> action, object args = null)
        {
            return TimerManager.NewOnceTimer(tillTime, action, args);
        }

        public long NewFrameTimer(Action<object> action, object args = null)
        {
            return TimerManager.NewFrameTimer(action, args);
        }

        public long NewRepeatedTimer(long time, Action<object> action, object args = null)
        {
            return TimerManager.NewRepeatedTimer(time, action, args);
        }

        public bool Remove(ref long id)
        {
            return TimerManager.Remove(ref id);
        }

        #endregion ITimerManager

        #region ICoroutineLockManager

        public async Task<CoroutineLock> Wait(int coroutineLockType, long key, int time = 600000)
        {
            return await CoroutineLockManager.Wait(coroutineLockType, key, time);
        }

        #endregion ICoroutineLockManager

        #region IMailBox

        public abstract MailBoxType MailBoxType { get; }

        public virtual int HandleMaxMessageCount => 200;

        public virtual void RegisterHandle()
        {
        }

        public void RegisterMessageHandle(Type type, ActorHandle handle)
        {
            MailBox.RegisterMessageHandle(type, handle);
        }

        public void RegisterRPCHandle(Type type, ActorRpcHandle rpcHandle)
        {
            MailBox.RegisterRPCHandle(type, rpcHandle);
        }

        #endregion IMailBox
    }
}