"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.LaunchDarklyUtilsFlags = void 0;

var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));

var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));

var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));

var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));

var _formatJson = _interopRequireDefault(require("format-json"));

var _fastJsonPatch = _interopRequireDefault(require("fast-json-patch"));

var _fs = _interopRequireDefault(require("fs"));

var _lodash = _interopRequireDefault(require("lodash"));

// Class representing Feature flag functionality
var LaunchDarklyUtilsFlags = /*#__PURE__*/function () {
  /**
   * Feature flag specific api functions attached as 'LaunchDarklyUtils.flags'
   * @constructor LaunchDarklyUtilsFlags
   * @param { Swagger } apiClient - generated launchdarkly apiClient
   * @param { Object } log - logger implementation, or 'console'
   * @param { LaunchDarklyUtils } ldUtils - primary utils class
   * @returns { LaunchDarklyUtilsFlags } feature flag api functions
   */
  function LaunchDarklyUtilsFlags(apiClient, log, ldUtils) {
    (0, _classCallCheck2["default"])(this, LaunchDarklyUtilsFlags);
    this.log = log;
    this.apiClient = apiClient;
    this.ldUtils = ldUtils;

    if (!this.ldUtils) {
      throw {
        message: 'LaunchDarklyUtilsRoles constructor requires ldUtils parameter'
      };
    }
  }
  /**
   * Api group object key in LD api
   * @returns {string}
   */


  (0, _createClass2["default"])(LaunchDarklyUtilsFlags, [{
    key: "API_GROUP",
    get: function get() {
      return 'Feature flags';
    }
    /**
     * Get all feature flags in project
     * @param {string} projectKey - project identifier
     * @returns {Promise}
     * @fulfil {Object} feature flag list json
     * @reject {Error} object with message
     * @example ldutils getFeatureFlags my-project
     */

  }, {
    key: "getFeatureFlags",
    value: function () {
      var _getFeatureFlags = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(projectKey) {
        return _regenerator["default"].wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                _context.prev = 0;
                return _context.abrupt("return", this.apiClient.apis[this.API_GROUP].getFeatureFlags({
                  projectKey: projectKey
                }).then(function (response) {
                  return response.body;
                }));

              case 4:
                _context.prev = 4;
                _context.t0 = _context["catch"](0);
                throw {
                  api: 'getFeatureFlags',
                  message: _context.t0.message,
                  docs: 'https://apidocs.launchdarkly.com/docs/list-feature-flags'
                };

              case 7:
              case "end":
                return _context.stop();
            }
          }
        }, _callee, this, [[0, 4]]);
      }));

      function getFeatureFlags(_x) {
        return _getFeatureFlags.apply(this, arguments);
      }

      return getFeatureFlags;
    }()
    /**
     * Get a single feature flag by key, and optional environment
     * @param {string} projectKey - project identifier
     * @param {string} featureFlagKey - feature flag identifier
     * @param {string} environmentKeyQuery - optional environment name
     * @returns {Promise}
     * @fulfil {Object} feature flag json
     * @reject {Error} object with message
     * @example ldutils getFeatureFlag my-project my-flag dev
     */

  }, {
    key: "getFeatureFlag",
    value: function () {
      var _getFeatureFlag = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(projectKey, featureFlagKey, environmentKeyQuery) {
        return _regenerator["default"].wrap(function _callee2$(_context2) {
          while (1) {
            switch (_context2.prev = _context2.next) {
              case 0:
                _context2.prev = 0;
                return _context2.abrupt("return", this.apiClient.apis[this.API_GROUP].getFeatureFlag({
                  projectKey: projectKey,
                  featureFlagKey: featureFlagKey,
                  env: environmentKeyQuery
                }).then(function (response) {
                  return response.body;
                }));

              case 4:
                _context2.prev = 4;
                _context2.t0 = _context2["catch"](0);
                throw {
                  api: 'getFeatureFlag',
                  message: _context2.t0.message,
                  docs: 'https://apidocs.launchdarkly.com/docs/get-feature-flag'
                };

              case 7:
              case "end":
                return _context2.stop();
            }
          }
        }, _callee2, this, [[0, 4]]);
      }));

      function getFeatureFlag(_x2, _x3, _x4) {
        return _getFeatureFlag.apply(this, arguments);
      }

      return getFeatureFlag;
    }()
    /**
     * Get the boolean state of a single feature flag by key, and optional environment
     * @param {string} projectKey - project identifier
     * @param {string} featureFlagKey - feature flag identifier
     * @param {string} environmentKeyQuery - environment name
     * @returns {Promise}
     * @fulfil {boolean} true/false
     * @reject {Error} object with message
     * @example ldutils getFeatureFlagState my-project my-flag dev
     */

  }, {
    key: "getFeatureFlagState",
    value: function () {
      var _getFeatureFlagState = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3(projectKey, featureFlagKey, environmentKeyQuery) {
        return _regenerator["default"].wrap(function _callee3$(_context3) {
          while (1) {
            switch (_context3.prev = _context3.next) {
              case 0:
                return _context3.abrupt("return", this.getFeatureFlag(projectKey, featureFlagKey, environmentKeyQuery).then(function (result) {
                  return result.environments[environmentKeyQuery].on;
                }));

              case 1:
              case "end":
                return _context3.stop();
            }
          }
        }, _callee3, this);
      }));

      function getFeatureFlagState(_x5, _x6, _x7) {
        return _getFeatureFlagState.apply(this, arguments);
      }

      return getFeatureFlagState;
    }()
    /**
     * patch a feature flag by key
     * @param {string} projectKey - project identifier
     * @param {string} featureFlagKey - feature flag identifier
     * @param {Array<Object>} patchComment - array of valid json patch descriptors
     * @returns {Promise}
     * @fulfil {Object} updated feature flag json
     * @reject {Error} object with message
     * @example ldutils updateFeatureFlag my-project my-flag {jsonPatch}
     */

  }, {
    key: "updateFeatureFlag",
    value: function () {
      var _updateFeatureFlag = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4(projectKey, featureFlagKey, patchComment) {
        return _regenerator["default"].wrap(function _callee4$(_context4) {
          while (1) {
            switch (_context4.prev = _context4.next) {
              case 0:
                _context4.prev = 0;
                return _context4.abrupt("return", this.apiClient.apis[this.API_GROUP].patchFeatureFlag({
                  projectKey: projectKey,
                  featureFlagKey: featureFlagKey,
                  patchComment: patchComment
                }).then(function (response) {
                  return response.body;
                }));

              case 4:
                _context4.prev = 4;
                _context4.t0 = _context4["catch"](0);
                throw {
                  api: 'patchFeatureFlag',
                  message: _context4.t0.message,
                  docs: 'https://apidocs.launchdarkly.com/docs/update-feature-flag'
                };

              case 7:
              case "end":
                return _context4.stop();
            }
          }
        }, _callee4, this, [[0, 4]]);
      }));

      function updateFeatureFlag(_x8, _x9, _x10) {
        return _updateFeatureFlag.apply(this, arguments);
      }

      return updateFeatureFlag;
    }()
    /**
     * Set the boolean state of a single feature flag by key, and environment name
     * @param {string} projectKey - project identifier
     * @param {string} featureFlagKey - feature flag identifier
     * @param {string} environmentKeyQuery - environment name
     * @param {boolean} value - true or false
     * @returns {Promise}
     * @fulfil {Object} updated feature flag json
     * @reject {Error} object with message
     * @example ldutils toggleFeatureFlag my-project my-flag dev true
     */

  }, {
    key: "toggleFeatureFlag",
    value: function () {
      var _toggleFeatureFlag = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee5(projectKey, featureFlagKey, environmentKeyQuery, value) {
        return _regenerator["default"].wrap(function _callee5$(_context5) {
          while (1) {
            switch (_context5.prev = _context5.next) {
              case 0:
                return _context5.abrupt("return", this.updateFeatureFlag(projectKey, featureFlagKey, [{
                  op: 'replace',
                  path: "/environments/".concat(environmentKeyQuery, "/on"),
                  value: value
                }]));

              case 1:
              case "end":
                return _context5.stop();
            }
          }
        }, _callee5, this);
      }));

      function toggleFeatureFlag(_x11, _x12, _x13, _x14) {
        return _toggleFeatureFlag.apply(this, arguments);
      }

      return toggleFeatureFlag;
    }()
    /**
     * Migrate feature flag properties between environments in a project. this includes:
     * targets, rules, fallthrough, offVariation, prerequisites and optionally the flags on/off state.
     * @param {string} projectKey - project identifier
     * @param {string} featureFlagKey - feature flag identifier
     * @param {string} fromEnv - environment to copy flag attributes from
     * @param {string} toEnv - environment to copy flag attributes to
     * @param {boolean} includeState - optionally copy boolean state true/false
     * @returns {Promise}
     * @fulfil {Object} updated feature flag json
     * @reject {Error} object with message
     * @example ldutils migrateFeatureFlag my-project my-flag dev test
     */

  }, {
    key: "migrateFeatureFlag",
    value: function () {
      var _migrateFeatureFlag = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee6(projectKey, featureFlagKey, fromEnv, toEnv, includeState) {
        var _this = this;

        var that;
        return _regenerator["default"].wrap(function _callee6$(_context6) {
          while (1) {
            switch (_context6.prev = _context6.next) {
              case 0:
                that = this;
                return _context6.abrupt("return", this.getFeatureFlag(projectKey, featureFlagKey).then(function (flag) {
                  var patchDelta = _fastJsonPatch["default"].compare(flag.environments[toEnv], flag.environments[fromEnv]);

                  that.log.debug("flagDelta for '".concat(featureFlagKey, "' ").concat(_formatJson["default"].plain(patchDelta)));
                  return patchDelta;
                }).then(function (patchDelta) {
                  var patchComment = _this.assembleFlagPatch(patchDelta, toEnv, includeState);

                  that.log.debug("patchComment for '".concat(featureFlagKey, "' in ").concat(toEnv, " : ").concat(_formatJson["default"].plain(patchComment)));
                  return _this.updateFeatureFlag(projectKey, featureFlagKey, patchComment);
                }));

              case 2:
              case "end":
                return _context6.stop();
            }
          }
        }, _callee6, this);
      }));

      function migrateFeatureFlag(_x15, _x16, _x17, _x18, _x19) {
        return _migrateFeatureFlag.apply(this, arguments);
      }

      return migrateFeatureFlag;
    }()
  }, {
    key: "assembleFlagPatch",
    value: function assembleFlagPatch(patchDelta, targetEnv, includeState) {
      var patchComment = [];
      patchDelta.forEach(function (patch) {
        if (patch.path.startsWith('/targets') || patch.path.startsWith('/rules') || patch.path.startsWith('/fallthrough') || patch.path.startsWith('/offVariation') || patch.path.startsWith('/prerequisites') || includeState && patch.path.startsWith('/on')) {
          // add target env obj path and push
          patch.path = "/environments/".concat(targetEnv).concat(patch.path);
          patchComment.push(patch);
        }
      });
      return patchComment;
    }
    /**
     * Migrate multiple feature flags properties between environments in a project. this includes:
     * targets, rules, fallthrough, offVariation, prerequisites and optionally the flags on/off state.
     * @param {string} projectKey - project identifier
     * @param {string} featureFlagKeys - comma-separated feature flag identifiers
     * @param {string} fromEnv - environment to copy flag attributes from
     * @param {string} toEnv - environment to copy flag attributes to
     * @param {boolean} includeState - optionally copy boolean state true/false
     * @returns {Promise}
     * @fulfil {Object} updated feature flag json array
     * @reject {Error} object with message
     * @example ldutils bulkMigrateFeatureFlags my-project my-flag,my-flag-two dev test
     */

  }, {
    key: "bulkMigrateFeatureFlags",
    value: function () {
      var _bulkMigrateFeatureFlags = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee7(projectKey, featureFlagKeys, fromEnv, toEnv, includeState) {
        var _this2 = this;

        var promises;
        return _regenerator["default"].wrap(function _callee7$(_context7) {
          while (1) {
            switch (_context7.prev = _context7.next) {
              case 0:
                promises = [];
                featureFlagKeys.split(',').forEach(function (key) {
                  promises.push(_this2.migrateFeatureFlag(projectKey, key, fromEnv, toEnv, includeState));
                });
                return _context7.abrupt("return", Promise.all(promises));

              case 3:
              case "end":
                return _context7.stop();
            }
          }
        }, _callee7);
      }));

      function bulkMigrateFeatureFlags(_x20, _x21, _x22, _x23, _x24) {
        return _bulkMigrateFeatureFlags.apply(this, arguments);
      }

      return bulkMigrateFeatureFlags;
    }()
    /**
     * Restore feature flags to state captured in a backup json file generated by getFeatureFlags(proj).
     * @param {string} projectKey - project identifier
     * @param {string} featureFlagKeys - feature flag identifiers comma separated
     * @param {string} targetEnv - environment to restore flag attributes to
     * @param {string} backupJsonFile - file to restore from from getFeatureFlags(proj)
     * @param {boolean} includeState - optionally restore boolean state true/false
     * @returns {Promise}
     * @fulfil {Object} updated feature flag json
     * @reject {Error} object with message
     * @example ldutils restoreFeatureFlags my-project my-flag,my-flag-two prod ./preReleaseBackup.json true
     */

  }, {
    key: "restoreFeatureFlags",
    value: function () {
      var _restoreFeatureFlags = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee8(projectKey, featureFlagKeys, targetEnv, backupJsonFile, includeState) {
        var _this3 = this;

        var that, promises, backupJson;
        return _regenerator["default"].wrap(function _callee8$(_context8) {
          while (1) {
            switch (_context8.prev = _context8.next) {
              case 0:
                that = this;
                promises = [];
                backupJson = JSON.parse(_fs["default"].readFileSync(process.cwd() + '/' + backupJsonFile, 'utf-8')); //foreach flag, lookup node in env branch

                featureFlagKeys.split(',').forEach(function (key) {
                  promises.push(_this3.getFeatureFlag(projectKey, key).then(function (flag) {
                    var backupFlagArr = _lodash["default"].filter(backupJson.items, {
                      key: key
                    });

                    if (backupFlagArr.length === 0) {
                      that.log.error("flag does not exist in backup: ".concat(key));
                    }

                    var backupFlag = backupFlagArr[0];
                    that.log.debug("backupFlag: ".concat(_formatJson["default"].plain(backupFlag)));

                    var patchDelta = _fastJsonPatch["default"].compare(flag.environments[targetEnv], backupFlag.environments[targetEnv]);

                    that.log.debug("flagDelta for '".concat(key, "' ").concat(_formatJson["default"].plain(patchDelta)));
                    return patchDelta;
                  }).then(function (patchDelta) {
                    var patchComment = _this3.assembleFlagPatch(patchDelta, targetEnv, includeState);

                    that.log.debug("patchComment for '".concat(key, "' in ").concat(targetEnv, " : ").concat(_formatJson["default"].plain(patchComment)));
                    return _this3.updateFeatureFlag(projectKey, key, patchComment);
                  }));
                });
                return _context8.abrupt("return", Promise.all(promises));

              case 5:
              case "end":
                return _context8.stop();
            }
          }
        }, _callee8, this);
      }));

      function restoreFeatureFlags(_x25, _x26, _x27, _x28, _x29) {
        return _restoreFeatureFlags.apply(this, arguments);
      }

      return restoreFeatureFlags;
    }()
  }]);
  return LaunchDarklyUtilsFlags;
}();

exports.LaunchDarklyUtilsFlags = LaunchDarklyUtilsFlags;