using Microsoft.Extensions.Options;
using SIGCM2.Application.Audit;
using SIGCM2.Domain.Exceptions;

namespace SIGCM2.Infrastructure.Audit;

/// UDT-010 — IAuditLogger implementation. Enriches from IAuditContext, sanitizes metadata,
/// persists via IAuditEventRepository. Fail-closed: throws AuditContextMissingException
/// when ActorUserId is null (system-emitted events should use a different path).
public sealed class AuditLogger : IAuditLogger
{
    private readonly IAuditContext _context;
    private readonly IAuditEventRepository _repo;
    private readonly IOptions<AuditOptions> _options;
    private readonly TimeProvider _timeProvider;

    public AuditLogger(
        IAuditContext context,
        IAuditEventRepository repo,
        IOptions<AuditOptions> options,
        TimeProvider timeProvider)
    {
        _context = context;
        _repo = repo;
        _options = options;
        _timeProvider = timeProvider;
    }

    public async Task LogAsync(
        string action,
        string targetType,
        string targetId,
        object? metadata = null,
        CancellationToken ct = default)
    {
        if (_context.ActorUserId is null)
            throw new AuditContextMissingException();

        var sanitized = metadata is null
            ? null
            : JsonSanitizer.Sanitize(metadata, _options.Value.SanitizedKeys);

        var correlationId = _context.CorrelationId == Guid.Empty
            ? (Guid?)null
            : _context.CorrelationId;

        await _repo.InsertAsync(
            occurredAt: _timeProvider.GetUtcNow().UtcDateTime,
            actorUserId: _context.ActorUserId,
            actorRoleId: _context.ActorRoleId,
            action: action,
            targetType: targetType,
            targetId: targetId,
            correlationId: correlationId,
            ipAddress: _context.Ip,
            userAgent: _context.UserAgent,
            metadata: sanitized,
            ct: ct);
    }
}
