using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.InMemory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using LittleShop.Data;
using LittleShop.Services;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Moq;
using System.Linq;

namespace LittleShop.Tests.Infrastructure;

public class TestWebApplicationFactory : WebApplicationFactory<Program>
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureServices(services =>
        {
            // Remove the existing DbContext registration
            var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<LittleShopContext>));
            if (descriptor != null)
                services.Remove(descriptor);

            // Add InMemory database for testing
            services.AddDbContext<LittleShopContext>(options =>
                options.UseInMemoryDatabase("InMemoryDbForTesting")
                       .ConfigureWarnings(warnings => warnings.Default(WarningBehavior.Ignore)));

            // Mock external services that might cause issues in tests
            services.Replace(ServiceDescriptor.Scoped<IPushNotificationService>(_ => Mock.Of<IPushNotificationService>()));
            services.Replace(ServiceDescriptor.Scoped<IBTCPayServerService>(_ => Mock.Of<IBTCPayServerService>()));
            services.Replace(ServiceDescriptor.Scoped<ITelegramBotManagerService>(_ => Mock.Of<ITelegramBotManagerService>()));

            // Build service provider
            var sp = services.BuildServiceProvider();

            // Create scope for database initialization
            using (var scope = sp.CreateScope())
            {
                var scopedServices = scope.ServiceProvider;
                var db = scopedServices.GetRequiredService<LittleShopContext>();
                var logger = scopedServices.GetRequiredService<ILogger<TestWebApplicationFactory>>();

                // Ensure database is created
                db.Database.EnsureCreated();

                try
                {
                    // Seed test data if needed
                    SeedTestData(db);
                }
                catch (Exception ex)
                {
                    logger.LogError(ex, "An error occurred seeding the database with test data.");
                }
            }
        });

        builder.UseEnvironment("Testing");
    }

    private static void SeedTestData(LittleShopContext context)
    {
        // Seed test data will be added as needed for specific tests
        context.SaveChanges();
    }
}