text: "use strict";
  Object.defineProperty(exports, "__esModule", { value: true });
  exports.UserApi = void 0;
  var tslib_1 = require("tslib");
  var cache_decorators_1 = require("@d-fischer/cache-decorators");
  var shared_utils_1 = require("@d-fischer/shared-utils");
  var twitch_api_call_1 = require("twitch-api-call");
  var twitch_common_1 = require("twitch-common");
  var NoSubscriptionProgramError_1 = require("../../../Errors/NoSubscriptionProgramError");
  var BaseApi_1 = require("../../BaseApi");
  var EmoteSetList_1 = require("../Channel/EmoteSetList");
  var PrivilegedUser_1 = require("./PrivilegedUser");
  var User_1 = require("./User");
  var UserBlock_1 = require("./UserBlock");
  var UserChatInfo_1 = require("./UserChatInfo");
  var UserFollow_1 = require("./UserFollow");
  var UserSubscription_1 = require("./UserSubscription");
  /**
   * The API methods that deal with users.
   *
   * Can be accessed using `client.kraken.users` on an {@ApiClient} instance.
   *
   * ## Example
   * ```ts
   * const api = new ApiClient(new StaticAuthProvider(clientId, accessToken));
   * const user = await api.kraken.users.getUser('125328655');
   * ```
   */
  var UserApi = /** @class */ (function (_super) {
      tslib_1.__extends(UserApi, _super);
      function UserApi() {
          var _this = _super !== null && _super.apply(this, arguments) || this;
          _this._userByNameCache = new Map();
          return _this;
      }
      /**
       * Retrieves the user data of the currently authenticated user.
       */
      UserApi.prototype.getMe = function () {
          return tslib_1.__awaiter(this, void 0, void 0, function () {
              var _a;
              return tslib_1.__generator(this, function (_b) {
                  switch (_b.label) {
                      case 0:
                          _a = PrivilegedUser_1.PrivilegedUser.bind;
                          return [4 /*yield*/, this._client.callApi({ url: 'user', scope: 'user_read' })];
                      case 1: return [2 /*return*/, new (_a.apply(PrivilegedUser_1.PrivilegedUser, [void 0, _b.sent(), this._client]))()];
                  }
              });
          });
      };
      /**
       * Retrieves the user data for the given user ID.
       *
       * @param userId The user ID you want to look up.
       */
      UserApi.prototype.getUser = function (userId) {
          return tslib_1.__awaiter(this, void 0, void 0, function () {
              var userData;
              return tslib_1.__generator(this, function (_a) {
                  switch (_a.label) {
                      case 0: return [4 /*yield*/, this._client.callApi({ url: "users/" + twitch_common_1.extractUserId(userId) })];
                      case 1:
                          userData = _a.sent();
                          // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
                          if (!userData) {
                              throw new twitch_common_1.HellFreezesOverError('Could not get authenticated user');
                          }
                          return [2 /*return*/, new User_1.User(userData, this._client)];
                  }
              });
          });
      };
      /**
       * Retrieves the user data for the given user name.
       *
       * @param userName The user name you want to look up.
       */
      UserApi.prototype.getUserByName = function (userName) {
          return tslib_1.__awaiter(this, void 0, void 0, function () {
              var users, user;
              return tslib_1.__generator(this, function (_a) {
                  switch (_a.label) {
                      case 0:
                          // not using the decorator's cache here as users-by-name is slightly more complex to cache
                          this._cleanUserCache();
                          if (this._userByNameCache.has(userName)) {
                              return [2 /*return*/, this._userByNameCache.get(userName).value];
                          }
                          return [4 /*yield*/, this._client.callApi({
                                  url: 'users',
                                  query: { login: userName }
                              })];
                      case 1:
                          users = (_a.sent()).users;
                          if (users.length === 0) {
                              return [2 /*return*/, null];
                          }
                          user = new User_1.User(users[0], this._client);
                          this._userByNameCache.set(userName, {
                              value: user,
                              expires: Date.now() + 3600 * 1000
                          });
                          return [2 /*return*/, user];
                  }
              });
          });
      };
      /**
       * Retrieves the user data for the given user names.
       *
       * @param userNames The user names you want to look up.
       */
      UserApi.prototype.getUsersByNames = function (userNames) {
          return tslib_1.__awaiter(this, void 0, void 0, function () {
              var cachedEntries, cachedObject, cachedUsers, toFetch, usersData, usersArr, users;
              var _this = this;
              return tslib_1.__generator(this, function (_a) {
                  switch (_a.label) {
                      case 0:
                          this._cleanUserCache();
                          userNames = userNames.map(function (name) { return name.toLowerCase(); });
                          cachedEntries = Array.from(this._userByNameCache.entries()).filter(function (_a) {
                              var _b = tslib_1.__read(_a, 1), key = _b[0];
                              return userNames.includes(key);
                          });
                          cachedObject = shared_utils_1.entriesToObject(cachedEntries);
                          cachedUsers = shared_utils_1.mapObject(cachedObject, function (entry) { return entry.value; });
                          toFetch = userNames.filter(function (name) { return !(name in cachedUsers); });
                          if (!toFetch.length) {
                              return [2 /*return*/, cachedUsers];
                          }
                          return [4 /*yield*/, this._client.callApi({
                                  url: 'users',
                                  query: { login: toFetch.join(',') }
                              })];
                      case 1:
                          usersData = _a.sent();
                          usersArr = usersData.users.map(function (data) { return new User_1.User(data, _this._client); });
                          usersArr.forEach(function (user) {
                              return _this._userByNameCache.set(user.name, {
                                  value: user,
                                  expires: Date.now() + 3600 * 1000
                              });
                          });
                          users = shared_utils_1.indexBy(usersArr, 'name');
                          return [2 /*return*/, tslib_1.__assign(tslib_1.__assign({}, cachedUsers), users)];
                  }
              });
          });
      };
      /**
       * Retrieves information about the user's chat appearance and privileges.
       *
       * @param user The user you want to get chat info for.
       */
      UserApi.prototype.getChatInfo = function (user) {
          return tslib_1.__awaiter(this, void 0, void 0, function () {
              var userId, data;
              return tslib_1.__generator(this, function (_a) {
                  switch (_a.label) {
                      case 0:
                          userId = twitch_common_1.extractUserId(user);
                          return [4 /*yield*/, this._client.callApi({ url: "users/" + userId + "/chat" })];
                      case 1:
                          data = _a.sent();
                          return [2 /*return*/, new UserChatInfo_1.UserChatInfo(data, this._client)];
                  }
              });
          });
      };
      /**
       * Retrieves the emotes a given user can use.
       *
       * @param user The user you want to get emotes for.
       */
      UserApi.prototype.getUserEmotes = function (user) {
          return tslib_1.__awaiter(this, void 0, void 0, function () {
              var userId, data;
              return tslib_1.__generator(this, function (_a) {
                  switch (_a.label) {
                      case 0:
                          userId = twitch_common_1.extractUserId(user);
                          return [4 /*yield*/, this._client.callApi({
                                  url: "users/" + userId + "/emotes",
                                  scope: 'user_subscriptions'
                              })];
                      case 1:
                          data = _a.sent();
                          return [2 /*return*/, new EmoteSetList_1.EmoteSetList(data.emoticon_sets)];
                  }
              });
          });
      };
      /**
       * Retrieves the subscription data for a given user to a given channel.
       *
       * @param user The user to retrieve the subscription data of.
       * @param toChannel The channel you want to retrieve the subscription data to.
       */
      UserApi.prototype.getSubscriptionData = function (user, toChannel) {
          return tslib_1.__awaiter(this, void 0, void 0, function () {
              var userId, channelId, _a, e_1;
              return tslib_1.__generator(this, function (_b) {
                  switch (_b.label) {
                      case 0:
                          userId = twitch_common_1.extractUserId(user);
                          channelId = twitch_common_1.extractUserId(toChannel);
                          _b.label = 1;
                      case 1:
                          _b.trys.push([1, 3, , 4]);
                          _a = UserSubscription_1.UserSubscription.bind;
                          return [4 /*yield*/, this._client.callApi({
                                  url: "users/" + userId + "/subscriptions/" + channelId,
                                  scope: 'user_subscriptions'
                              })];
                      case 2: return [2 /*return*/, new (_a.apply(UserSubscription_1.UserSubscription, [void 0, _b.sent(), this._client]))()];
                      case 3:
                          e_1 = _b.sent();
                          if (e_1 instanceof twitch_api_call_1.HttpStatusCodeError) {
                              if (e_1.statusCode === 404) {
                                  return [2 /*return*/, null];
                              }
                              else if (e_1.statusCode === 422) {
                                  throw new NoSubscriptionProgramError_1.NoSubscriptionProgramError(channelId);
                              }
                          }
                          throw e_1;
                      case 4: return [2 /*return*/];
                  }
              });
          });
      };
      /**
       * Get a list of channels a given user follows.
       *
       * @param user The user you want to retrieve the follows of.
       * @param page The result page you want to retrieve.
       * @param limit The number of results you want to retrieve.
       * @param orderBy The field to order by.
       * @param orderDirection The direction to order in - ascending or descending.
       */
      UserApi.prototype.getFollowedChannels = function (user, page, limit, orderBy, orderDirection) {
          if (limit === void 0) { limit = 25; }
          return tslib_1.__awaiter(this, void 0, void 0, function () {
              var userId, query, data;
              var _this = this;
              return tslib_1.__generator(this, function (_a) {
                  switch (_a.label) {
                      case 0:
                          userId = twitch_common_1.extractUserId(user);
                          query = {};
                          if (page) {
                              query.offset = ((page - 1) * limit).toString();
                          }
                          query.limit = limit.toString();
                          if (orderBy) {
                              query.sortby = orderBy;
                          }
                          if (orderDirection) {
                              query.direction = orderDirection;
                          }
                          return [4 /*yield*/, this._client.callApi({
                                  url: "users/" + userId + "/follows/channels",
                                  query: query
                              })];
                      case 1:
                          data = _a.sent();
                          return [2 /*return*/, data.follows.map(function (follow) { return new UserFollow_1.UserFollow(follow, _this._client); })];
                  }
              });
          });
      };
      /**
       * Get follow data for a given user to a given channel.
       *
       * @param user The user you want to retrieve follow data of.
       * @param channel The channel you want to retrieve follow data to.
       */
      UserApi.prototype.getFollowedChannel = function (user, channel) {
          return tslib_1.__awaiter(this, void 0, void 0, function () {
              var userId, channelId, data, e_2;
              return tslib_1.__generator(this, function (_a) {
                  switch (_a.label) {
                      case 0:
                          userId = twitch_common_1.extractUserId(user);
                          channelId = twitch_common_1.extractUserId(channel);
                          _a.label = 1;
                      case 1:
                          _a.trys.push([1, 3, , 4]);
                          return [4 /*yield*/, this._client.callApi({
                                  url: "users/" + userId + "/follows/channels/" + channelId
                              })];
                      case 2:
                          data = _a.sent();
                          return [2 /*return*/, new UserFollow_1.UserFollow(data, this._client)];
                      case 3:
                          e_2 = _a.sent();
                          if (e_2 instanceof twitch_api_call_1.HttpStatusCodeError) {
                              if (e_2.statusCode === 404) {
                                  return [2 /*return*/, null];
                              }
                          }
                          throw e_2;
                      case 4: return [2 /*return*/];
                  }
              });
          });
      };
      /**
       * Follows a given channel with a given user.
       *
       * @param user The user you want to follow with.
       * @param channel The channel to follow.
       * @param notifications Whether the user will receive notifications.
       */
      UserApi.prototype.followChannel = function (user, channel, notifications) {
          return tslib_1.__awaiter(this, void 0, void 0, function () {
              var userId, channelId, data;
              return tslib_1.__generator(this, function (_a) {
                  switch (_a.label) {
                      case 0:
                          userId = twitch_common_1.extractUserId(user);
                          channelId = twitch_common_1.extractUserId(channel);
                          return [4 /*yield*/, this._client.callApi({
                                  url: "users/" + userId + "/follows/channels/" + channelId,
                                  method: 'PUT',
                                  scope: 'user_follows_edit',
                                  body: { notifications: Boolean(notifications).toString() }
                              })];
                      case 1:
                          data = _a.sent();
                          return [2 /*return*/, new UserFollow_1.UserFollow(data, this._client)];
                  }
              });
          });
      };
      /**
       * Unfollows a given channel with a given user.
       *
       * @param user The user you want to unfollow with.
       * @param channel The channel to unfollow.
       */
      UserApi.prototype.unfollowChannel = function (user, channel) {
          return tslib_1.__awaiter(this, void 0, void 0, function () {
              var userId, channelId;
              return tslib_1.__generator(this, function (_a) {
                  switch (_a.label) {
                      case 0:
                          userId = twitch_common_1.extractUserId(user);
                          channelId = twitch_common_1.extractUserId(channel);
                          return [4 /*yield*/, this._client.callApi({
                                  url: "users/" + userId + "/follows/channels/" + channelId,
                                  scope: 'user_follows_edit',
                                  method: 'DELETE'
                              })];
                      case 1:
                          _a.sent();
                          return [2 /*return*/];
                  }
              });
          });
      };
      /**
       * Retrieves a list of users a given user has blocked.
       *
       * @param user The user you want to retrieve the block list of.
       * @param page The result page you want to retrieve.
       * @param limit The number of results you want to retrieve.
       */
      UserApi.prototype.getBlockedUsers = function (user, page, limit) {
          if (limit === void 0) { limit = 25; }
          return tslib_1.__awaiter(this, void 0, void 0, function () {
              var userId, query, data;
              var _this = this;
              return tslib_1.__generator(this, function (_a) {
                  switch (_a.label) {
                      case 0:
                          userId = twitch_common_1.extractUserId(user);
                          query = { limit: limit.toString() };
                          if (page) {
                              query.offset = ((page - 1) * limit).toString();
                          }
                          return [4 /*yield*/, this._client.callApi({
                                  url: "users/" + userId + "/blocks",
                                  query: query,
                                  scope: 'user_blocks_read'
                              })];
                      case 1:
                          data = _a.sent();
                          return [2 /*return*/, data.blocks.map(function (block) { return new UserBlock_1.UserBlock(block, _this._client); })];
                  }
              });
          });
      };
      /**
       * Blocks a given user with another given user.
       *
       * @param user The user you want to block with.
       * @param userToBlock The user to block.
       */
      UserApi.prototype.blockUser = function (user, userToBlock) {
          return tslib_1.__awaiter(this, void 0, void 0, function () {
              var userId, userIdToBlock, data;
              return tslib_1.__generator(this, function (_a) {
                  switch (_a.label) {
                      case 0:
                          userId = twitch_common_1.extractUserId(user);
                          userIdToBlock = twitch_common_1.extractUserId(userToBlock);
                          return [4 /*yield*/, this._client.callApi({
                                  url: "users/" + userId + "/blocks/" + userIdToBlock,
                                  method: 'PUT',
                                  scope: 'user_blocks_edit'
                              })];
                      case 1:
                          data = _a.sent();
                          return [2 /*return*/, new UserBlock_1.UserBlock(data, this._client)];
                  }
              });
          });
      };
      /**
       * Unblocks a given user with another given user.
       *
       * @param user The user you want to unblock with.
       * @param userToUnblock The user to unblock.
       */
      UserApi.prototype.unblockUser = function (user, userToUnblock) {
          return tslib_1.__awaiter(this, void 0, void 0, function () {
              var userId, userIdToUnblock;
              return tslib_1.__generator(this, function (_a) {
                  switch (_a.label) {
                      case 0:
                          userId = twitch_common_1.extractUserId(user);
                          userIdToUnblock = twitch_common_1.extractUserId(userToUnblock);
                          return [4 /*yield*/, this._client.callApi({
                                  url: "users/" + userId + "/blocks/" + userIdToUnblock,
                                  method: 'DELETE',
                                  scope: 'user_blocks_edit'
                              })];
                      case 1:
                          _a.sent();
                          return [2 /*return*/];
                  }
              });
          });
      };
      UserApi.prototype._cleanUserCache = function () {
          var _this = this;
          var now = Date.now();
          this._userByNameCache.forEach(function (val, key) {
              if (val.expires < now) {
                  _this._userByNameCache.delete(key);
              }
          });
      };
      tslib_1.__decorate([
          cache_decorators_1.Cached(3600)
      ], UserApi.prototype, "getMe", null);
      tslib_1.__decorate([
          cache_decorators_1.Cached(3600)
      ], UserApi.prototype, "getUser", null);
      tslib_1.__decorate([
          cache_decorators_1.Cached(3600)
      ], UserApi.prototype, "getChatInfo", null);
      tslib_1.__decorate([
          cache_decorators_1.Cached(3600)
      ], UserApi.prototype, "getUserEmotes", null);
      tslib_1.__decorate([
          cache_decorators_1.Cached(3600)
      ], UserApi.prototype, "getSubscriptionData", null);
      tslib_1.__decorate([
          cache_decorators_1.Cached(300)
      ], UserApi.prototype, "getFollowedChannels", null);
      tslib_1.__decorate([
          cache_decorators_1.Cached(300)
      ], UserApi.prototype, "getFollowedChannel", null);
      tslib_1.__decorate([
          cache_decorators_1.ClearsCache('getFollowedChannels', 1),
          cache_decorators_1.ClearsCache('getFollowedChannel', 2)
      ], UserApi.prototype, "followChannel", null);
      tslib_1.__decorate([
          cache_decorators_1.ClearsCache('getFollowedChannels', 1),
          cache_decorators_1.ClearsCache('getFollowedChannel', 2)
      ], UserApi.prototype, "unfollowChannel", null);
      tslib_1.__decorate([
          cache_decorators_1.Cached(3600)
      ], UserApi.prototype, "getBlockedUsers", null);
      tslib_1.__decorate([
          cache_decorators_1.ClearsCache('getBlockedUsers', 1)
      ], UserApi.prototype, "blockUser", null);
      tslib_1.__decorate([
          cache_decorators_1.ClearsCache('getBlockedUsers', 1)
      ], UserApi.prototype, "unblockUser", null);
      UserApi = tslib_1.__decorate([
          cache_decorators_1.Cacheable,
          twitch_common_1.rtfm('twitch', 'UserApi')
      ], UserApi);
      return UserApi;
  }(BaseApi_1.BaseApi));
  exports.UserApi = UserApi;
  