text: 'use strict';
  
  const GuildEmoji = require('./GuildEmoji');
  const Util = require('../util/Util');
  const ReactionEmoji = require('./ReactionEmoji');
  const ReactionUserStore = require('../stores/ReactionUserStore');
  
  /**
   * Represents a reaction to a message.
   */
  class MessageReaction {
    /**
     * @param {Client} client The instantiating client
     * @param {Object} data The data for the message reaction
     * @param {Message} message The message the reaction refers to
     */
    constructor(client, data, message) {
      /**
       * The client that instantiated this message reaction
       * @name MessageReaction#client
       * @type {Client}
       * @readonly
       */
      Object.defineProperty(this, 'client', { value: client });
      /**
       * The message that this reaction refers to
       * @type {Message}
       */
      this.message = message;
  
      /**
       * Whether the client has given this reaction
       * @type {boolean}
       */
      this.me = data.me;
  
      /**
       * The users that have given this reaction, mapped by their ID
       * @type {ReactionUserStore<Snowflake, User>}
       */
      this.users = new ReactionUserStore(client, undefined, this);
  
      this._emoji = new ReactionEmoji(this, data.emoji);
  
      this._patch(data);
    }
  
    _patch(data) {
      /**
       * The number of people that have given the same reaction
       * @type {?number}
       */
      // eslint-disable-next-line eqeqeq
      if (this.count == undefined) this.count = data.count;
    }
  
    /**
     * Removes all users from this reaction.
     * @returns {Promise<MessageReaction>}
     */
    async remove() {
      await this.client.api.channels(this.message.channel.id).messages(this.message.id).reactions(this._emoji.identifier)
        .delete();
      return this;
    }
  
    /**
     * The emoji of this reaction, either an GuildEmoji object for known custom emojis, or a ReactionEmoji
     * object which has fewer properties. Whatever the prototype of the emoji, it will still have
     * `name`, `id`, `identifier` and `toString()`
     * @type {GuildEmoji|ReactionEmoji}
     * @readonly
     */
    get emoji() {
      if (this._emoji instanceof GuildEmoji) return this._emoji;
      // Check to see if the emoji has become known to the client
      if (this._emoji.id) {
        const emojis = this.message.client.emojis;
        if (emojis.has(this._emoji.id)) {
          const emoji = emojis.get(this._emoji.id);
          this._emoji = emoji;
          return emoji;
        }
      }
      return this._emoji;
    }
  
    /**
     * Whether or not this reaction is a partial
     * @type {boolean}
     * @readonly
     */
    get partial() {
      return this.count === null;
    }
  
    /**
     * Fetch this reaction.
     * @returns {Promise<MessageReaction>}
     */
    fetch() {
      return this.message.reactions._fetchReaction(this.emoji, true);
    }
  
    toJSON() {
      return Util.flatten(this, { emoji: 'emojiID', message: 'messageID' });
    }
  
    _add(user) {
      if (this.partial) return;
      this.users.set(user.id, user);
      if (!this.me || user.id !== this.message.client.user.id || this.count === 0) this.count++;
      if (!this.me) this.me = user.id === this.message.client.user.id;
    }
  
    _remove(user) {
      if (this.partial) return;
      this.users.delete(user.id);
      if (!this.me || user.id !== this.message.client.user.id) this.count--;
      if (user.id === this.message.client.user.id) this.me = false;
      if (this.count <= 0 && this.users.size === 0) {
        this.message.reactions.remove(this.emoji.id || this.emoji.name);
      }
    }
  }
  
  module.exports = MessageReaction;
  