using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;
using System.Reflection;
using XYY.Core.Standard.ExcelHelper.MSExcelHelper;
using XYY.Core.Standard.AliYun;
using XYY.Core.Standard.Data.Infrastructure;
using EasyNetQ;
using XYY.TaskTrack.Standard;
using Serilog;
using StackExchange.Redis;
using XYY.Core.Standard.Data.Redis;
using XYY.Core.Standard.FiddlerClient;

namespace XYY.Service.Standard.RegionService
{

    public enum DistributedCacheType
    {
        Memory = 0,
        Redis = 1
    }


    public class ServiceOption
    {

        public bool NoService
        {
            get; set;
        }

        public string PBESConnection
        {
            get; set;
        }

        public string MsgESConnection
        {
            get; set;
        }

        /// <summary>
        /// 是否开启缓存
        /// </summary>
        public DistributedCacheType CacheType
        {
            get; set;
        }

        /// <summary>
        /// 是否使用事务支持
        /// </summary>
        public bool USEDBTransferAsMVC
        {
            get; set;
        }

        /// <summary>
        /// 传入连接并启用头程信息
        /// </summary>
        public string FirstESConnection
        {
            get; set;
        }
        /// <summary>
        /// 手动补充头程数据
        /// </summary>
        public string FirstESConnection2
        {
            get; set;
        }

        /// <summary>
        /// 是否启用Rebbit
        /// </summary>
        public bool UseRabbit
        {
            get; set;
        }
        public string FinanceChargesRedisConnection
        {
            get; set;
        }
        public string RedisConnection
        {
            get; set;
        }


        public bool UseTrackingPUSHRedis
        {
            get; set;
        }
        public bool UseFinanceChargesRedis
        {
            get; set;
        }
        public string SqlServiceConnection
        {
            get; set;
        }

        public AliYunConfig AliYunConfig
        {
            get; set;
        }
        public bool OpenChannelApi
        {
            get; set;
        }
        /// <summary>
        /// 开启捕获
        /// </summary>
        public bool UseFiddler
        {
            get; set;
        }
    }

    public static class DefaultConfig
    {
        /// <summary>
        /// DBConnectionStrings:SqlService
        /// </summary>
        public static string SqlServiceConnectionKey => "DBConnectionStrings:SqlService";

        public static string ESUrlKey => "DBConnectionStrings:ESUrl";

        public static string AliYunBucketName => "aliyun:AliYunBucketName";
        public static string AliYunEndPoint => "aliyun:aliYunEndPoint";

        public static string AliYunKeyId => "aliyun:aliYunKeyId";

        public static string AliYunKeySecret => "aliyun:aliYunKeySecret";

        public static string AliYunBasePath => "aliyun:BasePath";

        public static string AliYunPubEndPoint => "aliyun:aliYunPubEndPoint";

        public static string RabbitConnectionKey => "DBConnectionStrings:RabbitConnection";
        public static string RedisConnectionKey => "DBConnectionStrings:RedisCacheUrl";

    }

    public static class ServiceRegion
    {
        public static IServiceCollection AddDataService(this IServiceCollection services)
        {
            #region 依赖注入
            //services.AddScoped<IUserService, UserService>();

            string[] regeionTypes = new string[]
            {
                "XYY.Data.Standard.dll",
                "XYY.Data.Standard.User.dll",
                "XYY.Data.Standard.Customer.dll",
                "XYY.Data.Standard.Charging.dll"
            };
            var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory;
            var referencedAssemblies = System.IO.Directory.GetFiles(path, "*.dll").Where(x =>
            regeionTypes.Contains(System.IO.Path.GetFileName(x)))
            .Select(Assembly.LoadFrom).ToArray();
            var types = referencedAssemblies
                .SelectMany(a => a.DefinedTypes)
                .Select(type => type.AsType())
                .Where(x =>
                x.Name.EndsWith("Repository")
                ).ToArray();
            var implementTypes = types.Where(x => x.IsClass).ToArray();
            var interfaceTypes = types.Where(x => x.IsInterface).ToArray();
            foreach (var implementType in implementTypes)
            {
                var interfaceType = interfaceTypes.FirstOrDefault(x => x.IsAssignableFrom(implementType));
                if (interfaceType != null)
                    services.AddScoped(interfaceType, implementType);
            }

            #endregion

            return services;
        }

        public static IServiceCollection AddAliyunService(this IServiceCollection services, IConfiguration Configuration)
        {

            if (!string.IsNullOrEmpty(Configuration[DefaultConfig.AliYunPubEndPoint]))
            {
                var AliYunConfig = new Core.Standard.AliYun.AliYunConfig
                {
                    AliYunBucketName = Configuration[DefaultConfig.AliYunBucketName],
                    AliYunEndPoint = Configuration[DefaultConfig.AliYunEndPoint],
                    AliYunKeyId = Configuration[DefaultConfig.AliYunKeyId],
                    AliYunKeySecret = Configuration[DefaultConfig.AliYunKeySecret],
                    BasePath = Configuration[DefaultConfig.AliYunBasePath],
                    CDNEndPoint = Configuration[DefaultConfig.AliYunPubEndPoint],
                };
                services.AddSingleton<IAliYunPostFileSerivce>(x => new AliYunPostFileSerivce(AliYunConfig));
            }
            return services;
        }

