text: var _ = require('underscore');
  var moment = require('moment');
  var SmoochBot = require('../lib/smooch/smooch-bot');
  var ChatContextStore = require('../lib/chat-context-store');
  var ChatLog = require('../lib/chat-log');
  var helpers = require('../lib/smooch/helpers');
  var clc = require('cli-color');
  
  var DEBUG = false;
  var green = clc.greenBright;
  var white = clc.white;
  var grey = clc.blackBright;
  
  module.exports = function(RED) {
  
    function SmoochBotNode(n) {
      RED.nodes.createNode(this, n);
  
      var self = this;
      this.botname = n.botname;
      this.log = n.log;
  
      this.usernames = [];
      if (n.usernames) {
  
        this.usernames = _(n.usernames.split(',')).chain()
          .map(function(userId) {
            return userId.match(/^[a-zA-Z0-9_]+?$/) ? userId : null
          })
          .compact()
          .value();
      }
  
  
      this.handleMessage = function(botMsg) {
  
  
        var facebookBot = self.bot;
  
        if (DEBUG) {
          // eslint-disable-next-line no-console
          console.log('START:-------');
          // eslint-disable-next-line no-console
          console.log(botMsg);
          // eslint-disable-next-line no-console
          console.log('END:-------');
        }
  
        // mark the original message with the platform
        botMsg.transport = 'smooch';
  
        var userId = botMsg.authorId;
        var chatId = botMsg.authorId;
        var messageId = botMsg._id;
        // todo fix this
        //var isAuthorized = node.config.isAuthorized(username, userId);
        var isAuthorized = true;
        var chatContext = ChatContextStore.getOrCreateChatContext(self, chatId);
  
        // decode the message, eventually download stuff
        self.getMessageDetails(botMsg, self.bot)
          .then(function(payload) {
            // store some information
            chatContext.set('chatId', chatId);
            chatContext.set('messageId', messageId);
            chatContext.set('userId', userId);
            chatContext.set('firstName', botMsg.name);
            chatContext.set('lastName', null);
            chatContext.set('authorized', isAuthorized);
            chatContext.set('transport', 'smooch');
            chatContext.set('message', botMsg.text);
  
            var chatLog = new ChatLog(chatContext);
  
            return chatLog.log({
              payload: payload,
              originalMessage: {
                transport: 'smooch',
                chat: {
                  id: chatId
                }
              },
              chat: function() {
                return ChatContextStore.getChatContext(self, chatId);
              }
            }, self.log)
          })
          .then(function (msg) {
  
            var currentConversationNode = chatContext.get('currentConversationNode');
            // if a conversation is going on, go straight to the conversation node, otherwise if authorized
            // then first pin, if not second pin
            if (currentConversationNode != null) {
              // void the current conversation
              chatContext.set('currentConversationNode', null);
              // emit message directly the node where the conversation stopped
              RED.events.emit('node:' + currentConversationNode, msg);
            } else {
              facebookBot.emit('relay', msg);
            }
  
          })
          .catch(function (error) {
            facebookBot.emit('relay', null, error);
          });
      };
  
  
      if (this.credentials) {
        this.keyId = this.credentials.keyId;
        this.secret = this.credentials.secret;
        if (this.keyId != null && this.secret != null) {
          this.keyId = this.keyId.trim();
          this.secret = this.secret.trim();
  
          if (!this.bot) {
            this.bot = new SmoochBot({
              keyId: this.keyId,
              secret: this.secret
            });
  
            var uiPort = RED.settings.get('uiPort');
            // eslint-disable-next-line no-console
            console.log('');
            // eslint-disable-next-line no-console
            console.log(grey('------ Smooch Webhook ----------------'));
            // eslint-disable-next-line no-console
            console.log(green('Webhook URL: ') + white('http://localhost' + (uiPort != '80' ? ':' + uiPort : '')
                + '/redbot/smooch'));
            // eslint-disable-next-line no-console
            console.log('');
            // mount endpoints on local express
            this.bot.addExpressMiddleware(RED.httpNode);
  
            this.bot.on('message', this.handleMessage);
          }
        }
      }
  
      this.on('close', function (done) {
        self.bot.removeExpressMiddleware(RED.httpNode);
        done();
      });
  
      this.isAuthorized = function (username, userId) {
        if (self.usernames.length > 0) {
          return self.usernames.indexOf(username) != -1 || self.usernames.indexOf(String(userId)) != -1;
        }
        return true;
      };
  
      // creates the message details object from the original message
      this.getMessageDetails = function (message) {
  
        return new Promise(function (resolve, reject) {
  
          var chatId = message.authorId;
          var messageId = message._id;
  
          if (message.mediaUrl != null && message.mediaType.indexOf('image') !== -1) {
  
            helpers.downloadFile(message.mediaUrl)
              .then(function(buffer) {
                resolve({
                  chatId: chatId,
                  messageId: messageId,
                  type: 'photo',
                  content: buffer,
                  date: moment(message.received),
                  inbound: true
                });
              })
              .catch(function() {
                reject('Unable to download ' + message.mediaUrl);
              });
          } else if (!_.isEmpty(message.text)) {
            resolve({
              chatId: chatId,
              messageId: messageId,
              type: 'message',
              content: message.text,
              date: moment(message.received),
              inbound: true
            });
          }
  
  
        });
      }
  
    }
  
    RED.nodes.registerType('chatbot-smooch-node', SmoochBotNode, {
      credentials: {
        keyId: {
          type: 'text'
        },
        secret: {
          type: 'text'
        }
      }
    });
  
    function SmoochInNode(config) {
      RED.nodes.createNode(this, config);
      var node = this;
      this.bot = config.bot;
  
      this.config = RED.nodes.getNode(this.bot);
      if (this.config) {
        this.status({fill: 'red', shape: 'ring', text: 'disconnected'});
  
        node.bot = this.config.bot;
  
        if (node.bot) {
          this.status({fill: 'green', shape: 'ring', text: 'connected'});
  
          node.bot.on('relay', function(message, error) {
            if (error != null) {
              node.error(error);
            } else {
              node.send(message);
            }
          });
  
        } else {
          node.warn('no bot in config.');
        }
      } else {
        node.warn('Missing configuration in Facebook Messenger Receiver');
      }
    }
    RED.nodes.registerType('chatbot-smooch-receive', SmoochInNode);
  
  
    function SmoochOutNode(config) {
      RED.nodes.createNode(this, config);
      var node = this;
      this.bot = config.bot;
      this.track = config.track;
  
      this.config = RED.nodes.getNode(this.bot);
      if (this.config) {
        this.status({fill: 'red', shape: 'ring', text: 'disconnected'});
  
        node.bot = this.config.bot;
  
        if (node.bot) {
          this.status({fill: 'green', shape: 'ring', text: 'connected'});
        } else {
          node.warn('no bot in config.');
        }
      } else {
        node.warn('no config.');
      }
  
      function sendMessage(msg) {
  
        return new Promise(function(resolve, reject) {
  
          var type = msg.payload.type;
          var bot = node.bot;
          //var credentials = node.config.credentials;
  
          var reportError = function(err) {
            if (err) {
              reject(err);
            } else {
              resolve()
            }
          };
  
          switch (type) {
            case 'action':
              // implement actions
              break;
  
            case 'message':
              bot.sendMessage(msg.payload.chatId, msg.payload.content, reportError);
              break;
  
            case 'inline-buttons':
              // docs here https://docs.smooch.io/rest/#action-buttons
              return bot.sendActions(msg.payload.chatId, msg.payload.content, msg.payload.buttons)
                .catch(function(err) {
                  reject(err);
                })
                .then(function() {
                  resolve();
                });
  
            case 'photo':
              var image = msg.payload.content;
              bot.uploadBuffer(msg.payload.chatId, image)
                .catch(function(err) {
                  reject(err);
                })
                .then(function() {
                  resolve();
                });
              break;
  
            default:
              reject('Unable to prepare unknown message type');
          }
  
        });
      }
  
      // relay message
      var handler = function(msg) {
        node.send(msg);
      };
      RED.events.on('node:' + config.id, handler);
  
      // cleanup on close
      this.on('close',function() {
        RED.events.removeListener('node:' + config.id, handler);
      });
  
      this.on('input', function (msg) {
  
        // check if the message is from facebook
        if (msg.originalMessage != null && msg.originalMessage.transport !== 'smooch') {
          // exit, it's not from smooch
          return;
        }
  
        var track = node.track;
        var chatContext = msg.chat();
  
        // check if this node has some wirings in the follow up pin, in that case
        // the next message should be redirected here
        if (chatContext != null && track && !_.isEmpty(node.wires[0])) {
          chatContext.set('currentConversationNode', node.id);
          chatContext.set('currentConversationNode_at', moment());
        }
  
        var chatLog = new ChatLog(chatContext);
  
        chatLog.log(msg, this.config.log)
          .then(function () {
            return sendMessage(msg);
          })
          .catch(function(err) {
            node.error(err);
          });
  
      });
    }
  
    RED.nodes.registerType('chatbot-smooch-send', SmoochOutNode);
  
  };
  