using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using ZLog;

namespace ZSocket
{
    /// <summary>
    /// 解析粘包处理后的第二层数据并分发
    /// </summary>
    public class DispatchSystem : IDispatchSystem
    {
        public const int MAX_DATA_SIZE = 2 * 1024 * 1024;

        Dictionary<int, Action<int, MemoryStream>> rpcMap = new Dictionary<int, Action<int, MemoryStream>>();
        Dictionary<int, Action<int, MemoryStream>> rpcOldMap = new Dictionary<int, Action<int, MemoryStream>>();

        Dictionary<string, List<IMessageHandler>> mapMessageHandlers = new Dictionary<string, List<IMessageHandler>>();
        Dictionary<string, List<IRpcHandler>> mapRpcHandlers = new Dictionary<string, List<IRpcHandler>>();
        Dictionary<string, List<string>> mapRpcReplyTypes = new Dictionary<string, List<string>>();

        IncUidGenerator rpcIdGenerator = new IncUidGenerator();
        HeaderBuilderVersion1 headerBuilder = new HeaderBuilderVersion1();
        ParserVersion1 parser = new ParserVersion1();

        byte[] dataBuffer = new byte[MAX_DATA_SIZE];
        byte[] replyBuffer = new byte[MAX_DATA_SIZE];

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="serializationFlag">序列化模式，未支持</param>
        /// <param name="compressionFlag">压缩模式，未支持</param>
        public DispatchSystem(byte serializationFlag = 0x00, byte compressionFlag = 0x00)
        {
            headerBuilder.SetSerializationFlag(serializationFlag);
            headerBuilder.SetCompressionFlag(compressionFlag);

            foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
            {
                if (typeof(IMessageHandler).IsAssignableFrom(type) && typeof(IMessageHandler) != type && !type.IsAbstract)
                {
                    string msgType = type.GetCustomAttribute<MessageHandlerAttribute>()?.MsgType;
                    if (msgType == null)
                    {
                        Log.Error($"{type.Name} MessageHandler 特性未定义");
                        continue;
                    }

                    if (!mapMessageHandlers.TryGetValue(msgType, out List<IMessageHandler> handlers))
                    {
                        handlers = new List<IMessageHandler>();
                        mapMessageHandlers.Add(msgType, handlers);
                    }
                    handlers.Add(Activator.CreateInstance(type) as IMessageHandler);
                }
                else if (typeof(IRpcHandler).IsAssignableFrom(type) && typeof(IRpcHandler) != type && !type.IsAbstract)
                {
                    string recvType = type.GetCustomAttribute<RpcHandlerAttribute>()?.RecvMsgType;
                    string replyType = type.GetCustomAttribute<RpcHandlerAttribute>()?.ReplyMsgType;
                    if (recvType == null || replyType == null)
                    {
                        Log.Error($"{type.Name} RpcHandler 特性未定义");
                        continue;
                    }

                    if (!mapRpcHandlers.TryGetValue(recvType, out List<IRpcHandler> handlers))
                    {
                        handlers = new List<IRpcHandler>();
                        mapRpcHandlers.Add(recvType, handlers);
                    }
                    handlers.Add(Activator.CreateInstance(type) as IRpcHandler);

                    if (!mapRpcReplyTypes.TryGetValue(recvType, out List<string> replyTypes))
                    {
                        replyTypes = new List<string>();
                        mapRpcReplyTypes.Add(recvType, replyTypes);
                    }
                    replyTypes.Add(replyType);
                }
            }
        }

        /// <summary>
        /// 设置头
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        public void SetHeader(string key, string value)
        {
            headerBuilder.SetHeader(key, value);
        }

        void InternalSend(SocketHandler handler, string msgType, int rpcId, byte[] data, int offset, int size, byte flag = 0x00)
        {
            headerBuilder.SetReqNumber(rpcId)
                .SetFlag(flag)
                .SetMessageType(msgType)
                .Build();

            int pos = 0;
            Array.Copy(headerBuilder.Content, 0, dataBuffer, pos, headerBuilder.Size);
            pos += headerBuilder.Size;

            dataBuffer[pos] = (byte)((size & 0xff000000) >> 24);
            dataBuffer[pos + 1] = (byte)((size & 0xff0000) >> 16);
            dataBuffer[pos + 2] = (byte)((size & 0xff00) >> 8);
            dataBuffer[pos + 3] = (byte)(size & 0xff);
            pos += 4;

            if (pos + size > MAX_DATA_SIZE)
            {
                throw new Exception($"data too long {msgType}");
            }

            Array.Copy(data, offset, dataBuffer, pos, size);
            pos += size;

            handler.Send(dataBuffer, 0, pos);
        }

