import AuditLog from '../models/AuditLog.js';

const SENSITIVE_KEY = /(password|passwd|secret|token|authorization|jwt|credential|apikey|api_key)/i;

// Recursively strip sensitive values so they can never reach the audit trail.
const redact = (value, depth = 0) => {
  if (depth > 4) return '[depth-limit]';
  if (Array.isArray(value)) return value.slice(0, 50).map((v) => redact(v, depth + 1));
  if (value && typeof value === 'object') {
    const out = {};
    for (const [k, v] of Object.entries(value)) {
      out[k] = SENSITIVE_KEY.test(k) ? '[redacted]' : redact(v, depth + 1);
    }
    return out;
  }
  if (typeof value === 'string' && value.length > 500) return `${value.slice(0, 500)}…`;
  return value;
};

const clientIp = (req) => {
  if (!req) return '';
  const fwd = req.headers?.['x-forwarded-for'];
  if (typeof fwd === 'string' && fwd.trim()) return fwd.split(',')[0].trim();
  return req.ip || req.socket?.remoteAddress || '';
};

const logAudit = async (req, action, entity, entityId = '', meta = {}, extra = {}) => {
  try {
    await AuditLog.create({
      user: req.user
        ? { id: req.user._id, name: req.user.name, role: req.user.role || '' }
        : { id: null, name: 'system', role: '' },
      action,
      entity,
      entityId: entityId ? String(entityId) : '',
      description: extra.description || meta.description || '',
      ip: clientIp(req),
      before: extra.before !== undefined ? redact(extra.before) : null,
      after: extra.after !== undefined ? redact(extra.after) : null,
      meta: redact(meta),
    });
  } catch {
    // auditing must never break the primary operation
  }
};

export default logAudit;
