using Baya.Application.Contracts.Common;
using Baya.Infrastructure.CrossCutting.Seams;
using NSubstitute;

namespace Baya.Test.Foundation;

/// <summary>
/// Refinement Phase 0 — the Development-only OTP bring-up bridge. The store captures the latest code per
/// phone (spelling-insensitive) and the capturing sender both captures and still delegates to the real
/// (log-only) sender, changing no delivery behaviour.
/// </summary>
public class DevOtpBringUpTests
{
    [Fact]
    public void Store_CapturesAndReturnsLatestCode()
    {
        var store = new DevOtpStore();

        store.Capture("09120000001", "111111");
        store.Capture("09120000001", "222222");

        Assert.Equal("222222", store.GetLatest("09120000001"));
    }

    [Theory]
    [InlineData("09120000001")]
    [InlineData("+989120000001")]
    [InlineData("00989120000001")]
    [InlineData("9120000001")]
    public void Store_MatchesAnyPhoneSpelling(string lookup)
    {
        var store = new DevOtpStore();
        store.Capture("09120000001", "424242");

        Assert.Equal("424242", store.GetLatest(lookup));
    }

    [Fact]
    public void Store_ReturnsNullForUnknownPhone()
    {
        var store = new DevOtpStore();
        store.Capture("09120000001", "123456");

        Assert.Null(store.GetLatest("09350000009"));
    }

    [Fact]
    public async Task CapturingSender_CapturesTheCodeAndStillDelegates()
    {
        var inner = Substitute.For<ISmsSender>();
        var store = new DevOtpStore();
        var sender = new DevCapturingSmsSender(inner, store);

        await sender.SendOtpAsync("09120000001", "135790");

        Assert.Equal("135790", store.GetLatest("09120000001"));
        await inner.Received(1).SendOtpAsync("09120000001", "135790", Arg.Any<CancellationToken>());
    }

    [Fact]
    public async Task CapturingSender_PlainMessageDelegatesWithoutCapturing()
    {
        var inner = Substitute.For<ISmsSender>();
        var store = new DevOtpStore();
        var sender = new DevCapturingSmsSender(inner, store);

        await sender.SendAsync("09120000001", "your booking is confirmed");

        Assert.Null(store.GetLatest("09120000001"));
        await inner.Received(1).SendAsync("09120000001", "your booking is confirmed", Arg.Any<CancellationToken>());
    }
}
