using AspectCore.Extensions.DependencyInjection;
using HealthMonitor.Common;
using HealthMonitor.Common.helper;
using HealthMonitor.Core.Cache;
using HealthMonitor.Core.Context;
using HealthMonitor.Core.Dal.EfCoreImpl;
using HealthMonitor.Core.Dal;
using HealthMonitor.Core.Dal.Factory;
using HealthMonitor.Core.DbLog;
using HealthMonitor.Core.Operator;
using HealthMonitor.Core.Operator.Redis;
using HealthMonitor.Model.Config;
using HealthMonitor.Service.Biz.db;
using HealthMonitor.WebApi.Configs;
using HealthMonitor.WebApi.DbLog;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using HealthMonitor.WebApi.Swagger;
using HealthMonitor.Service.Cache;
using TelpoDataService.Util.Clients;
using HealthMonitor.Service.Sub;
using HealthMonitor.Service.Resolver;
using HealthMonitor.Service.Resolver.Factory;
using HealthMonitor.Service.Resolver.Interface;
using Serilog;
using Serilog.Core;
using HealthMonitor.WebApi.HttpLog;
using Microsoft.Extensions.Http;
using Microsoft.Extensions.DependencyInjection.Extensions;
using HealthMonitor.Service.Etcd;
using HealthMonitor.WebApi.Middleware;
using HealthMonitor.Service.Biz;
using HealthMonitor.Service.MessageQueue.Kafka;
using HealthMonitor.Service.MessageQueue;

