type Level = "info" | "warn" | "error";

type Fields = Record<string, unknown>;

// Keys that must never reach the logs, whatever a caller passes in.
// Keys owned by the logger itself; a caller's field may not overwrite them.
const RESERVED_KEYS = new Set(["time", "level", "event"]);

const REDACTED_KEYS = /pass(word)?|token|secret|cookie|authorization/i;

function sanitize(fields: Fields): Fields {
  const out: Fields = {};
  for (const [key, value] of Object.entries(fields)) {
    if (RESERVED_KEYS.has(key)) {
      out[`field_${key}`] = value;
    } else if (REDACTED_KEYS.test(key)) {
      out[key] = "[redacted]";
    } else if (value instanceof Error) {
      out[key] = { name: value.name, message: value.message, stack: value.stack };
    } else {
      out[key] = value;
    }
  }
  return out;
}

function write(level: Level, event: string, fields: Fields = {}) {
  const line = JSON.stringify({ time: new Date().toISOString(), level, event, ...sanitize(fields) });
  if (level === "error") console.error(line);
  else if (level === "warn") console.warn(line);
  else console.log(line);
}

// One JSON line per event, e.g. {"time":"…","level":"info","event":"auth.login.success","username":"admin"}
export const logger = {
  info: (event: string, fields?: Fields) => write("info", event, fields),
  warn: (event: string, fields?: Fields) => write("warn", event, fields),
  error: (event: string, fields?: Fields) => write("error", event, fields),
};