        /// <summary>
        /// RPC消息
        /// </summary>
        /// <param name="handler">Socket句柄</param>
        /// <param name="msgType">消息类型</param>
        /// <param name="data">消息正文</param>
        /// <param name="offset">消息正文偏移量</param>
        /// <param name="size">消息正文大小</param>
        /// <param name="callback">回调方法</param>
        public override void Call(SocketHandler handler, string msgType, byte[] data, int offset, int size, Action<int, MemoryStream> callback)
        {
            int rpcId = rpcIdGenerator.generate();

            rpcMap.Add(rpcId, callback);
            InternalSend(handler, msgType, rpcId, data, offset, size);
        }

        /// <summary>
        /// 发送不需要回复的消息
        /// </summary>
        /// <param name="handler">Socket句柄</param>
        /// <param name="msgType">消息类型</param>
        /// <param name="data">消息正文</param>
        /// <param name="offset">消息正文偏移量</param>
        /// <param name="size">消息正文大小</param>
        public override void Send(SocketHandler handler, string msgType, byte[] data, int offset, int size)
        {
            int rpcId = rpcIdGenerator.generate();

            InternalSend(handler, msgType, rpcId, data, offset, size);
        }

        /// <summary>
        /// 传入Socket接收到的信息，并进行解析和分发
        /// </summary>
        /// <param name="handler">Socket句柄</param>
        /// <param name="protocolVersion">解析协议版本</param>
        /// <param name="stream">消息字节流</param>
        public override void HandleRecvStream(SocketHandler handler, int protocolVersion, MemoryStream stream)
        {
            if (protocolVersion != 1)
            {
                throw new NotImplementedException();
            }
            parser.Parse(stream);

            if (parser.flags == 0x00)
            {
                if (mapMessageHandlers.TryGetValue(parser.msgType, out List<IMessageHandler> msgHandlers))
                {
                    foreach (var hdl in msgHandlers)
                    {
                        hdl.Handle(stream);
                    }
                }
                else if (mapRpcHandlers.TryGetValue(parser.msgType, out List<IRpcHandler> rpcHandlers))
                {
                    List<string> replyTypes = mapRpcReplyTypes[parser.msgType];

                    for (int i = 0; i < rpcHandlers.Count; ++i)
                    {
                        var hdl = rpcHandlers[i];
                        string replyType = replyTypes[i];
                        hdl.Handle(stream, replyBuffer, (size) =>
                        {
                            InternalSend(handler, replyType, parser.requestNumber, replyBuffer, 0, size, 0x01);
                        });
                    }
                }
                else
                {
                    Log.Error($"不存在消息的处理类 {parser.msgType}");
                }
            }
            else if (parser.flags == 0x01)
            {
                Action<int, MemoryStream> callback;
                if (rpcMap.TryGetValue(parser.requestNumber, out callback))
                {
                    rpcMap.Remove(parser.requestNumber);
                    callback.Invoke(ErrorCode.ERR_Success, stream);
                }
                else if (rpcOldMap.TryGetValue(parser.requestNumber, out callback))
                {
                    rpcOldMap.Remove(parser.requestNumber);
                    callback.Invoke(ErrorCode.ERR_Success, stream);
                }
                else
                {
                    Log.Warning("重复的回复消息或超时");
                }
            }
            else
            {
                throw new NotImplementedException();
            }
        }

        /// <summary>
        /// 超时清理没有接收到的消息。比如每10s调用一次
        /// </summary>
        public override void TimeOutClean()
        {
            int count = 0;
            foreach (var pair in rpcOldMap)
            {
                try
                {
                    pair.Value.Invoke(ErrorCode.ERR_RpcTimeout, null);
                }
                catch (Exception e)
                {
                    Log.Error(e.ToString());
                }
                count++;
            }
            rpcOldMap.Clear();

            // 交换
            var tmp = rpcMap;
            rpcMap = rpcOldMap;
            rpcOldMap = tmp;

            Log.Debug($"Rpc Cleaned {count}");
        }

        public override void ClearAllRpc(int errorCode)
        {
            foreach (var pair in rpcMap)
            {
                try
                {
                    pair.Value.Invoke(errorCode, null);
                }
                catch (Exception e)
                {
                    Log.Error(e.ToString());
                }
            }
            rpcMap.Clear();

            foreach (var pair in rpcOldMap)
            {
                try
                {
                    pair.Value.Invoke(errorCode, null);
                }
                catch (Exception e)
                {
                    Log.Error(e.ToString());
                }
            }
            rpcOldMap.Clear();

            Log.Debug($"Clear all Rpc with error {errorCode}");
        }
    }
}
