using LY.App.Extensions.DI;
using System.Reflection;
namespace LY.App.Extensions
{
    public static class AutoDIExtensions
    {
        /// 
        /// 
        /// 
        /// 
        /// 
        public static IServiceCollection ServicesAutoInjectionExtension(this IServiceCollection serviceCollection)
        {
            var directory = AppDomain.CurrentDomain.BaseDirectory;
            var types = Directory.GetFiles(directory, "*.dll", SearchOption.TopDirectoryOnly)
                .Where(s => !s.ToLower().Contains("sql"))
                .Select(Assembly.LoadFrom)
                .SelectMany(a => a.GetTypes());
            Injection(serviceCollection, types);
            return serviceCollection;
        }
        /// 
        /// 服务自动注入
        /// 
        /// 需要自动注入服务的服务集合
        /// 应用于每个Assembly的筛选函数
        /// 指定的注入类型不在可注入的范围内
        /// 指定注入的类型未实现任何服务
        /// 输入的参数错误:1、注入的类型未实现指定的服务。2、指定的服务不是Interface类型
        /// 自动注入服务后的服务集合
        public static IServiceCollection ServicesAutoInjection(this IServiceCollection serviceCollection, Func selector)
        {
            var directory = AppDomain.CurrentDomain.BaseDirectory;
            var types = Directory.GetFiles(directory, "*.dll", SearchOption.TopDirectoryOnly)
                .Select(Assembly.LoadFrom)
                .Where(selector)
                .SelectMany(a => a.GetTypes());
            Injection(serviceCollection, types);
            return serviceCollection;
        }
        // 注入逻辑
        private static void Injection(IServiceCollection serviceCollection, IEnumerable types)
        {
            foreach (var type in types)
            {
                var attribute = type.GetCustomAttribute();
                if (attribute == null) continue;
                switch (attribute.InjectionType)
                {
                    case InjectionType.Transient:
                        serviceCollection.AddTransient(type);
                        break;
                    case InjectionType.Scoped:
                        serviceCollection.AddScoped(type);
                        break;
                    case InjectionType.Singleton:
                        serviceCollection.AddSingleton(type);
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }
        }
    }
}