const GuildChannel = require('./GuildChannel');
const TextBasedChannel = require('./interfaces/TextBasedChannel');
const Collection = require('../util/Collection');

/**
 * Represents a guild text channel on Discord.
 * @extends {GuildChannel}
 * @implements {TextBasedChannel}
 */
class TextChannel extends GuildChannel {
  constructor(guild, data) {
    super(guild, data);
    this.type = 'text';
    this.messages = new Collection();
    this._typing = new Map();
  }

  setup(data) {
    super.setup(data);

    /**
     * The topic of the text channel
     * @type {?string}
     */
    this.topic = data.topic;

    /**
     * If the Discord considers this channel NSFW
     * @type {boolean}
     * @readonly
     */
    this.nsfw = Boolean(data.nsfw);

    /**
     * The ID of the last message sent in this channel, if one was sent
     * @type {?Snowflake}
     */
    this.lastMessageID = data.last_message_id;
  }

  /**
   * A collection of members that can see this channel, mapped by their ID
   * @type {Collection<Snowflake, GuildMember>}
   * @readonly
   */
  get members() {
    const members = new Collection();
    for (const member of this.guild.members.values()) {
      if (this.permissionsFor(member).has('READ_MESSAGES')) {
        members.set(member.id, member);
      }
    }
    return members;
  }

  /**
   * Fetch all webhooks for the channel.
   * @returns {Promise<Collection<Snowflake, Webhook>>}
   * @example
   * // Fetch webhooks
   * channel.fetchWebhooks()
   *   .then(hooks => console.log(`This channel has ${hooks.size} hooks`))
   *   .catch(console.error);
   */
  fetchWebhooks() {
    return this.client.rest.methods.getChannelWebhooks(this);
  }

  /**
   * Sets whether this channel is flagged as NSFW.
   * @param {boolean} nsfw Whether the channel should be considered NSFW
   * @param {string} [reason] Reason for changing the channel's NSFW flag
   * @returns {Promise<TextChannel>}
   */
  setNSFW(nsfw, reason) {
    return this.edit({ nsfw }, reason);
  }

  /**
   * Create a webhook for the channel.
   * @param {string} name The name of the webhook
   * @param {BufferResolvable|Base64Resolvable} [avatar] The avatar for the webhook
   * @param {string} [reason] Reason for creating this webhook
   * @returns {Promise<Webhook>} webhook The created webhook
   * @example
   * channel.createWebhook('Snek', 'https://i.imgur.com/mI8XcpG.jpg')
   *   .then(webhook => console.log(`Created webhook ${webhook}`))
   *   .catch(console.error)
   */
  createWebhook(name, avatar, reason) {
    if (typeof avatar === 'string' && avatar.startsWith('data:')) {
      return this.client.rest.methods.createWebhook(this, name, avatar, reason);
    } else {
      return this.client.resolver.resolveImage(avatar).then(data =>
        this.client.rest.methods.createWebhook(this, name, data, reason)
      );
    }
  }

  // These are here only for documentation purposes - they are implemented by TextBasedChannel
  /* eslint-disable no-empty-function */
  send() { }
  sendMessage() { }
  sendEmbed() { }
  sendFile() { }
  sendFiles() { }
  sendCode() { }
  fetchMessage() { }
  fetchMessages() { }
  fetchPinnedMessages() { }
  search() { }
  startTyping() { }
  stopTyping() { }
  get typing() { }
  get typingCount() { }
  createCollector() { }
  createMessageCollector() { }
  awaitMessages() { }
  bulkDelete() { }
  acknowledge() { }
  _cacheMessage() { }
}

TextBasedChannel.applyToClass(TextChannel, true);

module.exports = TextChannel;
