using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using MrWu.Debug;

namespace Server.Core
{
    /// <summary>
    /// 多处理器派发器
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="Msg"></typeparam>
    /// <typeparam name="Param"></typeparam>
    public abstract class MultiHandleBaseDispatcher<T, Msg, Param> : SingleInstance<T>
        where T : SingleInstance<T>, new()
        where Param : class
    {
        private class EventData<Msg1, Param1> where Param1 : class
        {
            public Msg1 msg;
            public Param1 param;

            public EventData(Msg1 msg, Param1 param)
            {
                this.msg = msg;
                this.param = param;
            }
        }

        /// <summary>
        /// 下一帧要执行的事件
        /// </summary>
        private ConcurrentQueue<EventData<Msg, Param>> nextEvent = new ConcurrentQueue<EventData<Msg, Param>>();

        private Queue<List<Action<Param>>> m_eventQueue = new Queue<List<Action<Param>>>();

        private Dictionary<Msg, List<Action<Param>>> m_msgDict = new Dictionary<Msg, List<Action<Param>>>();

        /// <summary>
        /// 普通事件派发器
        /// </summary>
        /// <param name="msgId"></param>
        /// <param name="listener"></param>
        public void AddListener(Msg msgId, Action<Param> listener)
        {
            if (m_msgDict.ContainsKey(msgId))
            {
                m_msgDict[msgId].Add(listener);
            }
            else
            {
                List<Action<Param>> list = new List<Action<Param>>();
                list.Add(listener);
                m_msgDict.Add(msgId, list);
            }
        }

        public void RemoveListener(Msg msgId, Action<Param> listener)
        {
            if (m_msgDict.ContainsKey(msgId))
            {
                List<Action<Param>> list = m_msgDict[msgId];
                if (list.Contains(listener))
                {
                    list.Remove(listener);
                    if (list.Count == 0)
                    {
                        m_msgDict.Remove(msgId);
                    }
                }
            }
        }

        public void Dispatch(Msg msgId, Param param = null)
        {
            InvokeMethods(m_msgDict, msgId, param);
        }

        public void DispatchNextFrame(Msg msgId, Param param = null)
        {
            nextEvent.Enqueue(new EventData<Msg, Param>(msgId, param));
        }

        private List<Action<Param>> GetEmptyEventList()
        {
            if (m_eventQueue.Count > 0)
            {
                return m_eventQueue.Dequeue();
            }

            return new List<Action<Param>>();
        }

        private void InvokeMethods(Dictionary<Msg, List<Action<Param>>> msgDict, Msg msgId, Param param)
        {
            if (!msgDict.ContainsKey(msgId)) return;

            List<Action<Param>> rawList = msgDict[msgId];
            int funcCount = rawList.Count;
            if (funcCount == 1)
            {
                Action<Param> onEvent = rawList[0];
                onEvent(param);
                return;
            }

            List<Action<Param>> invokeFuncs = GetEmptyEventList();
            invokeFuncs.AddRange(rawList);
            for (int i = 0; i < funcCount; i++)
            {
                try
                {
                    Action<Param> onEvent = invokeFuncs[i];
                    onEvent(param);
                }
                catch (Exception e)
                {
                    Debug.Error($"MuiltHandleError MsgId:{msgId} Error:{e}");
                }
            }

            invokeFuncs.Clear();
            m_eventQueue.Enqueue(invokeFuncs);
        }

        public void Update()
        {
            while (nextEvent.TryDequeue(out EventData<Msg, Param> eventData))
            {
                try
                {
                    Dispatch(eventData.msg, eventData.param);
                }
                catch (Exception e)
                {
                    Debug.Error($"事件执行错误:{eventData.msg},{e.Message}");
                }
            }
        }
    }
}