text: 'use strict';
  
  const Base = require('./Base');
  const { InteractionTypes, MessageComponentTypes, ApplicationCommandTypes } = require('../util/Constants');
  const Permissions = require('../util/Permissions');
  const SnowflakeUtil = require('../util/SnowflakeUtil');
  
  /**
   * Represents an interaction.
   * @extends {Base}
   */
  class Interaction extends Base {
    constructor(client, data) {
      super(client);
  
      /**
       * The interaction's type
       * @type {InteractionType}
       */
      this.type = InteractionTypes[data.type];
  
      /**
       * The interaction's id
       * @type {Snowflake}
       */
      this.id = data.id;
  
      /**
       * The interaction's token
       * @type {string}
       * @name Interaction#token
       * @readonly
       */
      Object.defineProperty(this, 'token', { value: data.token });
  
      /**
       * The application's id
       * @type {Snowflake}
       */
      this.applicationId = data.application_id;
  
      /**
       * The id of the channel this interaction was sent in
       * @type {?Snowflake}
       */
      this.channelId = data.channel_id ?? null;
  
      /**
       * The id of the guild this interaction was sent in
       * @type {?Snowflake}
       */
      this.guildId = data.guild_id ?? null;
  
      /**
       * The user which sent this interaction
       * @type {User}
       */
      this.user = this.client.users._add(data.user ?? data.member.user);
  
      /**
       * If this interaction was sent in a guild, the member which sent it
       * @type {?(GuildMember|APIGuildMember)}
       */
      this.member = data.member ? this.guild?.members._add(data.member) ?? data.member : null;
  
      /**
       * The version
       * @type {number}
       */
      this.version = data.version;
  
      /**
       * The permissions of the member, if one exists, in the channel this interaction was executed in
       * @type {?Readonly<Permissions>}
       */
      this.memberPermissions = data.member?.permissions ? new Permissions(data.member.permissions).freeze() : null;
  
      /**
       * The locale of the user who invoked this interaction
       * @type {string}
       * @see {@link https://discord.com/developers/docs/dispatch/field-values#predefined-field-values-accepted-locales}
       */
      this.locale = data.locale;
  
      /**
       * The preferred locale from the guild this interaction was sent in
       * @type {?string}
       */
      this.guildLocale = data.guild_locale ?? null;
    }
  
    /**
     * The timestamp the interaction was created at
     * @type {number}
     * @readonly
     */
    get createdTimestamp() {
      return SnowflakeUtil.timestampFrom(this.id);
    }
  
    /**
     * The time the interaction was created at
     * @type {Date}
     * @readonly
     */
    get createdAt() {
      return new Date(this.createdTimestamp);
    }
  
    /**
     * The channel this interaction was sent in
     * @type {?TextBasedChannels}
     * @readonly
     */
    get channel() {
      return this.client.channels.cache.get(this.channelId) ?? null;
    }
  
    /**
     * The guild this interaction was sent in
     * @type {?Guild}
     * @readonly
     */
    get guild() {
      return this.client.guilds.cache.get(this.guildId) ?? null;
    }
  
    /**
     * Indicates whether this interaction is received from a guild.
     * @returns {boolean}
     */
    inGuild() {
      return Boolean(this.guildId && this.member);
    }
  
    /**
     * Indicates whether or not this interaction is both cached and received from a guild.
     * @returns {boolean}
     */
    inCachedGuild() {
      return Boolean(this.guild && this.member);
    }
  
    /**
     * Indicates whether or not this interaction is received from an uncached guild.
     * @returns {boolean}
     */
    inRawGuild() {
      return Boolean(this.guildId && !this.guild && this.member);
    }
  
    /**
     * Indicates whether this interaction is a {@link BaseCommandInteraction}.
     * @returns {boolean}
     */
    isApplicationCommand() {
      return InteractionTypes[this.type] === InteractionTypes.APPLICATION_COMMAND;
    }
  
    /**
     * Indicates whether this interaction is a {@link CommandInteraction}.
     * @returns {boolean}
     */
    isCommand() {
      return InteractionTypes[this.type] === InteractionTypes.APPLICATION_COMMAND && typeof this.targetId === 'undefined';
    }
  
    /**
     * Indicates whether this interaction is a {@link ContextMenuInteraction}
     * @returns {boolean}
     */
    isContextMenu() {
      return InteractionTypes[this.type] === InteractionTypes.APPLICATION_COMMAND && typeof this.targetId !== 'undefined';
    }
  
    /**
     * Indicates whether this interaction is a {@link UserContextMenuInteraction}
     * @returns {boolean}
     */
    isUserContextMenu() {
      return this.isContextMenu() && ApplicationCommandTypes[this.targetType] === ApplicationCommandTypes.USER;
    }
  
    /**
     * Indicates whether this interaction is a {@link MessageContextMenuInteraction}
     * @returns {boolean}
     */
    isMessageContextMenu() {
      return this.isContextMenu() && ApplicationCommandTypes[this.targetType] === ApplicationCommandTypes.MESSAGE;
    }
  
    /**
     * Indicates whether this interaction is an {@link AutocompleteInteraction}
     * @returns {boolean}
     */
    isAutocomplete() {
      return InteractionTypes[this.type] === InteractionTypes.APPLICATION_COMMAND_AUTOCOMPLETE;
    }
  
    /**
     * Indicates whether this interaction is a {@link MessageComponentInteraction}.
     * @returns {boolean}
     */
    isMessageComponent() {
      return InteractionTypes[this.type] === InteractionTypes.MESSAGE_COMPONENT;
    }
  
    /**
     * Indicates whether this interaction is a {@link ButtonInteraction}.
     * @returns {boolean}
     */
    isButton() {
      return (
        InteractionTypes[this.type] === InteractionTypes.MESSAGE_COMPONENT &&
        MessageComponentTypes[this.componentType] === MessageComponentTypes.BUTTON
      );
    }
  
    /**
     * Indicates whether this interaction is a {@link SelectMenuInteraction}.
     * @returns {boolean}
     */
    isSelectMenu() {
      return (
        InteractionTypes[this.type] === InteractionTypes.MESSAGE_COMPONENT &&
        MessageComponentTypes[this.componentType] === MessageComponentTypes.SELECT_MENU
      );
    }
  }
  
  module.exports = Interaction;
  