text: const ArgumentType = require('../base');
  const { disambiguation } = require('../../util');
  const { escapeMarkdown } = require('discord.js');
  const RegExpRole = require('../../regexp/role').RegExpSingle;
  const RegExpSnowflake = require('../../regexp/snowflake').RegExpSingle;
  const memoize = require('fast-memoize');
  
  module.exports = memoize((typePrefix, guildID) => {
  	return class RoleArgumentType extends ArgumentType {
  		constructor(client) {
  			super(client, `${typePrefix}-role`);
  		}
  
  		validate(val, msg, arg) {
  			const guild = this.client.guilds.resolve(guildID);
  			// Snowflake format
  			if(RegExpSnowflake.simple().test(val)) {
  				return guild.roles.cache.has(val);
  			}
  			// Ping format
  			{
  				const matches = RegExpRole.ping().exec(val);
  				if(matches) {
  					const [, roleid] = matches;
  					return guild.roles.cache.has(roleid);
  				}
  			}
  
  			const search = val.toLowerCase();
  			let roles = guild.roles.cache.filter(nameFilterInexact(search));
  			if(roles.size === 0) return false;
  			if(roles.size === 1) {
  				if(arg.oneOf && !arg.oneOf.includes(roles.first().id)) return false;
  				return true;
  			}
  			const exactRoles = roles.filter(nameFilterExact(search));
  			if(exactRoles.size === 1) {
  				if(arg.oneOf && !arg.oneOf.includes(exactRoles.first().id)) return false;
  				return true;
  			}
  			if(exactRoles.size > 0) roles = exactRoles;
  			if(roles.size <= 15) {
  				return `${disambiguation(roles.map(role => `${escapeMarkdown(role.name)}`),
  				msg.localeStrings,
  				msg.localeStrings.types.role.disambiguation,
  				null
  				)}\n`;
  			}
  			return msg.localeStrings.types.role.multipleFound;
  		}
  
  		parse(val) {
  			const guild = this.client.guilds.resolve(guildID);
  			// Snowflake format
  			if(RegExpSnowflake.simple().test(val)) {
  				return guild.roles.cache.get(val) || null;
  			}
  			// Ping format
  			{
  				const matches = RegExpRole.ping().exec(val);
  				if(matches) {
  					const [, roleid] = matches;
  					return guild.roles.cache.get(roleid) || null;
  				}
  			}
  
  			const search = val.toLowerCase();
  			const roles = guild.roles.cache.filter(nameFilterInexact(search));
  			if(roles.size === 0) return null;
  			if(roles.size === 1) return roles.first();
  			const exactRoles = roles.filter(nameFilterExact(search));
  			if(exactRoles.size === 1) return exactRoles.first();
  			return null;
  		}
  	};
  
  	function nameFilterExact(search) {
  		return thing => thing.name.toLowerCase() === search;
  	}
  
  	function nameFilterInexact(search) {
  		return thing => thing.name.toLowerCase().includes(search);
  	}
  });
  