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

namespace VCommon.Reflection
{
    public static class AttributeExtensionMethod
    {
        public static T[] GetCustomAttributeIncludeInterface<T>(this Type findFrom) where T : Attribute
        {
            var ofType = findFrom.GetCustomAttributes<T>(true);
            var ifaces = findFrom.GetInterfaces().SelectMany(i => i.GetCustomAttributes<T>(true));

            return ofType.Concat(ifaces).Distinct().ToArray();
        }

        public static string GetDescriptionAttributeValue(this MemberInfo me) => me.GetCustomAttribute<DescriptionAttribute>()?.Description;

        public static bool IsDefinedIncludeInterface(this Type me, Type attributeType) => me.IsDefined(attributeType, true) || me.GetInterfaces().Any(p => p.IsDefined(attributeType, true));

        public static bool IsDefinedIncludeInterface(this PropertyInfo me, Type attributeType) => me.IsDefined(attributeType, true) || LookupInterfaceDefines(me, attributeType);

        public static T[] GetCustomAttributeIncludeInterface<T>(this PropertyInfo me)
        {
            var lstResult = new List<T>();

            lstResult.AddRange(me.GetCustomAttributes().OfType<T>());

            var interfaces = me.DeclaringType?.GetInterfaces();
            if (null == interfaces) return lstResult.ToArray();

            foreach (var iface in interfaces)
            {
                var propertyInfo = iface.GetProperty(me.Name);
                if (null != propertyInfo) lstResult.AddRange(propertyInfo.GetCustomAttributes(true).OfType<T>());
            }

            return lstResult.ToArray();
        }

        private static bool LookupInterfaceDefines(PropertyInfo me, Type attributeType)
        {
            var interfaces = me?.DeclaringType?.GetInterfaces();
            return null != interfaces
                && interfaces.Any(p => true == p.GetProperty(me.Name)?.IsDefined(attributeType, true));
        }
    }
}
