using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Transport;

namespace ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Services;

/// <summary>
/// Holder for the active bundle import id, backed by an <see cref="AsyncLocal{T}"/>
/// so each logical asynchronous call chain observes its own value. AuditService
/// reads it while writing AuditLogEntry rows.
/// <para>
/// Thread-safety / concurrency contract: the previous Scoped
/// instance with a plain auto-property mutated by <c>BundleImporter.ApplyAsync</c>
/// was vulnerable to cross-contamination if two imports ran concurrently inside
/// a shared DI scope — either via <c>Task.WhenAll</c> on a single Blazor circuit
/// or via a misconfigured singleton registration. Backing the property with
/// <see cref="AsyncLocal{T}"/> means every fresh logical-call-context — every
/// distinct <c>ApplyAsync</c> invocation, even ones sharing the same DI scope —
/// gets its own independent value, and the value flows naturally through every
/// <c>await</c> in the chain. Concurrent imports no longer leak BundleImportIds
/// across audit rows.
/// </para>
/// <para>
/// The class is still registered as Scoped so injection works with the existing
/// DI graph, but its in-memory state is per-call-context regardless of lifetime.
/// </para>
/// </summary>
public sealed class AuditCorrelationContext : IAuditCorrelationContext
{
    private static readonly AsyncLocal<Guid?> _bundleImportId = new();

    /// <inheritdoc />
    public Guid? BundleImportId
    {
        get => _bundleImportId.Value;
        set => _bundleImportId.Value = value;
    }
}
