using EntityFramework.Exceptions.SqlServer;
using IRaCIS.Core.Application.Triggers;
using IRaCIS.Core.Application.Triggers.AfterSaveTrigger;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Infra.EFCore.Interceptor;
using Medallion.Threading;
using Medallion.Threading.SqlServer;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace IRaCIS.Core.API
{
    public static class EFSetup
    {
        public static void AddEFSetup(this IServiceCollection services, IConfiguration configuration, string envName)
        {

            services.AddHttpContextAccessor();
            services.AddScoped<IUserInfo, UserInfo>();
            services.AddScoped<ISaveChangesInterceptor, AuditEntityInterceptor>();
            services.AddScoped<ISaveChangesInterceptor, DispatchDomainEventsInterceptor>();


            // First, register a pooling context factory as a Singleton service, as usual:

            //这个注入没有成功--注入是没问题的,构造函数也只是支持参数就好,错在注入的地方不能写DbContext
            //Web程序中通过重用池中DbContext实例可提高高并发场景下的吞吐量, 这在概念上类似于ADO.NET Provider原生的连接池操作方式,具有节省DbContext实例化成本的优点
            services.AddDbContext<IRaCISDBContext>((sp, options) =>
            {

                // 在控制台
                //public static readonly ILoggerFactory MyLoggerFactory    = LoggerFactory.Create(builder => { builder.AddConsole(); });
                var logFactory = LoggerFactory.Create(builder => { builder.AddDebug(); });

                var dbType = configuration.GetSection("ConnectionStrings:Db_Type").Value;
                if (!string.IsNullOrWhiteSpace(dbType) && dbType == "pgsql")
                {
                    options.UseNpgsql(configuration.GetSection("ConnectionStrings:RemoteNew").Value, contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());

                }
                else
                {
                    options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value, contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());
                }


                //迁移的时候,不生成外键
                options.ReplaceService<IMigrationsSqlGenerator, NoForeignKeyMigrationsSqlGenerator>();

                options.UseLoggerFactory(logFactory);

                options.UseExceptionProcessor();

                options.EnableSensitiveDataLogging();

                options.AddInterceptors(new QueryWithNoLockDbCommandInterceptor());
                options.AddInterceptors(sp.GetServices<ISaveChangesInterceptor>());

                options.UseProjectables();

                //options.UseTriggers(triggerOptions => triggerOptions.AddAssemblyTriggers(typeof(SubjectVisitTrigger).Assembly));


                options.UseTriggers(triggerOptions =>
                {
                    triggerOptions.AddTrigger<SubjectTrigger>();
                    triggerOptions.AddTrigger<ChallengeStateTrigger>();
                    triggerOptions.AddTrigger<SubjectVisitTrigger>();
                    triggerOptions.AddTrigger<SubjectVisitScanDateTrigger>();
                    triggerOptions.AddTrigger<TrialCriterionSignTrigger>();
                    triggerOptions.AddTrigger<TableQuestionRowTrigger>();
                    //triggerOptions.AddTrigger<AddlTrialUserTrigger>();
                    triggerOptions.AddTrigger<VisitTaskIsFrontTaskNeedSignButNotSignTrigger>();
                    triggerOptions.AddTrigger<JudgeVisitTaskTrigger>();

                    triggerOptions.AddTrigger<UserLogTrigger>();

                    triggerOptions.AddTrigger<UserAddTrigger>();

                    triggerOptions.AddTrigger<UserLogAfterTrigger>();

                    triggerOptions.AddTrigger<IdenttiyUserRoleInfoTrigger>();

                    

                });
            });

            // Register an additional context factory as a Scoped service, which gets a pooled context from the Singleton factory we registered above,
            //services.AddScoped<IRaCISDBScopedFactory>();

            //// Finally, arrange for a context to get injected from our Scoped factory:
            //services.AddScoped(sp => sp.GetRequiredService<IRaCISDBScopedFactory>().CreateDbContext());

            //注意区分 easy caching 也有  IDistributedLockProvider
            services.AddSingleton<IDistributedLockProvider>(sp =>
            {
                //var connection = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]!);

                return new SqlDistributedSynchronizationProvider(configuration.GetSection("ConnectionStrings:RemoteNew").Value);
            });

            //services.AddAssemblyTriggers(typeof(SubjectVisitImageDateTrigger).Assembly);
        }
    }
}