namespace ZB.MOM.WW.ScadaBridge.Commons.Types;

/// <summary>
/// Strongly-typed identifier for a cached outbound operation
/// (<c>ExternalSystem.CachedCall</c> / <c>Database.CachedWrite</c>) — the unified
/// tracking handle introduced by Audit Log. The same id is the
/// idempotency key end-to-end: it is stamped on every <c>AuditLog</c> row
/// produced for the operation's lifecycle (CachedSubmit → ApiCallCached /
/// DbWriteCached × N attempts → CachedResolve) and is the PK on the central
/// <c>SiteCalls</c> row that mirrors the operation's operational state.
/// </summary>
/// <remarks>
/// <para>
/// The struct wraps a <see cref="Guid"/> so it serialises identically to a
/// 36-character "D"-format string anywhere the existing GUID conventions are
/// used (gRPC strings, JSON, SQL TEXT columns). <see cref="ToString"/> returns
/// the lower-case 8-4-4-4-12 form unconditionally; never the brace- / parens-
/// wrapped variants — central ingest parses with <see cref="Guid.Parse"/>, which
/// is format-tolerant but the wire shape is fixed for log readability.
/// </para>
/// </remarks>
public readonly record struct TrackedOperationId(Guid Value)
{
    /// <summary>Mint a fresh id at the call site (script-thread safe).</summary>
    /// <returns>A new <see cref="TrackedOperationId"/> wrapping a freshly generated GUID.</returns>
    public static TrackedOperationId New() => new(Guid.NewGuid());

    /// <summary>
    /// Parse a serialised id back into the strong type. Throws when the input
    /// is not a valid GUID — callers crossing untrusted boundaries should use
    /// <see cref="TryParse"/> instead.
    /// </summary>
    /// <param name="s">GUID string to parse.</param>
    /// <returns>A <see cref="TrackedOperationId"/> wrapping the parsed GUID.</returns>
    public static TrackedOperationId Parse(string s) => new(Guid.Parse(s));

    /// <summary>
    /// Attempt to parse a serialised id. Returns <c>false</c> for null, empty
    /// or non-GUID input; <paramref name="result"/> is <c>default</c> on
    /// failure.
    /// </summary>
    /// <param name="s">GUID string to parse, or null.</param>
    /// <param name="result">Parsed value on success; default on failure.</param>
    /// <returns><c>true</c> if the string was successfully parsed; otherwise <c>false</c>.</returns>
    public static bool TryParse(string? s, out TrackedOperationId result)
    {
        if (Guid.TryParse(s, out var g))
        {
            result = new TrackedOperationId(g);
            return true;
        }

        result = default;
        return false;
    }

    /// <inheritdoc/>
    public override string ToString() => Value.ToString("D");
}
