using Baya.Application.Contracts.Common;
using Baya.Infrastructure.CrossCutting.Seams;
using Baya.Infrastructure.CrossCutting.Seams.Real;
using Baya.Infrastructure.CrossCutting.ServiceConfiguration;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace Baya.Test.Foundation.Seams;

/// <summary>
/// The Telegram OTP relay must be <b>invisible unless opted in</b>: an environment that configures no SMS
/// provider — or leaves the default <c>mock</c> — resolves the log-only sender exactly as it did before the
/// channel existed. Only <c>Seams:Sms:Provider = telegram</c> swaps it in.
/// </summary>
public class SmsProviderRegistrationTests
{
    [Fact]
    public void UnsetProvider_ResolvesTheLogOnlyMock()
        => Assert.IsType<LoggingSmsSender>(Resolve(null));

    [Fact]
    public void MockProvider_ResolvesTheLogOnlyMock()
        => Assert.IsType<LoggingSmsSender>(Resolve("mock"));

    [Fact]
    public void UnknownProvider_FallsClosedToTheLogOnlyMock()
        => Assert.IsType<LoggingSmsSender>(Resolve("telegramm"));

    [Fact]
    public void TelegramProvider_ResolvesTheRelayAdapter()
        => Assert.IsType<TelegramSmsSender>(Resolve("telegram"));

    [Fact]
    public async Task OtpCaptureBridge_DecoratesTheConfiguredSender_NotTheMock()
    {
        // The Development capture bridge runs alongside the relay, so it must wrap the *configured* sender —
        // re-creating a LoggingSmsSender here would silently drop every Telegram delivery. Proven without a
        // network call: only TelegramSmsSender refuses an unconfigured api key.
        var services = Services("telegram", apiKey: null);
        services.AddDevelopmentOtpCapture();

        var provider = services.BuildServiceProvider();
        var sender = provider.GetRequiredService<ISmsSender>();
        Assert.IsType<DevCapturingSmsSender>(sender);

        var ex = await Assert.ThrowsAsync<InvalidOperationException>(
            () => sender.SendOtpAsync("09120000001", "135790"));
        Assert.Contains("Seams:Sms:Telegram:ApiKey", ex.Message);

        // …and the code was still captured for GET /dev/last_otp before the inner sender ran.
        Assert.Equal("135790", provider.GetRequiredService<DevOtpStore>().GetLatest("09120000001"));
    }

    private static ISmsSender Resolve(string? provider)
        => Services(provider, "0123456789abcdef0123456789abcdef").BuildServiceProvider().GetRequiredService<ISmsSender>();

    private static ServiceCollection Services(string? provider, string? apiKey)
    {
        var settings = new Dictionary<string, string?>();
        if (provider is not null) settings["Seams:Sms:Provider"] = provider;
        if (apiKey is not null) settings["Seams:Sms:Telegram:ApiKey"] = apiKey;

        var configuration = new ConfigurationBuilder().AddInMemoryCollection(settings).Build();

        var services = new ServiceCollection();
        services.AddLogging();
        services.AddCrossCuttingSeams(configuration);

        return services;
    }
}
