#nullable enable
using System.Collections.Concurrent;

namespace Baya.Infrastructure.CrossCutting.Seams;

/// <summary>
/// Development-only, in-memory capture of the most recent OTP per phone. It exists so a browser or an
/// automated end-to-end test can complete phone-OTP login without a real SMS gateway — OTP "delivery" is
/// <see cref="LoggingSmsSender"/>, which only writes the code to the server log. It is populated ONLY when
/// <see cref="DevCapturingSmsSender"/> is registered, which happens only in the Development environment (see
/// <c>DevelopmentSeamExtensions.AddDevelopmentOtpCapture</c>). It is never wired outside Development, and the
/// endpoint that exposes it (<c>/api/v1/dev/last_otp/{phone}</c>) is additionally gated on
/// <c>IHostEnvironment.IsDevelopment()</c>. Superseded by the real SMS gateway in refinement Phase 8.
/// </summary>
public sealed class DevOtpStore
{
    // Bounded so a long-lived dev session can't grow the map without limit; only the newest code per phone
    // matters for completing a login.
    private const int MaxEntries = 500;

    private readonly ConcurrentDictionary<string, string> _codesByPhone = new();

    public void Capture(string phone, string code)
    {
        var key = NormalizeKey(phone);
        if (key is null)
            return;

        if (_codesByPhone.Count >= MaxEntries && !_codesByPhone.ContainsKey(key))
            _codesByPhone.Clear();

        _codesByPhone[key] = code;
    }

    public string? GetLatest(string phone)
    {
        var key = NormalizeKey(phone);
        return key is not null && _codesByPhone.TryGetValue(key, out var code) ? code : null;
    }

    // Digits-only, last 10 → matches IranianPhone's canonical 09xxxxxxxxx regardless of how the caller
    // spelled it (+98 / 0098 / 98 / 0 prefix). Kept self-contained so this dev helper needs no dependency on
    // the Application layer's internal phone normalizer.
    private static string? NormalizeKey(string? phone)
    {
        if (string.IsNullOrWhiteSpace(phone))
            return null;

        var digits = new string(phone.Where(char.IsAsciiDigit).ToArray());
        return digits.Length >= 10 ? digits[^10..] : null;
    }
}
