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

namespace SIGCM2.Infrastructure.Audit;

/// UDT-010 — ISecurityEventLogger implementation. Unlike AuditLogger this is NOT
/// fail-closed on missing actor: login failures have no ActorUserId by design.
/// Ip/UserAgent are pulled from IAuditContext when available (null in pre-auth paths).
public sealed class SecurityEventLogger : ISecurityEventLogger
{
    private readonly ISecurityEventRepository _repo;
    private readonly IAuditContext _context;
    private readonly IOptions<AuditOptions> _options;
    private readonly TimeProvider _timeProvider;

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

    public async Task LogAsync(
        string action,
        string result,
        int? actorUserId = null,
        string? attemptedUsername = null,
        Guid? sessionId = null,
        string? failureReason = null,
        object? metadata = null,
        CancellationToken ct = default)
    {
        var sanitized = metadata is null
            ? null
            : JsonSanitizer.Sanitize(metadata, _options.Value.SanitizedKeys);

        await _repo.InsertAsync(
            occurredAt: _timeProvider.GetUtcNow().UtcDateTime,
            actorUserId: actorUserId,
            attemptedUsername: attemptedUsername,
            sessionId: sessionId,
            action: action,
            result: result,
            failureReason: failureReason,
            ipAddress: _context.Ip,
            userAgent: _context.UserAgent,
            metadata: sanitized,
            ct: ct);
    }
}
