using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;

namespace GerbilManager.Tests;

/// <summary>
/// FEAT-13: In-Memory-Test-Host für Endpoint-Round-Trips. Ersetzt die
/// Aspire/Npgsql-Registrierung durch SQLite in-memory (eine offene Verbindung
/// hält die DB am Leben), Umgebung "Testing" überspringt Database.Migrate()
/// (Npgsql-Migrationen laufen nicht auf SQLite) — Schema via EnsureCreated,
/// inklusive der HasData-Seeds (73 Farbschläge + Zuchtprofil-Singleton).
/// Vertrags-Dateien landen in einem Temp-Ordner, der mit dem Host stirbt.
/// </summary>
public sealed class ApiFactory : WebApplicationFactory<Program>
{
    private readonly SqliteConnection _connection = new("DataSource=:memory:");

    /// <summary>
    /// INBOX-2: Test-spezifische DI-Überschreibungen (z. B. AI-Stub-Handler).
    /// Init-Property statt Konstruktor — xUnit-Klassen-Fixtures erlauben nur
    /// EINEN öffentlichen (parameterlosen) Konstruktor.
    /// </summary>
    public Action<IServiceCollection>? ConfigureTestServices { get; init; }

    public string ContractRoot { get; } =
        Path.Combine(Path.GetTempPath(), $"gerbil-contract-tests-{Guid.NewGuid():N}");

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.UseEnvironment("Testing");
        // Dummy, damit Aspires AddNpgsqlDbContext beim Host-Aufbau zufrieden ist;
        // die eigentliche Registrierung wird unten durch SQLite ersetzt.
        builder.UseSetting("ConnectionStrings:gerbilmanager",
            "Host=localhost;Database=test;Username=test;Password=test");
        builder.UseSetting("Contracts:RootPath", ContractRoot);

        builder.ConfigureServices(services =>
        {
            // EF 9+: AddDbContext registriert die Provider-Konfiguration als
            // IDbContextOptionsConfiguration<T> — ohne deren Entfernung blieben
            // Npgsql UND SQLite registriert (ein Provider pro ServiceProvider).
            services.RemoveAll<Microsoft.EntityFrameworkCore.Infrastructure.IDbContextOptionsConfiguration<ApplicationContext>>();
            services.RemoveAll<DbContextOptions<ApplicationContext>>();
            services.RemoveAll<ApplicationContext>();

            _connection.Open();
            services.AddDbContext<ApplicationContext>(o => o.UseSqlite(_connection));

            using var provider = services.BuildServiceProvider();
            using var scope = provider.CreateScope();
            scope.ServiceProvider.GetRequiredService<ApplicationContext>().Database.EnsureCreated();

            ConfigureTestServices?.Invoke(services);
        });
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        if (disposing)
        {
            _connection.Dispose();
            if (Directory.Exists(ContractRoot)) Directory.Delete(ContractRoot, recursive: true);
        }
    }
}
