using DodoSSH.Client.Domain;

namespace DodoSSH.Client.Domain.Tests;

/// <summary>
/// Reading a creation time back out of an identifier this client minted.
/// </summary>
/// <remarks>
/// The whole value of this helper is that it is the only creation time any vault item has, so the two cases
/// that matter are that a real id gives a plausible answer and that anything else gives none. A version 4
/// id answering with a date would be worse than answering nothing: it would be a plausible wrong date on a
/// screen somebody is using to decide whether a pin is stale.
/// </remarks>
public sealed class Uuid7TimestampTests
{
    [Fact]
    public void AFreshlyMintedId_CarriesTheMomentItWasMade()
    {
        // TimeProvider, because DateTimeOffset.UtcNow is banned repo-wide — see BannedSymbols.txt. The real
        // clock rather than a fake one is the point here: what is being checked is that the id Guid mints
        // for itself, from a clock nothing in this test controls, reads back as the moment it happened.
        var before = TimeProvider.System.GetUtcNow().AddSeconds(-5);
        var id = Guid.CreateVersion7();
        var after = TimeProvider.System.GetUtcNow().AddSeconds(5);

        var stamped = Uuid7Timestamp.Of(id).ShouldNotBeNull();

        stamped.ShouldBeGreaterThanOrEqualTo(before);
        stamped.ShouldBeLessThanOrEqualTo(after);
    }

    /// <remarks>
    /// The one that catches a little-endian read. Guid stores its first three fields in host order, so
    /// taking the bytes the obvious way scrambles precisely the six this reads — and produces dates tens of
    /// thousands of years out rather than throwing, which is why an ordering assertion is worth having on
    /// top of the range check above.
    /// </remarks>
    [Fact]
    public void TwoIdsMintedInOrder_ReadBackInThatOrder()
    {
        var first = Guid.CreateVersion7(DateTimeOffset.FromUnixTimeMilliseconds(1_500_000_000_000));
        var second = Guid.CreateVersion7(DateTimeOffset.FromUnixTimeMilliseconds(1_700_000_000_000));

        Uuid7Timestamp.Of(first).ShouldBe(DateTimeOffset.FromUnixTimeMilliseconds(1_500_000_000_000));
        Uuid7Timestamp.Of(second).ShouldBe(DateTimeOffset.FromUnixTimeMilliseconds(1_700_000_000_000));
    }

    [Fact]
    public void AnIdThatIsNotVersionSeven_HasNoTimeToRead()
    {
        Uuid7Timestamp.Of(Guid.Parse("f81d4fae-7dec-41d0-a765-00a0c91e6bf6")).ShouldBeNull();
        Uuid7Timestamp.Of(Guid.Empty).ShouldBeNull();
    }
}
