using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;
using System.Reflection;
namespace FastGithub
{
    /// 
    /// 服务注册扩展
    /// 
    public static class ServiceCollectionExtensions
    {
        /// 
        /// 注册程序集下所有服务下选项
        /// 
        /// 
        /// 配置  
        /// 
        public static IServiceCollection AddServiceAndOptions(this IServiceCollection services, Assembly assembly, IConfiguration configuration)
        { 
            services.AddAttributeServices(assembly);
            services.AddAttributeOptions(assembly, configuration); 
            return services;
        }
        /// 
        /// 添加程序集下ServiceAttribute标记的服务
        /// 
        /// 
        ///  
        /// 
        private static IServiceCollection AddAttributeServices(this IServiceCollection services, Assembly assembly)
        {
            var implTypes = assembly
                .GetTypes()
                .Where(item => item.IsClass && item.IsAbstract == false)
                .ToArray();
            foreach (var implType in implTypes)
            {
                var attributes = implType.GetCustomAttributes(false);
                foreach (var attr in attributes)
                {
                    var serviceType = attr.ServiceType ?? implType;
                    if (services.Any(item => item.ServiceType == serviceType && item.ImplementationType == implType) == false)
                    {
                        var descriptor = ServiceDescriptor.Describe(serviceType, implType, attr.Lifetime);
                        services.Add(descriptor);
                    }
                }
            }
            return services;
        }
        /// 
        /// 添加程序集下OptionsAttribute标记的服务 
        /// 
        /// 
        ///  
        /// 
        private static IServiceCollection AddAttributeOptions(this IServiceCollection services, Assembly assembly, IConfiguration configuration)
        {
            foreach (var optionsType in assembly.GetTypes())
            {
                var optionsAttribute = optionsType.GetCustomAttribute();
                if (optionsAttribute != null)
                {
                    var key = optionsAttribute.SessionKey ?? optionsType.Name;
                    var section = configuration.GetSection(key);
                    OptionsBinder.Create(services, optionsType).Bind(section);
                }
            }
            return services;
        }
        /// 
        /// options绑定器
        /// 
        private abstract class OptionsBinder
        {
            public abstract void Bind(IConfiguration configuration);
            /// 
            /// 创建OptionsBinder实例
            /// 
            /// 
            /// 
            /// 
            public static OptionsBinder Create(IServiceCollection services, Type optionsType)
            {
                var binderType = typeof(OptionsBinderImpl<>).MakeGenericType(optionsType);
                var binder = Activator.CreateInstance(binderType, new object[] { services });
                return binder is OptionsBinder optionsBinder
                    ? optionsBinder
                    : throw new TypeInitializationException(binderType.FullName, null);
            }
            private class OptionsBinderImpl : OptionsBinder where TOptions : class
            {
                private readonly IServiceCollection services;
                public OptionsBinderImpl(IServiceCollection services)
                {
                    this.services = services;
                }
                public override void Bind(IConfiguration configuration)
                {
                    this.services.AddOptions().Bind(configuration);
                }
            }
        }
    }
}