namespace DodoSSH.Client.Domain;
///
/// Reads the moment a version 7 identifier was created back out of it.
///
///
///
/// Why this exists. No vault item carries a timestamp. VaultItem is an id, a secret, a version
/// and three sync flags, and the server's created_at is deliberately not handed back — so a screen
/// that wants to say when something was added has nothing to read. Every id this client mints goes through
/// , which is banned-symbol policy rather than preference (see
/// BannedSymbols.txt), and RFC 9562 puts 48 bits of Unix milliseconds in the first six bytes of one.
/// That is a real creation time, already stored, costing nothing.
///
///
/// What it is not. It is when the item was created, never when it was last changed — an
/// update keeps the id. A screen showing this has to say so, or it is quietly presenting a creation date as
/// a modification date. And an id minted anywhere else, by an older client or another implementation, is not
/// a v7 at all; that case answers null rather than a number derived from bytes that mean something else.
///
///
public static class Uuid7Timestamp
{
/// Where the version nibble lives in the RFC byte order.
private const int VersionByte = 6;
///
/// The creation time recorded in a version 7 identifier, or null if it is not one.
///
public static DateTimeOffset? Of(Guid id)
{
Span bytes = stackalloc byte[16];
// Big-endian, which is the whole reason this is not two lines of shifting. Guid's own layout stores
// its first three fields in the host's byte order, so the little-endian overload scrambles exactly
// the six bytes being read here — and does it silently, producing dates in the year 30000 rather
// than an error.
if (!id.TryWriteBytes(bytes, bigEndian: true, out _))
{
return null;
}
if ((bytes[VersionByte] & 0xF0) != 0x70)
{
return null;
}
long milliseconds = 0;
for (var i = 0; i < 6; i++)
{
milliseconds = (milliseconds << 8) | bytes[i];
}
return DateTimeOffset.FromUnixTimeMilliseconds(milliseconds);
}
}