using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using ColaFlow.Modules.Identity.Infrastructure.Persistence;
using ColaFlow.Modules.ProjectManagement.Infrastructure.Persistence;

namespace ColaFlow.Modules.Identity.IntegrationTests.Infrastructure;

/// <summary>
/// Custom WebApplicationFactory for ColaFlow Integration Tests
/// Supports both In-Memory and Real PostgreSQL databases
/// </summary>
public class ColaFlowWebApplicationFactory(bool useInMemoryDatabase = true, string? testDatabaseName = null)
    : WebApplicationFactory<Program>
{
    private readonly string? _testDatabaseName = testDatabaseName ?? $"TestDb_{Guid.NewGuid()}";

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        // Set environment to Testing - this prevents PostgreSQL DbContext registration in modules
        builder.UseEnvironment("Testing");

        // Configure test-specific settings
        builder.ConfigureAppConfiguration((context, config) =>
        {
            // Clear existing connection strings to prevent PostgreSQL registration
            config.Sources.Clear();

            // Add minimal config for testing
            config.AddInMemoryCollection(new Dictionary<string, string?>
            {
                ["ConnectionStrings:DefaultConnection"] = "",
                ["ConnectionStrings:PMDatabase"] = "",
                ["Jwt:SecretKey"] = "test-secret-key-for-integration-tests-minimum-32-characters",
                ["Jwt:Issuer"] = "ColaFlow.Test",
                ["Jwt:Audience"] = "ColaFlow.Test",
                ["Jwt:AccessTokenExpirationMinutes"] = "15",
                ["Jwt:RefreshTokenExpirationDays"] = "7"
            });
        });

        builder.ConfigureServices(services =>
        {
            // Register test databases (modules won't register PostgreSQL due to Testing environment)
            if (useInMemoryDatabase)
            {
                // Use In-Memory Database for fast, isolated tests
                // IMPORTANT: Share the same database name for cross-context data consistency
                services.AddDbContext<IdentityDbContext>(options =>
                {
                    options.UseInMemoryDatabase(_testDatabaseName!);
                    options.EnableSensitiveDataLogging();
                });

                services.AddDbContext<PMDbContext>(options =>
                {
                    options.UseInMemoryDatabase(_testDatabaseName!);
                    options.EnableSensitiveDataLogging();
                });
            }
            else
            {
                // Use Real PostgreSQL for integration tests
                var connectionString = $"Host=localhost;Port=5432;Database=colaflow_test_{_testDatabaseName};Username=postgres;Password=postgres";

                services.AddDbContext<IdentityDbContext>(options =>
                {
                    options.UseNpgsql(connectionString);
                    options.EnableSensitiveDataLogging();
                });

                services.AddDbContext<PMDbContext>(options =>
                {
                    options.UseNpgsql(connectionString);
                    options.EnableSensitiveDataLogging();
                });
            }
        });
    }

    // Override CreateHost to initialize databases after the host is created
    protected override IHost CreateHost(IHostBuilder builder)
    {
        var host = base.CreateHost(builder);

        // Initialize databases after host is created
        using var scope = host.Services.CreateScope();
        var services = scope.ServiceProvider;

        try
        {
            // Initialize Identity database
            var identityDb = services.GetRequiredService<IdentityDbContext>();
            if (useInMemoryDatabase)
            {
                identityDb.Database.EnsureCreated();
            }
            else
            {
                identityDb.Database.Migrate();
            }

            // Initialize ProjectManagement database
            var pmDb = services.GetRequiredService<PMDbContext>();
            if (useInMemoryDatabase)
            {
                pmDb.Database.EnsureCreated();
            }
            else
            {
                pmDb.Database.Migrate();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error initializing test database: {ex.Message}");
            throw;
        }

        return host;
    }
}
