using System.Threading.Channels;
using ROLAC.API.Entities.Logging;

namespace ROLAC.API.Services.Logging;

/// <summary>
/// A singleton, bounded in-memory queue decoupling log producers (the ILogger hot path, the
/// audit interceptor, singleton services) from the single background DB writer. Enqueue is a
/// non-blocking <c>TryWrite</c>; when full the OLDEST entry is dropped (DropWrite) rather than
/// blocking a request thread or throwing — logging must never throw or stall business code.
/// Carries both SystemLog and AuditLog rows via a small union envelope.
/// </summary>
public sealed class SystemLogQueue
{
    private readonly Channel<LogEnvelope> _channel =
        Channel.CreateBounded<LogEnvelope>(new BoundedChannelOptions(capacity: 4096)
        {
            FullMode = BoundedChannelFullMode.DropWrite,
            SingleReader = true,
            SingleWriter = false,
        });

    public bool TryEnqueue(SystemLog log) => _channel.Writer.TryWrite(new LogEnvelope(log, null));

    public bool TryEnqueue(AuditLog log) => _channel.Writer.TryWrite(new LogEnvelope(null, log));

    public IAsyncEnumerable<LogEnvelope> ReadAllAsync(CancellationToken cancellationToken) =>
        _channel.Reader.ReadAllAsync(cancellationToken);
}

/// <summary>Either a SystemLog or an AuditLog — exactly one is non-null.</summary>
public sealed record LogEnvelope(SystemLog? System, AuditLog? Audit);
