using ROLAC.API.Entities.Logging;

namespace ROLAC.API.Services.Logging;

/// <summary>
/// Scoped <see cref="IAuditLogger"/>: fills actor/request context from
/// <see cref="CurrentUserAccessor"/> and enqueues the row onto the shared queue (no direct DB
/// write, so it can't fail a business transaction or recurse through AppDbContext).
/// </summary>
public sealed class AuditLogger : IAuditLogger
{
    private readonly SystemLogQueue      _queue;
    private readonly CurrentUserAccessor _currentUser;

    public AuditLogger(SystemLogQueue queue, CurrentUserAccessor currentUser)
    {
        _queue       = queue;
        _currentUser = currentUser;
    }

    public void Write(
        string action,
        string category,
        LogLevelEnum level = LogLevelEnum.Information,
        string? entityName = null,
        string? entityId = null,
        string? summary = null,
        object? before = null,
        object? after = null,
        string? userId = null,
        string? userEmail = null,
        string? ipAddress = null)
    {
        var log = new AuditLog
        {
            Timestamp     = DateTimeOffset.UtcNow,
            Level         = level,
            Action        = action,
            Category      = category,
            EntityName    = entityName,
            EntityId      = entityId,
            Summary       = summary,
            Changes       = AuditChangeSerializer.BuildChanges(before, after),
            UserId        = userId    ?? _currentUser.UserId,
            UserEmail     = userEmail ?? _currentUser.Email,
            IpAddress     = ipAddress ?? _currentUser.IpAddress,
            CorrelationId = _currentUser.CorrelationId,
        };

        _queue.TryEnqueue(log);
    }
}
