using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Polly;
using Polly.Extensions.Http;
using StorageService.Domain.AggregatesModel.FileAggregate;
using StorageService.Domain.AggregatesModel.QuotaAggregate;
using StorageService.Infrastructure.Caching;
using StorageService.Infrastructure.Configuration;
using StorageService.Infrastructure.ExternalServices;
using StorageService.Infrastructure.Idempotency;
using StorageService.Infrastructure.Persistence;
using StorageService.Infrastructure.Persistence.Repositories;
using StorageService.Infrastructure.Storage;

namespace StorageService.Infrastructure;

/// <summary>
/// EN: Dependency injection extensions for Infrastructure layer.
/// VI: Extensions dependency injection cho lớp Infrastructure.
/// </summary>
public static class DependencyInjection
{
    /// <summary>
    /// EN: Add infrastructure services to the DI container.
    /// VI: Thêm các services infrastructure vào DI container.
    /// </summary>
    public static IServiceCollection AddInfrastructure(
        this IServiceCollection services,
        IConfiguration configuration,
        string? environmentName = null)
    {
        // EN: Bind configuration sections / VI: Bind các configuration sections
        services.Configure<StorageSettings>(configuration.GetSection(StorageSettings.SectionName));
        services.Configure<IamServiceSettings>(configuration.GetSection(IamServiceSettings.SectionName));
        services.Configure<RedisSettings>(configuration.GetSection(RedisSettings.SectionName));
        services.Configure<CDNSettings>(configuration.GetSection("CDN"));

        // EN: Register Redis cache service / VI: Đăng ký Redis cache service
        services.AddSingleton<IRedisCacheService, RedisCacheService>();

        // EN: Register CDN service / VI: Đăng ký CDN service
        services.AddSingleton<CDN.ICDNService, CDN.CDNService>();

        // EN: Add DbContext with PostgreSQL / VI: Thêm DbContext với PostgreSQL
        if (!string.Equals(environmentName, "Testing", StringComparison.OrdinalIgnoreCase))
        {
            services.AddDbContext<StorageServiceContext>(options =>
            {
                var connectionString = configuration.GetConnectionString("DefaultConnection")
                    ?? configuration["DATABASE_URL"]
                    ?? throw new InvalidOperationException("Connection string not configured");

                options.UseNpgsql(connectionString, npgsqlOptions =>
                {
                    npgsqlOptions.MigrationsAssembly(typeof(StorageServiceContext).Assembly.FullName);
                    npgsqlOptions.EnableRetryOnFailure(
                        maxRetryCount: 5,
                        maxRetryDelay: TimeSpan.FromSeconds(30),
                        errorCodesToAdd: null);
                });

                // EN: Enable sensitive data logging in development only
                // VI: Chỉ bật sensitive data logging trong development
                if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development")
                {
                    options.EnableSensitiveDataLogging();
                    options.EnableDetailedErrors();
                }
            });
        }

        // EN: Register repositories / VI: Đăng ký repositories
        services.AddScoped<IFileRepository, FileRepository>();
        services.AddScoped<IQuotaRepository, QuotaRepository>();
        services.AddScoped<Domain.AggregatesModel.FileShareAggregate.IFileShareRepository, FileShareRepository>();
        services.AddScoped<Domain.AggregatesModel.FileVersionAggregate.IFileVersionRepository, FileVersionRepository>();
        services.AddScoped<Domain.AggregatesModel.FolderAggregate.IFolderRepository, FolderRepository>();

        // EN: Register storage providers / VI: Đăng ký storage providers
        services.AddSingleton<MinioStorageProvider>();
        services.AddSingleton<AliyunOssStorageProvider>();
        services.AddSingleton<IStorageProviderFactory, StorageProviderFactory>();

        // EN: Register IAM Service client with Polly resilience / VI: Đăng ký IAM Service client với Polly resilience
        services.AddHttpClient<IIamServiceClient, HttpIamServiceClient>()
            .SetHandlerLifetime(TimeSpan.FromMinutes(5))
            .AddPolicyHandler(GetRetryPolicy())
            .AddPolicyHandler(GetCircuitBreakerPolicy());

        // EN: Register idempotency services / VI: Đăng ký idempotency services
        services.AddScoped<IRequestManager, RequestManager>();

        return services;
    }

    /// <summary>
    /// EN: Get retry policy for HTTP client.
    /// VI: Lấy retry policy cho HTTP client.
    /// </summary>
    private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
    {
        return HttpPolicyExtensions
            .HandleTransientHttpError()
            .WaitAndRetryAsync(3, retryAttempt => 
                TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
    }

    /// <summary>
    /// EN: Get circuit breaker policy for HTTP client.
    /// VI: Lấy circuit breaker policy cho HTTP client.
    /// </summary>
    private static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
    {
        return HttpPolicyExtensions
            .HandleTransientHttpError()
            .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
    }
}
