const { literal, argument, greedyString, DynamicCommandExceptionType } = require('brigadier-commands')
const TextMessage = require('../util/command/text_message')

const UNKNOWN_COMMAND_ERROR = new DynamicCommandExceptionType(command => new TextMessage(['Unknown command: ', command]))

module.exports = {
  register (dispatcher) {
    const node = dispatcher.register(
      literal('help')
        .executes(this.listCommands)
        .then(
          argument('command', greedyString())
            .executes(this.showCommandInfo)
        )
    )

    node.description = 'Lists commands or shows info about a command'
    node.permissionLevel = 0
  },

  listCommands (context) {
    const source = context.source
    const bot = source.bot

    const nodes = bot.commands.dispatcher.root.getChildren()

    const publicList = []
    const trustedList = []
    const adminList = []
    const unknownList = []
    nodes.forEach(node => {
      if (node.redirect) return // ignore aliases

      const msg = {
        color: 'dark_aqua',
        text: bot.prefix + node.name + ' ',
        clickEvent: { action: 'suggest_command', value: bot.prefix + 'help ' + node.name },
        hoverEvent: { action: 'show_text', value: 'Click to see info about the command' }
      }
      if (node.permissionLevel === 0) {
        msg.color = 'green'
        publicList.push(msg)
      } else if (node.permissionLevel === 1) {
        msg.color = 'red'
        trustedList.push(msg)
      } else if (node.permissionLevel === 2) {
        msg.color = 'dark_red'
        adminList.push(msg)
      } else {
        unknownList.push(msg)
      }
    })

    const msg = [{ text: 'Commands - ', color: 'gray' }, ...publicList, ...trustedList, ...adminList, ...unknownList]
    source.sendFeedback(msg, false)
  },

  showCommandInfo (context) {
    const source = context.source
    const bot = source.bot

    const nodes = bot.commands.dispatcher.root.getChildren()

    const commandName = context.getArgument('command')
    let node = nodes.find(node => node.name === commandName)
    if (!node) throw UNKNOWN_COMMAND_ERROR.create(commandName)
    if (node.redirect) node = node.redirect

    const aliases = [node, ...nodes.filter(_node => _node.redirect === node)].map(node => node.name)
    const usages = [...bot.commands.dispatcher.getSmartUsage(node, source, false).values()]

    let msg
    if (usages.length !== 1) {
      msg = [
        { text: bot.prefix + node.name, ...bot.styles.primary },
        { text: ' (' + aliases.join(', ') + ')', color: 'white' },
        { text: ` - ${node.description}\n`, color: 'gray' }
      ]
      usages.forEach((usage, i) => {
        msg.push(bot.prefix + node.name)
        msg.push({
          text: ` ${usage}\n`,
          ...bot.styles.secondary,
          clickEvent: { action: 'suggest_command', value: node.name + ' ' + usage }
        })
      })
      msg[msg.length - 1].text = msg[msg.length - 1].text.slice(0, -1)
    } else {
      msg = [
        { text: bot.prefix + node.name, ...bot.styles.primary },
        { text: ' (' + aliases.join(', ') + ')', color: 'white' },
        {
          text: ` ${usages[0]}`,
          ...bot.styles.secondary,
          clickEvent: { action: 'suggest_command', value: node.name + ' ' + usages[0] }
        },
        { text: ` - ${node.description}`, color: 'gray' }
      ]
    }
    source.sendFeedback(msg, false)
  }
}