using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace VCommon.Reflection
{
    public static class TypeExtensionMethod
    {
        /// <summary> 获取该类所有公开实例属性 </summary>
        public static PropertyInfo[] GetPublicInstanceProperties(this Type type) => type.GetProperties(BindingFlags.Public | BindingFlags.Instance);

        /// <summary> 获取该类所有公开实例字段 </summary>
        public static FieldInfo[] GetPublicInstanceFields(this Type type) => type.GetFields(BindingFlags.Public | BindingFlags.Instance);

        /// <summary> 获取全部公开实例方法 </summary>
        public static MethodInfo[] GetPublicInstanceMethods(this Type type) => type.GetMethods(BindingFlags.Public | BindingFlags.Instance);

        /// <summary>
        /// 反射一个类的全部接口, 按提供的类过滤, 支持泛型, 将匹配的不同泛型分组返回, 另外提供未命中的接口
        /// </summary>
        public static IReadOnlyDictionary<Type, Type[]> FilterInterfaces(this Type type, Type[] interfacesToCheck, out Type[] noMatches)
        {
            var riface = type.GetInterfaces();
            var lstNoMatches = new HashSet<Type>();

            var dic = new Dictionary<Type, Type[]>();

            foreach (var check in interfacesToCheck)
            {
                var list = new List<Type>();

                foreach (var ri in riface)
                {
                    if (ri == check)
                    {
                        list.Add(ri);
                    }
                    else if (ri.IsGenericType)
                    {
                        var genericTypeDefinition = ri.GetGenericTypeDefinition();
                        if (genericTypeDefinition == check)
                        {
                            list.Add(ri);
                        }
                        else if (false == interfacesToCheck.Contains(genericTypeDefinition))
                        {
                            lstNoMatches.Add(ri);
                        }
                    }
                    else if (false == interfacesToCheck.Contains(ri))
                    {
                        lstNoMatches.Add(ri);
                    }

                }

                if (0 == list.Count) continue;
                dic[check] = list.ToArray();
            }

            noMatches = lstNoMatches.ToArray();
            return dic;
        }
    }
}
