using AMREZ.EOP.Abstractions.Applications.Tenancy; using AMREZ.EOP.Abstractions.Applications.UseCases.Authentications; using AMREZ.EOP.Abstractions.Applications.UseCases.HumanResources; using AMREZ.EOP.Abstractions.Applications.UseCases.Tenancy; using AMREZ.EOP.Abstractions.Infrastructures.Common; using AMREZ.EOP.Abstractions.Infrastructures.Repositories; using AMREZ.EOP.Abstractions.Security; using AMREZ.EOP.Abstractions.Storage; using AMREZ.EOP.Application.UseCases.Authentications; using AMREZ.EOP.Application.UseCases.HumanResources; using AMREZ.EOP.Application.UseCases.Tenancy; using AMREZ.EOP.Domain.Shared.Tenancy; using AMREZ.EOP.Infrastructures.Data; using AMREZ.EOP.Infrastructures.Options; using AMREZ.EOP.Infrastructures.Repositories; using AMREZ.EOP.Infrastructures.Security; using AMREZ.EOP.Infrastructures.Storage; using AMREZ.EOP.Infrastructures.Tenancy; using AMREZ.EOP.Infrastructures.UnitOfWork; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using StackExchange.Redis; namespace AMREZ.EOP.Infrastructures.DependencyInjections; public static class ServiceCollectionExtensions { public static IServiceCollection AddInfrastructure(this IServiceCollection services) { services.AddHttpContextAccessor(); // Options services.AddOptions() .BindConfiguration("Connections") .ValidateOnStart(); // Tenancy core (order matters for AddDbContext factory resolution) services.AddSingleton(sp => { var map = new TenantMap(); var opts = sp.GetRequiredService>().Value; map.UpsertTenant("public", new TenantContext { Id = "public", Schema = "public", ConnectionString = string.IsNullOrWhiteSpace(opts.DefaultConnection) ? null : opts.DefaultConnection, Mode = TenantMode.Rls }); return map; }); services.AddHostedService(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); // DbContext (attach RLS/search_path interceptors) services.AddDbContext((sp, o) => { var cfg = sp.GetRequiredService>().Value; o.UseNpgsql(cfg.DefaultConnection); o.AddInterceptors( sp.GetRequiredService(), sp.GetRequiredService() ); }); // Db scope / UoW services.AddScoped(); services.AddScoped(); services.AddScoped(); // Security services.AddScoped(); // Repositories — Auth & HR แยกกัน services.AddScoped(); services.AddScoped(); services.AddScoped(); // UseCases — Authentication services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); // UseCases — HR services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); // UseCases — Tenancy services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); // Redis (optional) services.AddSingleton(sp => { var opts = sp.GetRequiredService>().Value; var conn = opts.RedisConnection; if (string.IsNullOrWhiteSpace(conn)) return null; try { var cfg = ConfigurationOptions.Parse(conn, true); cfg.AbortOnConnectFail = false; cfg.ConnectTimeout = 1000; cfg.SyncTimeout = 1000; var mux = ConnectionMultiplexer.Connect(cfg); return mux.IsConnected ? mux : null; } catch { return null; } }); return services; } }