'use strict';

const mailer = require('nodemailer');
const os = require('os');

/**
 * SMTP Appender. Sends logging events using SMTP protocol.
 * It can either send an email on each event or group several
 * logging events gathered during specified interval.
 *
 * @param _config appender configuration data
 *    config.sendInterval time between log emails (in seconds), if 0
 *    then every event sends an email
 *    config.shutdownTimeout time to give up remaining emails (in seconds; defaults to 5).
 * @param _layout a function that takes a logevent and returns a string (defaults to basicLayout).
 */
function smtpAppender(config, layout, subjectLayout) {
  if (!config.attachment) {
    config.attachment = {};
  }

  config.attachment.enable = !!config.attachment.enable;
  config.attachment.message = config.attachment.message || 'See logs as attachment';
  config.attachment.filename = config.attachment.filename || 'default.log';

  const sendInterval = config.sendInterval * 1000 || 0;
  const shutdownTimeout = ('shutdownTimeout' in config ? config.shutdownTimeout : 5) * 1000;
  const transport = mailer.createTransport(getTransportOptions());
  const logEventBuffer = [];

  let unsentCount = 0;
  let sendTimer;

  function sendBuffer() {
    if (logEventBuffer.length > 0) {
      const firstEvent = logEventBuffer[0];
      let body = '';
      const count = logEventBuffer.length;
      while (logEventBuffer.length > 0) {
        body += `${layout(logEventBuffer.shift(), config.timezoneOffset)}\n`;
      }

      const msg = {
        to: config.recipients,
        subject: config.subject || subjectLayout(firstEvent),
        headers: { Hostname: os.hostname() }
      };

      if (config.attachment.enable === true) {
        msg[config.html ? 'html' : 'text'] = config.attachment.message;
        msg.attachments = [
          {
            filename: config.attachment.filename,
            contentType: 'text/x-log',
            content: body
          }
        ];
      } else {
        msg[config.html ? 'html' : 'text'] = body;
      }

      if (config.sender) {
        msg.from = config.sender;
      }
      transport.sendMail(msg, (error) => {
        if (error) {
          console.error('log4js.smtpAppender - Error happened', error);
        }
        transport.close();
        unsentCount -= count;
      });
    }
  }

  function getTransportOptions() {
    let options = null;
    if (config.SMTP) {
      options = config.SMTP;
    } else if (config.transport) {
      options = config.transport.options || {};
      options.transport = config.transport.plugin || 'smtp';
    }
    return options;
  }

  function scheduleSend() {
    if (!sendTimer) {
      sendTimer = setTimeout(() => {
        sendTimer = null;
        sendBuffer();
      }, sendInterval);
    }
  }

  function shutdown(cb) {
    if (shutdownTimeout > 0) {
      setTimeout(() => {
        if (sendTimer) {
          clearTimeout(sendTimer);
        }

        sendBuffer();
      }, shutdownTimeout);
    }

    (function checkDone() {
      if (unsentCount > 0) {
        setTimeout(checkDone, 100);
      } else {
        cb();
      }
    }());
  }

  const appender = (loggingEvent) => {
    unsentCount++; // eslint-disable-line no-plusplus
    logEventBuffer.push(loggingEvent);
    if (sendInterval > 0) {
      scheduleSend();
    } else {
      sendBuffer();
    }
  };

  appender.shutdown = shutdown;

  return appender;
}

function configure(config, layouts) {
  const subjectLayout = layouts.messagePassThroughLayout;
  let layout = layouts.basicLayout;
  if (config.layout) {
    layout = layouts.layout(config.layout.type, config.layout);
  }
  return smtpAppender(config, layout, subjectLayout);
}


module.exports.configure = configure;