        /// <summary>
        /// 添加Service层注入
        /// </summary>
        /// <param name="services"></param>
        /// <param name="serviceName">XYY.Service.Standard.{serviceName}</param>
        /// <returns></returns>
        public static IServiceCollection AddStandardService(this IServiceCollection services, string serviceName)
        {

            var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory;
            var referencedAssemblies = System.IO.Directory.GetFiles(path, $"XYY.Service.Standard.{serviceName}.dll")
                .Where(x => !System.IO.Path.GetFileName(x).Equals("XYY.Service.Standard.RegionService.dll"))
            .Select(Assembly.LoadFrom).ToArray();
            var types = referencedAssemblies
                .SelectMany(a => a.DefinedTypes)
                .Select(type => type.AsType())
                .Where(x =>
                x.Name.EndsWith("Service")
                || x.Name.EndsWith("Api")
                ).ToArray();
            var implementTypes = types.Where(x => x.IsClass).ToArray();
            var interfaceTypes = types.Where(x => x.IsInterface).ToArray();
            foreach (var implementType in implementTypes)
            {
                var allInterfaceTypes = interfaceTypes.Where(x => x.IsAssignableFrom(implementType));
                if (allInterfaceTypes?.Any() == true)
                {
                    foreach (var interfaceType in allInterfaceTypes)
                    {
                        services.AddScoped(interfaceType, implementType);
                    }
                }

            }
            return services;
        }

