const logger = require("../utils/logger");

/**
 * Convert an Error object to a plain object for serialization.
 * @param err
 * @returns {{[p: string]: unknown, name: *, message: *, stack: *}|null}
 */
const toPlainError = (err) => {
  if (!err) return null;
  return {
    name: err.name,
    message: err.message,
    stack: err.stack,
    ...Object.fromEntries(Object.entries(err).filter(([k]) => !["stack"].includes(k)))
  };
};

/**
 * Safely serialize meta information for logging.
 * @param meta
 * @returns {{note: string}|any|{[p: string]: *, name: *, message: *, stack: *}|null}
 */
const safeMeta = (meta) => {
  try {
    if (meta instanceof Error) return toPlainError(meta);
    if (meta && typeof meta === "object") {
      // JSON-safe clone w/ BigInt -> string
      return JSON.parse(JSON.stringify(meta, (_k, v) => (typeof v === "bigint" ? v.toString() : v)));
    }
    return meta ?? null;
  } catch {
    return { note: "meta not serializable" };
  }
};

/**
 * Create and emit a Reynolds log event.
 * @param socket
 * @param level
 * @param message
 * @param meta
 * @returns {{timestamp: number, level: string, message: string|string, meta: {note: string}|*|{[p: string]: *, name: *, message: *, stack: *}|null}}
 * @constructor
 */
const CreateRRLogEvent = (socket, level = "INFO", message = "", meta = null) => {
  const ts = Date.now();
  const lvl = String(level || "INFO").toUpperCase();
  const normLevel = lvl.toLowerCase();
  const msg = typeof message === "string" ? message : (message?.toString?.() ?? JSON.stringify(message));

  const payload = {
    timestamp: ts,
    level: lvl,
    message: msg,
    meta: safeMeta(meta)
  };

  // Central logger (Winston + CloudWatch + S3)
  try {
    // user = "RR", record = null, meta = payload.meta
    logger.log(`[RR]  ${msg}`, normLevel, "RR", null, payload.meta);
  } catch {
    // Fallback console
    console.log(`[RR] ${new Date(ts).toISOString()} | ${lvl} | ${msg}`, payload.meta);
  }

  // Socket
  try {
    socket?.emit?.("rr-log-event", payload);
  } catch {
    // ignore socket failures
  }

  return payload;
};

module.exports = CreateRRLogEvent;
