using Microsoft.EntityFrameworkCore;
using DramaLing.Api.Data;
using DramaLing.Api.Services;
using DramaLing.Api.Services.Caching;
using DramaLing.Api.Services.Infrastructure.Caching;
using DramaLing.Api.Services.AI.Generation;
using DramaLing.Api.Services.AI.Gemini;
using DramaLing.Api.Services.Storage;
using DramaLing.Api.Contracts.Repositories;
using DramaLing.Api.Repositories;
using DramaLing.Api.Contracts.Services.Core;
using DramaLing.Api.Models.Configuration;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Extensions.Options;
using System.Text;
namespace DramaLing.Api.Extensions;
///
/// 服務集合擴展方法,用於組織和模組化依賴注入配置
///
public static class ServiceCollectionExtensions
{
///
/// 配置資料庫服務
///
public static IServiceCollection AddDatabaseServices(this IServiceCollection services, IConfiguration configuration)
{
var useInMemoryDb = Environment.GetEnvironmentVariable("USE_INMEMORY_DB") == "true";
if (useInMemoryDb)
{
services.AddDbContext(options =>
options.UseSqlite("Data Source=:memory:"));
}
else
{
var connectionString = Environment.GetEnvironmentVariable("DRAMALING_DB_CONNECTION")
?? configuration.GetConnectionString("DefaultConnection")
?? "Data Source=dramaling_test.db";
services.AddDbContext(options =>
options.UseSqlite(connectionString));
}
return services;
}
///
/// 配置 Repository 服務
///
public static IServiceCollection AddRepositoryServices(this IServiceCollection services)
{
services.AddScoped(typeof(IRepository<>), typeof(BaseRepository<>));
services.AddScoped();
services.AddScoped();
services.AddScoped();
return services;
}
///
/// 配置快取服務
///
public static IServiceCollection AddCachingServices(this IServiceCollection services)
{
services.AddMemoryCache();
// 快取組件
services.AddSingleton();
services.AddSingleton();
services.AddScoped();
// 快取提供者 - 使用具名註冊
services.AddScoped(provider =>
{
var memoryCache = provider.GetRequiredService();
var logger = provider.GetRequiredService>();
var databaseCacheManager = provider.GetRequiredService();
var strategyManager = provider.GetRequiredService();
var memoryProvider = new MemoryCacheProvider(
memoryCache,
provider.GetRequiredService>());
ICacheProvider? distributedProvider = null;
var distributedCache = provider.GetService();
if (distributedCache != null)
{
distributedProvider = new DistributedCacheProvider(
distributedCache,
provider.GetRequiredService(),
provider.GetRequiredService>());
}
return new HybridCacheService(
memoryProvider,
distributedProvider,
databaseCacheManager,
strategyManager,
logger);
});
return services;
}
///
/// 配置 AI 服務
///
public static IServiceCollection AddAIServices(this IServiceCollection services, IConfiguration configuration)
{
// 強型別配置
services.Configure(configuration.GetSection(GeminiOptions.SectionName));
services.AddSingleton, GeminiOptionsValidator>();
// Gemini 服務組件
services.AddHttpClient();
services.AddScoped();
services.AddScoped();
// 主要 Gemini 服務 (Facade)
services.AddScoped();
// 圖片生成服務組件
services.AddScoped();
services.AddScoped();
services.AddScoped();
services.AddScoped();
services.AddScoped();
return services;
}
///
/// 配置業務服務
///
public static IServiceCollection AddBusinessServices(this IServiceCollection services)
{
services.AddScoped();
// 媒體服務
services.AddScoped();
services.AddScoped();
// Replicate 服務
services.AddHttpClient();
// 詞彙服務
services.AddScoped();
// 分析服務
services.AddScoped();
// 複習服務
services.AddScoped();
return services;
}
///
/// 配置身份驗證
///
public static IServiceCollection AddAuthenticationServices(this IServiceCollection services, IConfiguration configuration)
{
var supabaseUrl = Environment.GetEnvironmentVariable("DRAMALING_SUPABASE_URL")
?? configuration["Supabase:Url"]
?? "https://localhost";
var jwtSecret = Environment.GetEnvironmentVariable("DRAMALING_SUPABASE_JWT_SECRET")
?? configuration["Supabase:JwtSecret"]
?? "dev-secret-minimum-32-characters-long-for-jwt-signing-in-development-mode-only";
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = supabaseUrl,
ValidAudience = "authenticated",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSecret))
};
});
return services;
}
///
/// 配置 CORS 政策
///
public static IServiceCollection AddCorsServices(this IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("AllowFrontend", policy =>
{
policy.WithOrigins("http://localhost:3000", "http://localhost:3001", "http://localhost:3002")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
.SetPreflightMaxAge(TimeSpan.FromMinutes(5));
});
options.AddPolicy("AllowAll", policy =>
{
policy.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
return services;
}
///
/// 配置 API 文檔服務
///
public static IServiceCollection AddApiDocumentationServices(this IServiceCollection services)
{
services.AddEndpointsApiExplorer();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new() { Title = "DramaLing API", Version = "v1" });
// JWT Authentication for Swagger
c.AddSecurityDefinition("Bearer", new Microsoft.OpenApi.Models.OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer scheme",
Name = "Authorization",
In = Microsoft.OpenApi.Models.ParameterLocation.Header,
Type = Microsoft.OpenApi.Models.SecuritySchemeType.ApiKey,
Scheme = "Bearer"
});
c.AddSecurityRequirement(new Microsoft.OpenApi.Models.OpenApiSecurityRequirement
{
{
new Microsoft.OpenApi.Models.OpenApiSecurityScheme
{
Reference = new Microsoft.OpenApi.Models.OpenApiReference
{
Type = Microsoft.OpenApi.Models.ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
Array.Empty()
}
});
});
return services;
}
}