namespace DeepDrftPublic.Client.Services;

/// <summary>
/// Supplies the client-minted anonymous listener id (Phase 16 §3, wave 16.3, D5 Option A) to the
/// fire-and-forget telemetry sinks. The id is a random first-party <c>localStorage</c> GUID — opaque, no
/// PII, no fingerprinting, clearable. Split into an async warm (<see cref="EnsureLoadedAsync"/>) and a
/// synchronous read (<see cref="Current"/>) so the existing sync emit paths (the beacon sink, the share
/// tracker) need no async signature change: a caller warms the cache when it goes interactive, and the
/// emit then reads the cached value with no JS round-trip on the close/unload path.
///
/// <para>
/// Degrades to null when <c>localStorage</c> is unavailable (private mode / blocked / partitioned
/// third-party iframe) — the sink then omits the id and sends an anonId-less event. Over-counting is the
/// accepted direction of error (§3); a missing id never throws.
/// </para>
/// </summary>
public interface IAnonIdProvider
{
    /// <summary>
    /// The cached anon id, or null if not yet warmed or if storage is unavailable. Synchronous and safe
    /// to read from the player close path and the page-unload handler, neither of which can await.
    /// </summary>
    string? Current { get; }

    /// <summary>
    /// Warm the cache from <c>localStorage</c> via JS interop (minting on first visit). Idempotent — only
    /// the first successful read populates the cache; later calls are no-ops. Best-effort: a JS failure
    /// (interop unavailable during prerender, storage blocked) leaves <see cref="Current"/> null and never
    /// throws.
    /// </summary>
    ValueTask EnsureLoadedAsync();
}
