import createDebug from 'debug';

const debug = createDebug('console-capture');

function setupConsoleCapture() {
  // Elements are either console call argument arrays or the
  // truncation warning string.
  let outputLines: Array<unknown[] | string> = [];
  let truncated = false;
  let currentSize = 0;
  let sendFromIndex = 0;

  const MAX_RETAINED_LOG_SIZE_MB = Number(
    process.env.MAX_RETAINED_LOG_SIZE_MB || '50'
  );
  const MAX_RETAINED_LOG_SIZE = MAX_RETAINED_LOG_SIZE_MB * 1024 * 1024;

  const interval = setInterval(() => {
    if (!truncated && outputLines.length - sendFromIndex > 0) {
      const newBatch = outputLines.slice(sendFromIndex, outputLines.length);
      sendFromIndex = outputLines.length;
      global.artillery.globalEvents.emit('logLines', newBatch, Date.now());
    }
  }, 10 * 1000).unref();

  global.artillery.ext({
    ext: 'onShutdown',
    method: async () => {
      debug('onBeforeExit', sendFromIndex, outputLines.length);
      clearInterval(interval);

      if (!truncated && sendFromIndex < outputLines.length) {
        const ts = Date.now();
        global.artillery.globalEvents.emit(
          'logLines',
          outputLines.slice(sendFromIndex, outputLines.length),
          ts,
          true
        );
        sendFromIndex = outputLines.length;
      }
    }
  });

  console.log = (() => {
    const orig = console.log;
    return (...args) => {
      try {
        orig.apply(console, args);

        if (currentSize < MAX_RETAINED_LOG_SIZE) {
          outputLines = outputLines.concat([args]);
          for (const x of args) {
            currentSize += String(x).length;
          }
        } else {
          if (!truncated) {
            truncated = true;
            const msg = `[WARNING] Artillery: maximum retained log size exceeded, max size: ${MAX_RETAINED_LOG_SIZE_MB}MB. Further logs won't be retained.\n\n`;
            process.stdout.write(msg);
            outputLines = outputLines.concat([msg]);
          }
        }
      } catch (err) {
        debug(err);
      }
    };
  })();

  console.error = (() => {
    const orig = console.error;
    return (...args) => {
      try {
        orig.apply(console, args);

        if (currentSize < MAX_RETAINED_LOG_SIZE) {
          outputLines = outputLines.concat([args]);
          for (const x of args) {
            currentSize += String(x).length;
          }
        } else {
          if (!truncated) {
            truncated = true;
            const msg = `[WARNING] Artillery: maximum retained log size exceeded, max size: ${MAX_RETAINED_LOG_SIZE_MB}MB. Further logs won't be retained.\n\n`;
            process.stdout.write(msg);
            outputLines = outputLines.concat([msg]);
          }
        }
      } catch (err) {
        debug(err);
      }
    };
  })();
}

export default setupConsoleCapture;