        /// 若需要支持事务服务、方法计时服务请配置 spectCore.Extensions.DependencyInjection 框架
        /// 启动项添加配置： UseServiceProviderFactory(x => new DynamicProxyServiceProviderFactory())
        public static IServiceCollection AddXYYService(this IServiceCollection services, ServiceOption serviceOption, IConfiguration Configuration)
        {

            if (!string.IsNullOrEmpty(Configuration[DefaultConfig.AliYunPubEndPoint]))
            {
                serviceOption.AliYunConfig = new Core.Standard.AliYun.AliYunConfig
                {
                    AliYunBucketName = Configuration[DefaultConfig.AliYunBucketName],
                    AliYunEndPoint = Configuration[DefaultConfig.AliYunEndPoint],
                    AliYunKeyId = Configuration[DefaultConfig.AliYunKeyId],
                    AliYunKeySecret = Configuration[DefaultConfig.AliYunKeySecret],
                    BasePath = Configuration[DefaultConfig.AliYunBasePath],
                    CDNEndPoint = Configuration[DefaultConfig.AliYunPubEndPoint],
                };
            }

            if (serviceOption != null && serviceOption.AliYunConfig != null)
            {
                //阿里云
                services.AddSingleton<IAliYunPostFileSerivce>(x => new AliYunPostFileSerivce(serviceOption.AliYunConfig));
            }
            //excel
            services.AddSingleton<IExcelHelper, MSExcelHelper>();

            if (serviceOption != null && !string.IsNullOrEmpty(serviceOption.PBESConnection))
            {
                //pb
                //services.AddSingleton<IPerformanceDB>(x => new ESPerformanceDB(serviceOption.PBESConnection));
            }

            if (serviceOption != null && serviceOption.UseRabbit)
            {
                //Rebbit服务注册
                try
                {
                    services.AddSingleton(x => RabbitHutch.CreateBus(Configuration[DefaultConfig.RabbitConnectionKey]));
                    services.AddSingleton<IMQManager, MQManager>();
                }
                catch (Exception ex)
                {
                    Log.Error("服务注册失败" + ex.Message);
                }
            }



            if (serviceOption != null)
            {
                //缓存
                switch (serviceOption.CacheType)
                {
                    case DistributedCacheType.Memory:
                        services.AddDistributedMemoryCache();
                        break;
                    case DistributedCacheType.Redis:
                        services.AddDistributedRedisCache(x =>
                        {
                            x.Configuration = serviceOption.RedisConnection;
                            x.ConfigurationOptions = new StackExchange.Redis.ConfigurationOptions
                            {
                                Password = "12345",
                            };
                            x.ConfigurationOptions.EndPoints.Add(serviceOption.RedisConnection);
                        });
                        break;
                }
                //缓存 
            }

            //计费缓存
            if (serviceOption != null && serviceOption.UseFinanceChargesRedis)
            {
                services.AddSingleton(x => new RedisHelper(serviceOption.FinanceChargesRedisConnection, "FinanceChargesRedis", "r-wz9o30bx758o8jhbra:100Ep*dp", 2));
            }
            if (serviceOption != null && serviceOption.UseTrackingPUSHRedis)
            {
                services.AddSingleton(x => new RedisHelper(serviceOption.RedisConnection, "TrackingPUSHRedis", "r-wz9o30bx758o8jhbra:100Ep*dp", 3));
            }
            if (serviceOption != null && !string.IsNullOrEmpty(serviceOption.SqlServiceConnection))
            {
                //数据                
                services.AddDB(serviceOption.SqlServiceConnection);
                AddDataService(services);
            }

            if (serviceOption != null && serviceOption.USEDBTransferAsMVC)
            {
                //事务
                services.ConfigAspectCore("Repository");
                services.AddMvcCore(x =>
                {
                    x.Filters.Add<ApiExceptionAcitonFilterAttribute>();
                    x.Filters.Add<ApiActionFilterAttribute>();
                });
            }


            if (serviceOption == null || !serviceOption.NoService)
            {
                try
                {
                    var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory;
                    var referencedAssemblies = System.IO.Directory.GetFiles(path, "XYY.Service.Standard.*.dll")
                        .Where(x => !System.IO.Path.GetFileName(x).Equals("XYY.Service.Standard.RegionService.dll"))
                    .Select(Assembly.LoadFrom).ToArray();
                    var types = referencedAssemblies
                        .SelectMany(a => a.DefinedTypes)
                        .Select(type => type.AsType())
                        .Where(x =>
                        x.Name.EndsWith("Service")
                        || x.Name.EndsWith("Api")
                        ).ToArray();
                    var implementTypes = types.Where(x => x.IsClass).ToArray();
                    var interfaceTypes = types.Where(x => x.IsInterface).ToArray();
                    foreach (var implementType in implementTypes)
                    {
                        if (implementType.FullName == "XYY.Service.Standard.ChannelApi.Ultidel.Api")
                        {

                        }
                        //var dd = interfaceTypes.Where(x => x.IsAssignableFrom(implementType));
                        var allInterfaceTypes = interfaceTypes.Where(x => x.IsAssignableFrom(implementType));
                        if (allInterfaceTypes?.Any() == true)
                        {
                            foreach (var interfaceType in allInterfaceTypes)
                            {
                                services.AddScoped(interfaceType, implementType);
                            }
                        }

                    }
                }
                catch
                {

                }
            }
            //更改注入方式，注意需要取消订单的api，仅使用Repository 不用services，不能产生依赖关系
            //注入处理比较麻烦，尽可能让api纯净
            if (serviceOption == null || serviceOption.OpenChannelApi)
            {
                string[] regeionTypes = new string[]
                  {
                        "XYY.Data.Standard.dll",
                        "XYY.Service.Standard.ChannelApi.dll",
                  };
                string[] fullNames = new string[] { "XYY.Data.Standard.Order", "XYY.Data.Standard.Channel", "XYY.Service.Standard.ChannelApi.Frayun.Api", "XYY.Service.Standard.ChannelApi.SKPB.Api", "XYY.Service.Standard.ChannelApi.MIQ.Api", "XYY.Service.Standard.ChannelApi.Winit.LMAApi", "XYY.Service.Standard.ChannelApi.Winit.ISPApi", "XYY.Service.Standard.ChannelApi.Ultidel" };
                var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory;
                var referencedAssemblies = System.IO.Directory.GetFiles(path, "*.dll")
                    .Where(x => regeionTypes.Contains(System.IO.Path.GetFileName(x)))
                .Select(Assembly.LoadFrom).ToArray();
                var types = referencedAssemblies
                    .SelectMany(a => a.DefinedTypes)
                    .Select(type => type.AsType())
                    .Where(x => fullNames.Any(p => x.FullName.Contains(p))
                    || x.Name.Contains("IBaseApi")
                    ).ToArray();
                var implementTypes = types.Where(x => x.IsClass).ToArray();
                var interfaceTypes = types.Where(x => x.IsInterface).ToArray();
                foreach (var implementType in implementTypes)
                {
                    var interfaceType = interfaceTypes.FirstOrDefault(x => x.IsAssignableFrom(implementType));
                    if (interfaceType != null)
                        services.AddSingleton(interfaceType, implementType);
                }
            }

            var fiddlerLog = new LoggerConfiguration()
                .MinimumLevel.Warning()
                .MinimumLevel.Override("LogginService", Serilog.Events.LogEventLevel.Warning)
                .Enrich.FromLogContext()
                .WriteTo.Seq("http://47.244.232.78:5341/")
                .WriteTo.Debug().CreateLogger();


            services.AddLogging(logging =>
            {
                logging.AddSerilog(fiddlerLog);
            });

            //注入访问监听
            if (serviceOption != null && serviceOption.UseFiddler)
            {
                services.AddSingleton<FiddlerClient>();
            }
            return services;
        }

    }
}
