namespace NATS.Server;

/// <summary>
/// Per-client trace configuration and echo control.
/// Go reference: server/client.go — c.trace, c.echo fields.
/// </summary>
public sealed class ClientTraceInfo
{
    private bool _traceEnabled;
    private bool _echoEnabled = true; // default: echo is enabled
    private readonly List<TraceRecord> _traceLog = new();
    private readonly Lock _lock = new();

    /// <summary>Whether message delivery tracing is enabled for this client.</summary>
    public bool TraceEnabled
    {
        get => Volatile.Read(ref _traceEnabled);
        set => Volatile.Write(ref _traceEnabled, value);
    }

    /// <summary>Whether this client echoes its own published messages back.</summary>
    public bool EchoEnabled
    {
        get => Volatile.Read(ref _echoEnabled);
        set => Volatile.Write(ref _echoEnabled, value);
    }

    /// <summary>
    /// Records a message delivery trace if tracing is enabled.
    /// Go reference: server/client.go — traceMsg / TraceMsgDelivery.
    /// </summary>
    public void TraceMsgDelivery(string subject, string destination, int payloadSize)
    {
        if (!TraceEnabled) return;
        lock (_lock)
        {
            _traceLog.Add(new TraceRecord
            {
                Subject = subject,
                Destination = destination,
                PayloadSize = payloadSize,
                TimestampUtc = DateTime.UtcNow,
            });
        }
    }

    /// <summary>
    /// Returns whether a message from this client should be delivered back to it.
    /// When echo is disabled, messages published by this client are not delivered to
    /// subscriptions on the same client.
    /// Go reference: server/client.go — c.echo check in deliverMsg.
    /// </summary>
    public bool ShouldEcho(string publisherClientId, string subscriberClientId)
    {
        if (EchoEnabled) return true;
        return !string.Equals(publisherClientId, subscriberClientId, StringComparison.Ordinal);
    }

    /// <summary>Returns all trace records and clears the log.</summary>
    public IReadOnlyList<TraceRecord> DrainTraceLog()
    {
        lock (_lock)
        {
            var copy = _traceLog.ToList();
            _traceLog.Clear();
            return copy;
        }
    }

    /// <summary>Current trace log count.</summary>
    public int TraceLogCount
    {
        get { lock (_lock) return _traceLog.Count; }
    }
}

public sealed record TraceRecord
{
    public string Subject { get; init; } = string.Empty;
    public string Destination { get; init; } = string.Empty;
    public int PayloadSize { get; init; }
    public DateTime TimestampUtc { get; init; }
}
