using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
using WalletService.Infrastructure;

namespace WalletService.FunctionalTests;

/// <summary>
/// EN: Custom WebApplicationFactory for functional tests.
/// VI: WebApplicationFactory tùy chỉnh cho functional tests.
/// </summary>
public class CustomWebApplicationFactory : WebApplicationFactory<Program>
{
    private readonly string _databaseName = "TestDatabase_" + Guid.NewGuid().ToString();

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.UseEnvironment("Testing");

        // EN: Configure services BEFORE the app configures itself
        // VI: Cấu hình services TRƯỚC KHI app tự cấu hình
        builder.ConfigureServices(services =>
        {
            // EN: Remove ALL existing DbContext registrations
            // VI: Xóa TẤT CẢ các đăng ký DbContext hiện có
            RemoveExistingDbContextRegistrations(services);

            // EN: Remove PostgreSQL health check registrations
            // VI: Xóa các đăng ký health check PostgreSQL
            RemoveHealthCheckRegistrations(services);

            // EN: Add in-memory database for testing
            // VI: Thêm in-memory database để test
            services.AddDbContext<WalletServiceContext>(options =>
            {
                options.UseInMemoryDatabase(_databaseName);
                options.EnableSensitiveDataLogging();
            });

            // EN: Add simple health checks for testing (no external dependencies)
            // VI: Thêm health checks đơn giản cho testing (không có external dependencies)
            services.AddHealthChecks();

            // EN: Set logging level for debugging tests
            // VI: Đặt mức logging để debug tests
            services.AddLogging(logging =>
            {
                logging.SetMinimumLevel(LogLevel.Warning);
                logging.AddFilter("Microsoft.EntityFrameworkCore", LogLevel.Warning);
            });
        });
    }

    private static void RemoveExistingDbContextRegistrations(IServiceCollection services)
    {
        // EN: Remove all DbContext-related registrations
        // VI: Xóa tất cả các đăng ký liên quan đến DbContext
        var descriptorsToRemove = services.Where(d =>
            d.ServiceType == typeof(DbContextOptions<WalletServiceContext>) ||
            d.ServiceType == typeof(WalletServiceContext) ||
            d.ServiceType == typeof(DbContextOptions) ||
            d.ServiceType.FullName?.Contains("EntityFrameworkCore") == true ||
            d.ImplementationType?.FullName?.Contains("Npgsql") == true)
            .ToList();

        foreach (var descriptor in descriptorsToRemove)
        {
            services.Remove(descriptor);
        }

        services.RemoveAll(typeof(DbContextOptions));
        services.RemoveAll(typeof(DbContextOptions<WalletServiceContext>));
    }

    private static void RemoveHealthCheckRegistrations(IServiceCollection services)
    {
        // EN: Remove health check registrations that depend on external services
        // VI: Xóa các health check registrations phụ thuộc vào external services
        var healthCheckDescriptors = services.Where(d =>
            d.ServiceType == typeof(HealthCheckService) ||
            d.ServiceType.FullName?.Contains("HealthCheck") == true ||
            d.ImplementationType?.FullName?.Contains("NpgSql") == true ||
            d.ImplementationType?.FullName?.Contains("Npgsql") == true)
            .ToList();

        foreach (var descriptor in healthCheckDescriptors)
        {
            services.Remove(descriptor);
        }
    }

    /// <summary>
    /// EN: Ensure database is created after host is built
    /// VI: Đảm bảo database được tạo sau khi host được build
    /// </summary>
    protected override void ConfigureClient(HttpClient client)
    {
        base.ConfigureClient(client);

        // EN: Create the database when the first client is created
        // VI: Tạo database khi client đầu tiên được tạo
        using var scope = Services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<WalletServiceContext>();
        db.Database.EnsureCreated();
    }
}
