using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.Configuration;
using Testcontainers.PostgreSql;
using Xunit;

namespace foodmarket.IntegrationTests.Support;

/// <summary>Поднимает реальный API (WebApplicationFactory) поверх одноразового
/// Postgres-контейнера (Testcontainers). Миграции применяются на старте host'а
/// (Program.Migrate), сидеры наполняют справочники и SuperAdmin. Запускается
/// один раз на всю коллекцию тестов.</summary>
public sealed class ApiFactory : WebApplicationFactory<Program>, IAsyncLifetime
{
    static ApiFactory()
    {
        // Ryuk (reaper) тянет образ из Docker Hub — на этом хосте сеть к внешним
        // реестрам нестабильна, а postgres:16-alpine уже закэширован. Выключаем.
        Environment.SetEnvironmentVariable("TESTCONTAINERS_RYUK_DISABLED", "true");
        // Лимитер читает конфиг ЭАГЕРНО при регистрации сервисов — поэтому
        // переопределяем через env-переменную (её CreateBuilder подхватывает до
        // регистрации), а не через ConfigureAppConfiguration (применяется позже).
        // Тесты логинятся десятки раз с одного loopback-IP — иначе 429.
        Environment.SetEnvironmentVariable("RateLimiting__Enabled", "false");
        // Тише логи в тестовом прогоне (OpenIddict сыплет Debug-событиями).
        // Ошибки (Error) пропускаем — нужно для отладки 500 в тестах.
        Environment.SetEnvironmentVariable("Serilog__MinimumLevel__Default", "Warning");
        // Hangfire-сервер не нужен в интеграционных тестах: он бы создавал свои
        // таблицы в одноразовом контейнере и удерживал коннекшен. Сам клиент
        // (AddHangfire) остаётся — recurring jobs не регистрируются.
        Environment.SetEnvironmentVariable("Hangfire__Enabled", "false");
    }

    private readonly PostgreSqlContainer _db = new PostgreSqlBuilder()
        .WithImage("postgres:16-alpine")
        .WithDatabase("food_market")
        .WithUsername("food_market")
        .WithPassword("food_market_test")
        .Build();

    public async Task InitializeAsync() => await _db.StartAsync();

    public new async Task DisposeAsync()
    {
        await _db.DisposeAsync();
        await base.DisposeAsync();
    }

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        // Development — простые dev-ключи OpenIddict (без генерации сертификатов),
        // 3-сегментный токен. Лимитер выключаем: тесты логинятся много раз с одного IP.
        builder.UseEnvironment("Development");
        builder.ConfigureAppConfiguration((_, cfg) =>
        {
            // Строку подключения AddDbContext читает лениво — здесь override
            // срабатывает. RateLimiting выключён через env (см. static ctor).
            cfg.AddInMemoryCollection(new Dictionary<string, string?>
            {
                ["ConnectionStrings:Default"] = _db.GetConnectionString(),
            });
        });
    }
}
