import _ from 'lodash';
import { BotCommand, BotPlugin } from 'psyduck-contracts';
import * as Discord from 'discord.js';
import commandLineArgs, { CommandLineOptions } from 'command-line-args';

const optionsDefinition = [
    { name: 'help', alias: 'h', type: Boolean }
];

const userFormatRegex = new RegExp(/^(<@.+>)|(<!.+>)$/gm);

export default class PsyduckExample implements BotPlugin {
    gateCommand: string;
    gateChannelId: string;
    roleId: string;

    constructor(options: { gateCommand: string, gateChannelId: string, roleId: string }) {
        this.gateCommand = options.gateCommand;
        this.gateChannelId = options.gateChannelId;
        this.roleId = options.roleId;
    }

    /**
     * This event is emitted from Psyduck when a message is recieved in a discord channel. From there you may do as you with with it in your plugin.
     */
    onMessage(message: Discord.Message) {
        // If the message came from a bot, ignore.
        if (message.author.bot) {
            return;
        }
        // If the message is too small to be a command, ignore.
        if (message.content.length <= 1) {
            return;
        }
        // If the message is a string of repeated characters, ignore. For example !!!!!!!
        const dupe = RegExp(/^(.)\1*$/gm);
        if (dupe.test(message.content)) {
            return;
        }
        if (message.channel.id !== this.gateChannelId) {
            return;
        }
        // Extract the command code, if it is in the list of commands we want to handle, continue.
        if (message.content.startsWith('!')) {
            const commandCode = message.content.slice(1).trim();
            if (this.gateCommand === commandCode) {
                this.updateUser(message);
            }
        }
    }
    async updateUser(message: Discord.Message) {
        try {
            const serverRole = message.guild.roles.find('id', this.roleId);
            if (serverRole) {
                const guildUser = await message.guild.fetchMember(message.author.id);
                if (guildUser && !guildUser.roles.get(serverRole.id)) {
                    guildUser.addRole(serverRole);
                }
            }
        } catch (error) {
        }
    }
    /**
     * If you command will use the command-line-args package, you can use this RegEx to extract the parts in to an array for use with hydrateOptions.
     */
    parseParameters(messageContent: string): string[] {
        return messageContent.match(/ (?=\S)[^'\s]*(?:'[^\\']*(?:\\[\s\S][^\\']*)*'[^'\s]*)*/g) || [];
    }
    /**
     * Hydrate an object with the shape if your options definition. 
     */
    hydrateOptions(parameters: string[]): CommandLineOptions {
        return commandLineArgs(optionsDefinition, { argv: parameters.map(p => p.trim()), partial: true });
    }
    /**
     * If you need to extract a userId from a mention for later use, you can pass the raw mention to this method. <@1234567890> => 1234567890 | undefined
     */
    extractUserId(userId: string): string | undefined {
        const matches = userId.match(/(?<=@|!)(.*)(?=>)/gm);
        if (matches && matches.length === 1) {
            return matches[0];
        }
        return undefined;
    }
}