using EFCore7Study.DataService;

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.SqlServer;

namespace EFCore7Study.WebApi
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // Add services to the container.

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

            //注册服务:EFCore
            #region 注册服务:EFCore
            var connectString = builder.Configuration.GetConnectionString("SQLServer");
            var contextOptionsBuilder = new DbContextOptionsBuilder<AppDbContext>()
                .UseSqlServer(connectString)
                .EnableSensitiveDataLogging();
            var contextOptions = contextOptionsBuilder.Options;

            //方式一:默认构造,使用内部数据连接
            //builder.Services.AddScoped(provider => new AppDbContext());

            //方式二: 设置连接字符串属性
            //builder.Services.AddScoped(provider =>
            //{
            //    var db = new AppDbContext();
            //    db.ConnectString = connectString;
            //    return db;
            //});

            //方法三:使用 DbContextOptions 的构建函数 [比较推荐]
            //builder.Services.AddScoped<AppDbContext>(provider => new AppDbContext(contextOptions));

            //方式四:使用 AddDbContext 扩展方法 [官方推荐]
            //小问题:会覆盖之前方法的服务注册,猜测内部进行过去重复处理过,要验证请使用 GetServices 获取所有注册的服务。
            //解决:方法三放在方法四后面
            //builder.Services.AddDbContext<AppDbContext>(option =>
            //{
            //    //从配置中获取连接字符串
            //    option.UseSqlServer(connectString)
            //        .EnableSensitiveDataLogging();
            //});

            //方式五: 使用 DbContextFactory 工厂
            //注意:
            //  1、此方法与方法四都是注册的 AppDbContext对象,方法四默认为Scoped,此方式默认为单例,两者的冲突导致异常
            //  2、此方法与方法四,都会覆盖之前的 AppDbContext 注册
            //解决:
            //  1、此方法不与方法4同用,如果要同时使用,请使用方法1-3
            //  2、使此方法与方法四,应用相同生命周期
            //builder.Services.AddDbContextFactory<AppDbContext>(optionBuilder =>
            //{
            //    optionBuilder.UseSqlServer(connectString)
            //       .EnableSensitiveDataLogging();
            //});

            //使用自定的覆盖工厂的AppDbContext,但工厂本身的IDbContextFactory<AppDbContext>不会覆盖,可以分开使用。
            //builder.Services.AddScoped<AppDbContext>(provider => new AppDbContext(contextOptions));

            //方式六:使用 DbContextPool 池
            builder.Services.AddDbContextPool<AppDbContext>((provider, optionBuilder) =>
            {
                //provider.GetRequiredService<AppDbContext>();
                optionBuilder.UseSqlServer(connectString)
                   .EnableSensitiveDataLogging();
            }, poolSize: 2048);

            //方式七:使用连接池的工厂
            builder.Services.AddPooledDbContextFactory<AppDbContext>((serviceProvider, optionBuilder) =>
            {
                //serviceProvider.GetRequiredService<AppDbContext>();

                optionBuilder.UseSqlServer(connectString)
                   .EnableSensitiveDataLogging();
            }, poolSize: 1024);

            //使用自定的覆盖工厂的AppDbContext,但工厂本身的IDbContextFactory<AppDbContext>不会覆盖,可以分开使用。
            builder.Services.AddScoped(provider => new AppDbContext());

            //获取所有注册的服务(可没查看是否覆盖注册)
            //var dd = builder?.Services?.BuildServiceProvider().GetServices<AppDbContext>();
            #endregion

            #region 注册服务:EFCore2

            var contextOptionBuilder2 = new DbContextOptionsBuilder<AppDbContext2>()
                .UseSqlServer(connectString)
                .EnableSensitiveDataLogging();
            DbContextOptions<AppDbContext2>? contextOptions2 = contextOptionBuilder2.Options;

            //方法:使用 统一构建函数
            //builder.Services.AddScoped<AppDbContext2>(provider => new AppDbContext2(contextOptions));
            //或者
            builder?.Services.AddScoped(provider => new AppDbContext2(contextOptions2, connectString));

            //方式:使用 AddDbContext 扩展方法 [官方推荐]
            //builder.Services.AddDbContext<AppDbContext2>((server, option) =>
            //{
            //    //从配置中获取连接字符串
            //    //builder.Configuration.GetConnectionString("SQLServer");

            //    //设置
            //    option.UseSqlServer(connectString)
            //        .EnableSensitiveDataLogging();
            //});

            //方式: 使用 DbContextFactory 工厂
            //builder.Services.AddDbContextFactory<AppDbContext2>(optionBuilder =>
            //{
            //    optionBuilder.UseSqlServer(connectString)
            //       .EnableSensitiveDataLogging();
            //}, ServiceLifetime.Scoped);

            //或者
            //builder.Services.AddDbContextFactory<AppDbContext2>((provider, builder) =>
            //{


            //}, ServiceLifetime.Scoped);

            //方式:使用 DbContextPool 池
            //builder.Services.AddDbContextPool<AppDbContext2>(optionBuilder =>
            //{
            //    optionBuilder.UseSqlServer(connectString)
            //       .EnableSensitiveDataLogging();
            //});

            //方式:使用连接池的工厂
            //builder.Services.AddPooledDbContextFactory<AppDbContext2>(optionBuilder =>
            //{
            //    optionBuilder.UseSqlServer(connectString)
            //       .EnableSensitiveDataLogging();
            //});
            #endregion

            var app = builder!.Build();

            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

            app.UseAuthorization();


            app.MapControllers();

            app.Run();
        }
    }
}