using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.StackExchangeRedis;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using StackExchange.Redis;
using TakeoutSaaS.Application.Dictionary.Abstractions;
using TakeoutSaaS.Domain.Dictionary.Repositories;
using TakeoutSaaS.Domain.SystemParameters.Repositories;
using TakeoutSaaS.Infrastructure.Common.Extensions;
using TakeoutSaaS.Infrastructure.Dictionary.Caching;
using TakeoutSaaS.Infrastructure.Dictionary.ImportExport;
using TakeoutSaaS.Infrastructure.Dictionary.Options;
using TakeoutSaaS.Infrastructure.Dictionary.Persistence;
using TakeoutSaaS.Infrastructure.Dictionary.Repositories;
using TakeoutSaaS.Infrastructure.Dictionary.Services;
using TakeoutSaaS.Shared.Abstractions.Constants;

namespace TakeoutSaaS.Infrastructure.Dictionary.Extensions;

/// <summary>
/// 字典基础设施注册扩展。
/// </summary>
public static class DictionaryServiceCollectionExtensions
{
    /// <summary>
    /// 注册字典模块基础设施。
    /// </summary>
    /// <param name="services">服务集合。</param>
    /// <param name="configuration">配置源。</param>
    /// <returns>服务集合。</returns>
    /// <exception cref="InvalidOperationException">缺少数据库配置时抛出。</exception>
    public static IServiceCollection AddDictionaryInfrastructure(this IServiceCollection services, IConfiguration configuration)
    {
        services.AddDatabaseInfrastructure(configuration);
        services.AddPostgresDbContext<DictionaryDbContext>(DatabaseConstants.DictionaryDataSource);

        services.AddScoped<IDictionaryRepository, EfDictionaryRepository>();
        services.AddScoped<IDictionaryGroupRepository, DictionaryGroupRepository>();
        services.AddScoped<IDictionaryItemRepository, DictionaryItemRepository>();
        services.AddScoped<ITenantDictionaryOverrideRepository, TenantDictionaryOverrideRepository>();
        services.AddScoped<IDictionaryLabelOverrideRepository, DictionaryLabelOverrideRepository>();
        services.AddScoped<IDictionaryImportLogRepository, DictionaryImportLogRepository>();
        services.AddScoped<ICacheInvalidationLogRepository, CacheInvalidationLogRepository>();
        services.AddScoped<ISystemParameterRepository, EfSystemParameterRepository>();
        services.AddScoped<IDictionaryCache, DistributedDictionaryCache>();
        services.AddScoped<ICsvDictionaryParser, CsvDictionaryParser>();
        services.AddScoped<IJsonDictionaryParser, JsonDictionaryParser>();

        services.AddMemoryCache();

        var redisConnection = configuration.GetConnectionString("Redis");
        var hasDistributedCache = services.Any(descriptor => descriptor.ServiceType == typeof(IDistributedCache));
        if (!hasDistributedCache)
        {
            if (!string.IsNullOrWhiteSpace(redisConnection))
            {
                services.AddStackExchangeRedisCache(options =>
                {
                    options.Configuration = redisConnection;
                });
            }
            else
            {
                services.AddDistributedMemoryCache();
            }
        }

        if (!string.IsNullOrWhiteSpace(redisConnection) && !services.Any(descriptor => descriptor.ServiceType == typeof(IConnectionMultiplexer)))
        {
            services.AddSingleton<IConnectionMultiplexer>(_ => ConnectionMultiplexer.Connect(redisConnection));
        }

        services.AddSingleton<MemoryCacheService>();
        services.AddSingleton<CacheMetricsCollector>();
        services.AddSingleton(sp => new RedisCacheService(
            sp.GetRequiredService<IDistributedCache>(),
            sp.GetService<IConnectionMultiplexer>()));
        services.AddSingleton(sp => new HybridCacheService(
            sp.GetRequiredService<MemoryCacheService>(),
            sp.GetRequiredService<RedisCacheService>(),
            sp.GetService<IConnectionMultiplexer>(),
            sp.GetService<ILogger<HybridCacheService>>(),
            sp.GetService<CacheMetricsCollector>(),
            sp.GetService<IServiceScopeFactory>()));
        services.AddSingleton<IDictionaryHybridCache>(sp => sp.GetRequiredService<HybridCacheService>());

        services.AddOptions<DictionaryCacheOptions>()
            .Bind(configuration.GetSection("Dictionary:Cache"))
            .ValidateDataAnnotations();

        services.AddOptions<DictionaryCacheWarmupOptions>()
            .Bind(configuration.GetSection("CacheWarmup"))
            .ValidateDataAnnotations();

        services.AddHostedService<CacheWarmupService>();

        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 中兜底并记录日志。
    }
}
