using System;
using System.Linq;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Testcontainers.PostgreSql;
using Testcontainers.Redis;

namespace ColaFlow.IntegrationTests.Infrastructure;

/// <summary>
/// Custom WebApplicationFactory for API integration tests
/// Replaces production database with Testcontainers
/// </summary>
/// <typeparam name="TProgram">Program class from ColaFlow.API</typeparam>
/// <typeparam name="TDbContext">DbContext class from ColaFlow.Infrastructure</typeparam>
public class ColaFlowWebApplicationFactory<TProgram, TDbContext>
    : WebApplicationFactory<TProgram>, IAsyncDisposable
    where TProgram : class
    where TDbContext : DbContext
{
    private PostgreSqlContainer? _postgresContainer;
    private RedisContainer? _redisContainer;

    /// <summary>
    /// Configure services for testing
    /// </summary>
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureServices(async services =>
        {
            // Remove existing DbContext registration
            var dbContextDescriptor = services.SingleOrDefault(
                d => d.ServiceType == typeof(DbContextOptions<TDbContext>));

            if (dbContextDescriptor != null)
            {
                services.Remove(dbContextDescriptor);
            }

            // Start Testcontainers
            _postgresContainer = new PostgreSqlBuilder()
                .WithImage("postgres:16-alpine")
                .WithDatabase("colaflow_test")
                .WithUsername("colaflow_test")
                .WithPassword("colaflow_test_password")
                .WithCleanUp(true)
                .Build();

            _redisContainer = new RedisBuilder()
                .WithImage("redis:7-alpine")
                .WithCleanUp(true)
                .Build();

            await _postgresContainer.StartAsync();
            await _redisContainer.StartAsync();

            // Add test DbContext with Testcontainers connection string
            services.AddDbContext<TDbContext>(options =>
            {
                options.UseNpgsql(_postgresContainer.GetConnectionString());
                options.EnableSensitiveDataLogging();
                options.EnableDetailedErrors();
            });

            // Replace Redis connection string
            // TODO: Configure Redis connection with Testcontainers connection string

            // Build service provider and apply migrations
            var serviceProvider = services.BuildServiceProvider();
            using var scope = serviceProvider.CreateScope();
            var dbContext = scope.ServiceProvider.GetRequiredService<TDbContext>();

            // Apply migrations
            await dbContext.Database.MigrateAsync();
        });

        // Optional: Disable HTTPS redirection for tests
        builder.UseEnvironment("Testing");
    }

    /// <summary>
    /// Create a new scope with fresh DbContext
    /// </summary>
    public IServiceScope CreateScope()
    {
        return Services.CreateScope();
    }

    /// <summary>
    /// Get DbContext from a scope
    /// </summary>
    public TDbContext GetDbContext(IServiceScope scope)
    {
        return scope.ServiceProvider.GetRequiredService<TDbContext>();
    }

    /// <summary>
    /// Cleanup Testcontainers
    /// </summary>
    public new async ValueTask DisposeAsync()
    {
        if (_postgresContainer != null)
        {
            await _postgresContainer.DisposeAsync();
        }

        if (_redisContainer != null)
        {
            await _redisContainer.DisposeAsync();
        }

        await base.DisposeAsync();
    }
}

/// <summary>
/// Example usage in test class:
///
/// public class ProjectsApiTests : IClassFixture<ColaFlowWebApplicationFactory<Program, ColaFlowDbContext>>
/// {
///     private readonly HttpClient _client;
///     private readonly ColaFlowWebApplicationFactory<Program, ColaFlowDbContext> _factory;
///
///     public ProjectsApiTests(ColaFlowWebApplicationFactory<Program, ColaFlowDbContext> factory)
///     {
///         _factory = factory;
///         _client = factory.CreateClient();
///     }
///
///     [Fact]
///     public async Task GetProjects_ReturnsSuccessStatusCode()
///     {
///         // Arrange
///         using var scope = _factory.CreateScope();
///         var dbContext = _factory.GetDbContext(scope);
///
///         // Seed test data
///         // ...
///
///         // Act
///         var response = await _client.GetAsync("/api/v1/projects");
///
///         // Assert
///         response.EnsureSuccessStatusCode();
///     }
/// }
/// </summary>
