using InboxIntel.Application.Abstractions; using InboxIntel.Domain.Enums; using InboxIntel.Infrastructure.Ai; using InboxIntel.Infrastructure.Analytics; using InboxIntel.Infrastructure.Cleanup; using InboxIntel.Infrastructure.Configuration; using InboxIntel.Infrastructure.Export; using InboxIntel.Infrastructure.Gmail; using InboxIntel.Infrastructure.Notifications; using InboxIntel.Infrastructure.Persistence; using InboxIntel.Infrastructure.Search; using InboxIntel.Infrastructure.Security; using InboxIntel.Infrastructure.Sync; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace InboxIntel.Infrastructure; public static class DependencyInjection { public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration config) { // EF Core / PostgreSQL services.AddDbContext(opt => opt.UseNpgsql(config.GetConnectionString("Postgres"), npg => npg.MigrationsAssembly(typeof(AppDbContext).Assembly.FullName))); services.AddScoped(sp => sp.GetRequiredService()); // Options services.Configure(config.GetSection(GoogleOAuthOptions.SectionName)); services.Configure(config.GetSection(GmailSyncOptions.SectionName)); services.Configure(config.GetSection(AiOptions.SectionName)); services.Configure(config.GetSection(SmtpOptions.SectionName)); services.Configure(config.GetSection(DigestOptions.SectionName)); // Security services.AddSingleton(); // Gmail services.AddScoped(); services.AddScoped(); // Background sync queue (singleton) + its worker. services.AddSingleton(); services.AddSingleton(sp => sp.GetRequiredService()); services.AddHostedService(); // Core services services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); // Notifications (digest emails) services.AddScoped(); services.AddScoped(); services.AddHostedService(); // HTTP clients // V-01: do NOT follow redirects — a validated external URL must not be able to // 3xx-redirect into an internal target after SafeHttpGuard has checked it. services.AddHttpClient("unsubscribe", c => c.Timeout = TimeSpan.FromSeconds(15)) .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler { AllowAutoRedirect = false }); services.AddHttpClient("ollama"); services.AddHttpClient("openai"); // AI provider selected by configured mode. var aiMode = config.GetSection(AiOptions.SectionName).GetValue("Mode"); switch (aiMode) { case AiProviderMode.LocalOllama: services.AddScoped(); break; case AiProviderMode.CloudOpenAi: services.AddScoped(); break; default: services.AddScoped(); break; } services.AddScoped(); // Background worker (daily incremental sync + aggregate refresh) services.AddHostedService(); return services; } }