using System.Reflection;

namespace Quadarax.Foundation.Core.Reflection
{
    public static class AttributeQuery<TAttributeType> where TAttributeType : Attribute
    {
        public static TAttributeType Get<TAttributeProvider>(TAttributeProvider oProvider)
            where TAttributeProvider : ICustomAttributeProvider
        {
            return Get(oProvider, true);
        }

        public static TAttributeType Get<TAttributeProvider>(TAttributeProvider oProvider, bool bInherit)
            where TAttributeProvider : ICustomAttributeProvider
        {
            var attribute = Find(oProvider, bInherit);
            if (attribute == null)
            {
                throw new Exception($"Cannot find attribute '{typeof(TAttributeType).Name}' inside class '{oProvider.GetType().AssemblyQualifiedName}'");
            }
            return attribute;
        }

        public static TAttributeType? Find<TAttributeProvider>(TAttributeProvider oProvider, bool bInherit)
            where TAttributeProvider : ICustomAttributeProvider
        {
            var attributes = FindAll(oProvider, bInherit);
            return attributes.Length > 0 ? attributes[0] : null;
        }

        public static TAttributeType?[] FindAll<TAttributeProvider>(TAttributeProvider oProvider)
            where TAttributeProvider : ICustomAttributeProvider
        {
            return FindAll(oProvider, true);
        }

        public static TAttributeType?[] FindAll<TAttributeProvider>(TAttributeProvider oProvider, bool bInherit)
            where TAttributeProvider : ICustomAttributeProvider
        {
            return (TAttributeType?[])oProvider.GetCustomAttributes(typeof(TAttributeType), bInherit);
        }

        public static MemberInfo[] GetMembers(Type oSource, BindingFlags eFlags)
        {
            var oResult = new List<MemberInfo>();
            if (oSource.IsEnum)
            {
                var oMembers = oSource.GetEnumValues();
                foreach (var oMember in oMembers)
                {
                    var oMemberInfo = oSource.GetMember(oMember.ToString() ?? string.Empty);                                        
                    if (Has(oMemberInfo[0]))
                        oResult.Add(oMemberInfo[0]);                    
                }
                return oResult.ToArray();
            }
            throw new NotSupportedException(
                $"Attribute query in GetMembers does't support type object '{oSource.AssemblyQualifiedName}");
        }

        public static bool Has<TAttributeProvider>(TAttributeProvider oProvider)
            where TAttributeProvider : ICustomAttributeProvider
        {
            return oProvider.IsDefined(typeof(TAttributeType), true);
        }

        public static bool Has<TAttributeProvider>(TAttributeProvider oProvider, bool bInherit)
            where TAttributeProvider : ICustomAttributeProvider
        {
            return Find(oProvider, bInherit) != null;
        }
    }
}
