text: "use strict";
  /**
   * Login API
   *
   * Provides various utilities for managing the login process, including
   * login/logout and import/export of appstate files.
   *
   * Encapsulates the login by caching the appstate in memory.
   *
   * @module login
  */
  var __importDefault = (this && this.__importDefault) || function (mod) {
      return (mod && mod.__esModule) ? mod : { "default": mod };
  };
  Object.defineProperty(exports, "__esModule", { value: true });
  exports.getMemCache = exports.convertToFile = exports.convert = exports.logout = exports.loadLogin = exports.dumpLogin = exports.login = void 0;
  var facebook_chat_api_1 = __importDefault(require("facebook-chat-api")); // Chat API
  var fs_1 = require("fs");
  var argparse_1 = require("argparse");
  var memjs_1 = require("memjs");
  // Default behavior: minimal logging and auto-approve recent logins
  var defaultOptions = {
      "logLevel": "error",
      "forceLogin": true,
      // TODO: Get rid of this option. We currently have to use this outdated user agent to force Facebook
      // to give us an older version of the login page that doesn't include new checks that break the API.
      "userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Mobile Safari/537.36"
  };
  var mem;
  /**
   * Call this to initialize the login module and log into Facebook using
   * [facebook-chat-api](https://github.com/Schmavery/facebook-chat-api).
   * See examples/ for example usage.
   *
   * @param credentials
   * @param callback called after login completed (successfully or unsuccessfully)
   * @param [forceCreds=false] if true, forces a login with credentials even if appstate exists
   * @param [options=defaultOptions] any options you wish to pass to the API on login;
   * by default, sets `logLevel` to `error` and `forceLogin` to `true` (auto-approves errors asking
   * for approval of recent logins for simplicity)
  */
  var login = function (credentials, callback, forceCreds, options) {
      if (forceCreds === void 0) { forceCreds = false; }
      if (options === void 0) { options = defaultOptions; }
      // Initialize mem variable for external storage API (Memcachier)
      mem = memjs_1.Client.create(credentials.MEMCACHIER_SERVERS, {
          username: credentials.MEMCACHIER_USERNAME,
          password: credentials.MEMCACHIER_PASSWORD
      });
      // Login utility funcs
      function withAppstate(appstate, callback) {
          console.log("Logging in with saved appstate...");
          facebook_chat_api_1.default({
              appState: JSON.parse(appstate)
          }, options, function (err, api) {
              if (err) {
                  withCreds(callback);
              }
              else {
                  callback(err, api);
              }
          });
      }
      function withCreds(callback) {
          console.log("Logging in with credentials...");
          if (!credentials.FACEBOOK_EMAIL || !credentials.FACEBOOK_PASSWORD) {
              return console.error("Fatal error: no login credentials provided");
          }
          facebook_chat_api_1.default({
              email: credentials.FACEBOOK_EMAIL,
              password: credentials.FACEBOOK_PASSWORD
          }, options, function (err, api) {
              if (err)
                  return console.error("Fatal error: failed login with credentials");
              mem.set("appstate", JSON.stringify(api.getAppState()), {}, function (merr) {
                  if (err) {
                      return console.error(merr);
                  }
                  else {
                      callback(err, api);
                  }
              });
          });
      }
      if (forceCreds) {
          // Force login with credentials
          withCreds(callback);
      }
      else {
          // Use stored appstate if exists, otherwise fallback to creds
          mem.get("appstate", function (err, val) {
              if (!err && val) {
                  withAppstate(val.toString(), callback);
              }
              else {
                  withCreds(callback);
              }
          });
      }
  };
  exports.login = login;
  /**
   * Dumps the current login into a specified file.
   *
   * @param filename Name of the file specifying where to store the login
   * @param callback Callback to use after writing the file
   */
  var dumpLogin = function (filename, callback) {
      mem.get("appstate", function (err, val) {
          if (!err && val) {
              fs_1.writeFileSync(filename, val.toString());
          }
          callback(err);
      });
  };
  exports.dumpLogin = dumpLogin;
  /**
   * Reads a new login into memory from a file.
   * @param filename Name of the file specifying where the imported login
   * is stored
   * @param callback Callback to use after reading the login
   */
  var loadLogin = function (filename, callback) {
      fs_1.readFile(filename, function (err, val) {
          if (!err) {
              mem.set("appstate", JSON.stringify(JSON.parse(val.toString())), {});
          }
          callback(err);
      });
  };
  exports.loadLogin = loadLogin;
  /**
   * Logs out of Facebook.
   * @param callback
   */
  var logout = function (callback) {
      mem.delete("appstate", function (err) {
          var success = true;
          if (err) {
              console.log("Error logging out: " + err);
              success = false;
          }
          else {
              console.log("Logged out successfully.");
          }
          callback(err, success);
      });
  };
  exports.logout = logout;
  /**
   * Converts a (NodeJS) facebook-chat-api appstate into a (Python) fbchat
   * session. See the examples/ directory for how this can be used to create
   * an fbchat bot with BotCore.
   *
   * @param filename Name of the file whose location contains the
   * appstate data to be converted
   * @param callback Callback to use after conversion completed,
   * passed the converted session
   */
  var convert = function (filename, callback) {
      fs_1.readFile(filename, function (err, file) {
          if (err) {
              callback(err);
          }
          else {
              // Extract the required information from the appstate
              var data_1 = JSON.parse(file.toString());
              var attrs = ["c_user", "datr", "fr", "sb", "spin", "xs"];
              var output = attrs.reduce(function (obj, key) {
                  obj[key] = searchAttribute(data_1, key);
                  return obj;
              }, {});
              output["noscript"] = "1"; // Special attr
              callback(null, output);
          }
      });
  };
  exports.convert = convert;
  /**
   * A variant of `convert` that directly outputs the converted session to a file.
   *
   * @param appstate Location of appstate to be converted
   * @param output Where to place the converted session
   * @param callback Callback called after conversion
   */
  var convertToFile = function (appstate, output, callback) {
      exports.convert(appstate, function (err, session) {
          if (err) {
              callback(err);
          }
          else {
              fs_1.writeFile(output, JSON.stringify(session), null, callback);
          }
      });
  };
  exports.convertToFile = convertToFile;
  /**
   * Exposes the underlying memjs memcache instance, which can be used for
   * temporary storage. Use wisely, or you may break your BotCore installation!
   *
   * > NOTE: if you call this before logging in with {@link login},
   * it will return nothing; the memcache is not initialized until you log in.
   *
   * @returns {Object} The underlying BotCore [memjs](https://memjs.netlify.app)
   * instance
   */
  var getMemCache = function () {
      return mem;
  };
  exports.getMemCache = getMemCache;
  /**
   * facebook-chat-api appstates are an array of objects containing "key" and
   * "value" keys and additional properties (that the Python API doesn't use).
   *
   * This function searches and extracts the value for the given key, discarding
   * the other information.
   *
   * @param data facebook-chat-api appstate
   * @param key The key to locate
   * @returns {string} The value of the key (or null if not found)
  */
  function searchAttribute(data, key) {
      for (var i = 0; i < data.length; i++) {
          if (data[i].key == key) {
              return data[i].value;
          }
      }
      return "";
  }
  if (require.main === module) {
      var parser = new argparse_1.ArgumentParser({ add_help: true });
      parser.add_argument("--MEMCACHIER-USERNAME", { required: true });
      parser.add_argument("--MEMCACHIER-PASSWORD", { required: true });
      parser.add_argument("--MEMCACHIER-SERVERS", { required: true });
      parser.add_argument("--logout", { nargs: 0 });
      parser.add_argument("--dump-login", { nargs: 0 });
      parser.add_argument("--load-login", { nargs: 0 });
      parser.add_argument("--convert-login", { nargs: 0 });
      var args_1 = parser.parse_args();
      exports.login(args_1, function () {
          if (args_1.logout !== null) {
              exports.logout(function () {
                  process.exit();
              });
          }
          else if (args_1.dump_login !== null) {
              exports.dumpLogin("appstate.json", function () {
                  process.exit();
              });
          }
          else if (args_1.load_login !== null) {
              exports.loadLogin("appstate.json", function () {
                  process.exit();
              });
          }
          else if (args_1.convert_login !== null) {
              exports.convertToFile("appstate.json", "session.txt", function () {
                  process.exit();
              });
          }
          else {
              process.exit();
          }
      });
  }
  