using System;
using System.Collections.Generic;
using MrWu.Debug;
using Server.Core;

namespace NetWorkMessage
{
    public class OpcodeType : Singleton<OpcodeType>
    {
        /// <summary>
        /// 包类型 对应 的包编号
        /// </summary>
        private readonly DoubleMap<Type, uint> typeOpcode = new DoubleMap<Type, uint>();

        /// <summary>
        /// Request 对应的 Response
        /// </summary>
        private readonly Dictionary<Type, Type> requestResponse = new Dictionary<Type, Type>();

        protected override void Awake()
        {
            HashSet<Type> types = CodeTypes.Instance.GetTypes(typeof(MessageAttribute));
            foreach (Type type in types)
            {
                object[] att = type.GetCustomAttributes(typeof(MessageAttribute), false);
                if (att.Length == 0)
                {
                    continue;
                }
                
                MessageAttribute messageAttribute = att[0] as MessageAttribute;
                if (messageAttribute == null)
                {
                    continue;
                }

                uint opcode = messageAttribute.Opcode;
                if (opcode != 0)
                {
                    if (!this.typeOpcode.Add(type, opcode))
                    {
                        Debug.Error($"包协议添加失败! {type}");
                    }
                }

                if (typeof(IRequest).IsAssignableFrom(type))
                {
                    var attrs = type.GetCustomAttributes(typeof(ResponseTypeAttribute), false);
                    if (attrs.Length == 0)
                    {
                        Debug.Error($"not found responseType: {type}");
                        continue;
                    }
                    
                    ResponseTypeAttribute responseTypeAttribute = attrs[0] as ResponseTypeAttribute;
                    this.requestResponse.Add(type,responseTypeAttribute.Type);
                }
            }
        }

        public uint GetOpcode(Type type)
        {
            return this.typeOpcode.GetValueByKey(type);
        }

        public Type GetType(uint opcode)
        {
            return this.typeOpcode.GetKeyByValue(opcode);
        }

        public Type GetResponseType(Type request)
        {
            if (!requestResponse.TryGetValue(request, out Type response))
            {
                Debug.Error($"not find response type, request type: {request.FullName}");
                return null;
            }

            return response;
        }
    }
}