namespace HealthMonitor.WebApi
{
    public class Program
    {
        public static void Main(string[] args)
        {

            //选择配置文件appsetting.json
            var config = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .Build();
            Log.Logger = new LoggerConfiguration()
                .ReadFrom.Configuration(config).Enrich.WithThreadInfo()
                .CreateLogger();


            var builder = WebApplication.CreateBuilder(args);

            // Add services to the container.
          

            builder.Services.AddHttpClient(Consts.DEFAULT_HTTPCLIENT_NAME, c =>
            {
                c.Timeout = TimeSpan.FromSeconds(60);   //超时限制
                c.DefaultRequestHeaders.Add("Accept", "application/json");
                //c.DefaultRequestHeaders.Connection.Add("keep-alive");
            });

           // builder.Services.Configure<TDengineServiceConfig>(builder.Configuration.GetSection("TDengineServiceConfig"));

            builder.Services.AddSingleton<HttpHelper>();
            builder.Services.AddSingleton<TDengineService>();

            builder.Services.AddControllers();
            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();


            #region scoped MySQL 数据库
            builder.Services // gps_card
                .AddDbContextPool<GpsCardContext>((sp, options) =>
            {
                var loggerFactory = sp.GetRequiredService<EfCoreLoggerFactory>();
                var mySqlCon = builder.Configuration.GetConnectionString("GpsCard_Connection_String");
                var serverVersion = ServerVersion.AutoDetect(mySqlCon);
                options.UseMySql(mySqlCon, serverVersion)
                    .UseLoggerFactory(loggerFactory);
            }, poolSize: 64) // health_monitor
                .AddDbContextPool<HealthMonitorContext>((sp, options) =>
                {
                    var loggerFactory = sp.GetRequiredService<EfCoreLoggerFactory>();
                  
                    var mySqlCon = builder.Configuration.GetConnectionString("HealthMonitor_Connection_String");
                    var serverVersion = ServerVersion.AutoDetect(mySqlCon);
                    options.UseMySql(mySqlCon, serverVersion)
                        .UseLoggerFactory(loggerFactory);
                }, poolSize: 64);

            builder.Services
                .AddScoped<IGpsCardDataAccessor, EfCoreDataAccessor>(sp =>
            {
                var context = sp.GetRequiredService<GpsCardContext>();
                return new EfCoreDataAccessor(context);
            })
                .AddScoped<IHealthMonitorDataAccessor, EfCoreDataAccessor>(sp =>
            {
                var context = sp.GetRequiredService<HealthMonitorContext>();
                return new EfCoreDataAccessor(context);
            });


            //builder.Services.AddDbContextPool<HealthMonitorContext>((sp, options) =>
            //{
            //    var loggerFactory = sp.GetRequiredService<EfCoreLoggerFactory>();
            //    options.UseMySql(builder.Configuration.GetConnectionString("GpsCard_Connection_String"))
            //        .UseLoggerFactory(loggerFactory);
            //}, poolSize: 64);

            //builder.Services.AddScoped<IHealthMonitorDataAccessor, EfCoreDataAccessor>(sp =>
            //{
            //    var context = sp.GetRequiredService<HealthMonitorContext>();
            //    return new EfCoreDataAccessor(context);
            //});


            #endregion

            #region AOP
            //builder.Services.Configure<RedisConfig>(builder.Configuration.GetSection("Redis"));

            builder.Services
                .Configure<ApiBehaviorOptions>(options =>
            {
                options.SuppressModelStateInvalidFilter = true;
            })
                .Configure<RedisConfig>(builder.Configuration.GetSection("Redis"))
                .Configure<TDengineServiceConfig>(builder.Configuration.GetSection("TDengineServiceConfig"))
                .Configure<ServiceConfig>(builder.Configuration.GetSection("ServiceConfig"))
                .Configure<BoodPressResolverConfig>(builder.Configuration.GetSection("BoodPressResolverConfig"));


            builder.Services
                .AddSingleton<IEfCoreLoggerProvider, EfCoreLogProvider>()
                .AddSingleton<IDurableEntityManager, DurableEntityManager>()
                .AddSingleton<EfCoreLoggerFactory>(sp =>
                {
                    var provider = sp.GetRequiredService<IEfCoreLoggerProvider>();
                    return new EfCoreLoggerFactory(new[] { provider });
                });
            //builder.Services.AddSingleton<IDurableEntityManager, DurableEntityManager>();

            //builder.Services.AddSingleton<EfCoreLoggerFactory>(sp =>
            //{
            //    var provider = sp.GetRequiredService<IEfCoreLoggerProvider>();
            //    return new EfCoreLoggerFactory(new[] { provider });
            //});


            builder.Services
                .AddSingleton<GpsCardAccessorFactory>()
                .AddSingleton<HealthMonitorAccessorFactory>();
            //builder.Services.AddSingleton<HealthMonitorAccessorFactory>();

            builder.Services
                .AddSingleton<IGpsCardOperatorManager, GpsCardOperatorRedisManager>()
                .AddSingleton<IHealthMonitorOperatorManager, HealthMonitorOperatorRedisManager>();
            //builder.Services.AddSingleton<IHealthMonitorOperatorManager, HealthMonitorOperatorRedisManager>();
            
            //用AspectCore替换默认的IOC容器
            builder.Host.UseServiceProviderFactory(new DynamicProxyServiceProviderFactory());
            #endregion

            #region Cache
            builder.Services
                .AddSingleton<PersonCacheManager>()
                .AddSingleton<DeviceCacheManager>()
                .AddSingleton<FhrPhrMapCacheManager>()
                .AddSingleton<FetalMovementNormalValueRangeCacheManager>()
                .AddSingleton<BloodPressReferenceValueCacheManager>();

            #endregion

            #region TelpoDataServices

            builder.Services.AddTelpoDataServices(opt =>
            {
                opt.TelpoDataUrl = builder.Configuration.GetSection("ServiceConfig:TelpoDataUrl").Value;
            });

            #endregion

            #region  Worker
            builder.Services.AddSingleton<MsgQueueManager>();
            builder.Services.AddSingleton<IResolverFactory, ResolverFactory>();
            builder.Services.AddSingleton<BloodpressResolver>();
            builder.Services.AddSingleton<PregnancyHeartRateResolver>();
            builder.Services.AddSingleton<PackageProcess>();

            builder.Services
                .AddSingleton<TDengineDataSubcribe>()
                .AddSingleton<IotApiService>()
                .AddSingleton<EtcdService>()
                .AddHostedService<Worker>();
            #endregion

            #region kafka
            builder.Services.AddSingleton<MqProcessLogic>();
            builder.Services.AddSingleton<KafkaService>();
            #endregion

            builder.Host.UseSerilog();

            builder.Services.Replace(ServiceDescriptor.Singleton<IHttpMessageHandlerBuilderFilter, CustomLoggingFilter>());




            // Register the Swagger generator, defining 1 or more Swagger documents
            builder.Services.AddSwaggerGen(c =>
            {
                //c.SwaggerDoc(AppConsts.SWAGGER_DOC_GpsCard, new OpenApiInfo { Title = "GpsCard模块", Version = "v1", Description = "gps_card数据库服务" });                //分组显示
                c.SwaggerDoc(AppConsts.SWAGGER_DOC_HealthMonitor, new OpenApiInfo { Title = "HealthMonitor模块", Version = "v1", Description = "health_monitor数据库服务" });    //分组显示


                c.DocumentFilter<EnumDocumentFilter>();

                //var utilXmlFile = Path.Combine(AppContext.BaseDirectory, "HealthMonitor.Util.xml");
                //var webapiXmlFile = Path.Combine(AppContext.BaseDirectory, "HealthMonitor.WebApi.xml");

                //c.IncludeXmlComments(utilXmlFile, true);
                //c.IncludeXmlComments(webapiXmlFile, true);
            });


   


            var app = builder.Build();

            // Configure the HTTP request pipeline.
            //if (app.Environment.IsDevelopment())
            //{
            //    app.UseSwagger();
            //    app.UseSwaggerUI();
            //}
            string prefix = string.Empty;




            if (!app.Environment.IsDevelopment())
            {
                //prefix = optConfigAppSettings.Value.NginxPrefix;
                //if (string.IsNullOrWhiteSpace(prefix)) prefix = SERVICE_PREFIX;
                prefix = "hm";
            }

            // Enable middleware to serve generated Swagger as a JSON endpoint.

            app.UseSwagger(c =>
            {
                c.PreSerializeFilters.Add((swagger, httpReq) =>
                {
                    var scheme = httpReq.Headers.TryGetValue("X-Forwarded-Proto", out var v2) ? v2.ToString() : httpReq.Scheme;
                    swagger.Servers = new List<OpenApiServer> { new OpenApiServer { Url = $"{scheme}://{httpReq.Host}/{prefix}" } };
                });
                c.RouteTemplate = "/{documentName}/api-docs/";
            });
            // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
            // specifying the Swagger JSON endpoint.
            app.UseSwaggerUI(c =>
            {
                string sub = string.IsNullOrEmpty(prefix) ? "" : $"/{prefix}";
                //c.SwaggerEndpoint($"{sub}/{AppConsts.SWAGGER_DOC_GpsCard}/api-docs/", "GpsCard模块");            //分组显示
                c.SwaggerEndpoint($"{sub}/{AppConsts.SWAGGER_DOC_HealthMonitor}/api-docs/", "HealthMonitor模块");    //分组显示
                c.RoutePrefix = string.Empty;
            });
            



            // redis default
            var csredis = new CSRedis.CSRedisClient(app.Services.GetService<IOptions<RedisConfig>>()!.Value.ToString());
            RedisHelper.Initialization(csredis);

            // redis db7
            var csredisDb7Con = app.Services.GetService<IOptions<RedisConfig>>()!.Value;
            csredisDb7Con.DefaultDatabase = 7;
            csredisDb7Con.Prefix = "TELPO";
            var csredisDb7 = new CSRedis.CSRedisClient(csredisDb7Con.ToString());
            RedisHelperDb7.Initialization(csredisDb7);

            // redis db10
            var csredisDb10Con = app.Services.GetService<IOptions<RedisConfig>>()!.Value;
            csredisDb10Con.DefaultDatabase = 10;
            csredisDb10Con.Prefix = "_GW_";
            var csredisDb10 = new CSRedis.CSRedisClient(csredisDb10Con.ToString());
            RedisHelperDb10.Initialization(csredisDb10);


            app.UseHttpsRedirection();

            app.UseAuthorization();

            app.UseMiddleware<LoggingMiddleware>();

            app.MapControllers();

            app.Run();
        }
    }
}