using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using TakeoutSaaS.Application.Identity.Abstractions;
using TakeoutSaaS.Domain.Identity.Repositories;
using TakeoutSaaS.Infrastructure.Common.Extensions;
using TakeoutSaaS.Infrastructure.Identity.Options;
using TakeoutSaaS.Infrastructure.Identity.Persistence;
using TakeoutSaaS.Infrastructure.Identity.Repositories;
using TakeoutSaaS.Infrastructure.Identity.Services;
using TakeoutSaaS.Shared.Abstractions.Constants;
using DomainIdentityUser = TakeoutSaaS.Domain.Identity.Entities.IdentityUser;

namespace TakeoutSaaS.Infrastructure.Identity.Extensions;

/// <summary>
/// 身份认证基础设施注入。
/// </summary>
public static class ServiceCollectionExtensions
{
    /// <summary>
    /// 注册身份认证基础设施（数据库、Redis、JWT、限流等）。
    /// </summary>
    /// <param name="services">服务集合。</param>
    /// <param name="configuration">配置源。</param>
    /// <param name="enableMiniFeatures">是否启用小程序相关依赖（如微信登录）。</param>
    /// <param name="enableAdminSeed">是否启用后台账号初始化。</param>
    /// <returns>服务集合。</returns>
    /// <exception cref="InvalidOperationException">配置缺失时抛出。</exception>
    public static IServiceCollection AddIdentityInfrastructure(
        this IServiceCollection services,
        IConfiguration configuration,
        bool enableMiniFeatures = false,
        bool enableAdminSeed = false)
    {
        services.AddDatabaseInfrastructure(configuration);
        services.AddPostgresDbContext<IdentityDbContext>(DatabaseConstants.IdentityDataSource);

        var redisConnection = configuration.GetConnectionString("Redis");
        if (string.IsNullOrWhiteSpace(redisConnection))
        {
            throw new InvalidOperationException("缺少 Redis 连接字符串配置。");
        }

        services.AddStackExchangeRedisCache(options =>
        {
            options.Configuration = redisConnection;
        });

        services.AddScoped<IIdentityUserRepository, EfIdentityUserRepository>();
        services.AddScoped<IMiniUserRepository, EfMiniUserRepository>();
        services.AddScoped<IRoleRepository, EfRoleRepository>();
        services.AddScoped<IPermissionRepository, EfPermissionRepository>();
        services.AddScoped<IUserRoleRepository, EfUserRoleRepository>();
        services.AddScoped<IRolePermissionRepository, EfRolePermissionRepository>();
        services.AddScoped<IRoleTemplateRepository, EfRoleTemplateRepository>();
        services.AddScoped<IMenuRepository, EfMenuRepository>();
        services.AddScoped<IJwtTokenService, JwtTokenService>();
        services.AddScoped<IRefreshTokenStore, RedisRefreshTokenStore>();
        services.AddScoped<ILoginRateLimiter, RedisLoginRateLimiter>();
        services.AddScoped<IPasswordHasher<DomainIdentityUser>, PasswordHasher<DomainIdentityUser>>();

        services.AddOptions<JwtOptions>()
            .Bind(configuration.GetSection("Identity:Jwt"))
            .ValidateDataAnnotations()
            .ValidateOnStart();

        services.AddOptions<LoginRateLimitOptions>()
            .Bind(configuration.GetSection("Identity:LoginRateLimit"))
            .ValidateDataAnnotations()
            .ValidateOnStart();

        services.AddOptions<RefreshTokenStoreOptions>()
            .Bind(configuration.GetSection("Identity:RefreshTokenStore"));

        if (enableMiniFeatures)
        {
            services.AddOptions<WeChatMiniOptions>()
                .Bind(configuration.GetSection("Identity:WeChatMini"))
                .ValidateDataAnnotations()
                .ValidateOnStart();

            services.AddHttpClient<IWeChatAuthService, WeChatAuthService>(client =>
            {
                client.BaseAddress = new Uri("https://api.weixin.qq.com/");
                client.Timeout = TimeSpan.FromSeconds(10);
            });
        }

        if (enableAdminSeed)
        {
            services.AddOptions<AdminSeedOptions>()
                .Bind(configuration.GetSection("Identity:AdminSeed"))
                .ValidateDataAnnotations()
                .ValidateOnStart();

            services.AddHostedService<IdentityDataSeeder>();
        }

        return services;
    }

    /// <summary>
    /// 确保数据库连接已配置（Database 节或 ConnectionStrings）。
    /// </summary>
    /// <param name="configuration">配置源。</param>
    /// <param name="dataSourceName">数据源名称。</param>
    /// <exception cref="InvalidOperationException">未配置时抛出。</exception>
    private static void EnsureDatabaseConnectionConfigured(IConfiguration configuration, string dataSourceName)
    {
        // 保留兼容接口，当前逻辑在 DatabaseConnectionFactory 中兜底并记录日志。
    }
}
