import { InteractionReplyOptions, Message, InteractionResponse, ApplicationCommandOptionType, ApplicationCommandOptionChoiceData, CommandInteraction, ApplicationCommandType, ChatInputCommandInteraction, MessageContextMenuCommandInteraction, UserContextMenuCommandInteraction, ModalSubmitInteraction, StringSelectMenuInteraction, Client, Collection, Guild, GuildMember, ButtonInteraction, ColorResolvable, EmbedBuilder, Embed, PermissionResolvable } from 'discord.js';

declare global {
    interface Array<T> {
        /**
         * @returns A random element from the array.
         */
        random(): T;

        /**
         * Gets a number of random different elements from the array.
         * @param number The number of elements to draw. Defaults to 1.
         * @returns An array containing the drawn elements.
         */
        draw(number?: number): T[];
    }
}

declare module 'discord.js' {
    interface BaseInteraction {
        /**
        * Replies to an interaction or follows up if already replied or deferred, avoiding Interaction Already Acknowledged error.
        * @param reply The reply to be sent.
        * @returns InteractionResponse, if followed up, or Message, if replied.
        */
        replyOrFollowUp(reply: InteractionReplyOptions | string): Promise<Message<boolean>> | Promise<InteractionResponse<boolean>>;
    }

    interface StringSelectMenuInteraction {
        /**
         * Clears the selection of the select menu.
         * 
         * @note This is not recommended since it resets the select menu for all users, but it is currently the only way to clear the selection.
         */
        clearSelection(): Promise<void>;
    }
}

declare namespace index_d {
  export {  };
}

type CommandOption = {
    name: string;
    description: string;
    type: ApplicationCommandOptionType;
    required?: boolean;
    choices?: ApplicationCommandOptionChoiceData[];
    options?: CommandOption[];
};
type NumberCommandOption = CommandOption & {
    type: ApplicationCommandOptionType.Integer | ApplicationCommandOptionType.Number;
    minValue?: number;
    maxValue?: number;
};
type StringCommandOption = CommandOption & {
    type: ApplicationCommandOptionType.String;
    minLength?: number;
    maxLength?: number;
};
interface CustomCommandInteraction<K extends CommandInteraction> extends CustomInteraction<K> {
    readonly type: ApplicationCommandType;
    readonly defaultPermission: boolean;
    execute(interaction: K, client: ExtendedClient): Promise<void>;
}
/**
 * Defines a custom chat input command. Chat input commands should implement this interface
 */
interface CustomChatInputCommand extends CustomCommandInteraction<ChatInputCommandInteraction> {
    readonly type: ApplicationCommandType.ChatInput;
    readonly description: string;
    readonly options?: CommandOption[];
}
/**
 * Defines a custom message command. Message commands should implement this interface
 */
interface CustomMessageCommand extends CustomCommandInteraction<MessageContextMenuCommandInteraction> {
    readonly type: ApplicationCommandType.Message;
}
/**
 * Defines a custom user command. User commands should implement this interface
 */
interface CustomUserCommand extends CustomCommandInteraction<UserContextMenuCommandInteraction> {
    readonly type: ApplicationCommandType.User;
}

interface CustomModalInteraction extends CustomInteraction<ModalSubmitInteraction> {
    execute(interaction: ModalSubmitInteraction, client: ExtendedClient): Promise<void>;
}

interface CustomSelectMenuInteraction extends CustomInteraction<StringSelectMenuInteraction> {
    execute(interaction: StringSelectMenuInteraction, client: ExtendedClient): Promise<void>;
}

declare class ExtendedClient extends Client {
    protected readonly _commands: Collection<string, CustomCommandInteraction<CommandInteraction>>;
    protected readonly _buttons: Collection<string, CustomButtonInteraction>;
    protected readonly _selectMenus: Collection<string, CustomSelectMenuInteraction>;
    protected readonly _modals: Collection<string, CustomModalInteraction>;
    constructor(token: string);
    /**
     * Caches the commands to respond to their interactions once they are triggered
     * @param commands The commands to register
     *
     * @note This method is intended for JavaScript users. TypeScript users should use the decorator `@Register...Command` instead
     * @see RegisterChatInputCommandInteraction
     */
    registerCommands(...commands: CustomCommandInteraction<CommandInteraction>[]): Promise<void>;
    /**
     * Caches the buttons to respond to their interactions once they are triggered
     * @param buttons The buttons to register
     *
     * @note This method is intended for JavaScript users. TypeScript users should use the decorator `@RegisterButton` instead
     * @see RegisterButtonInteraction
     */
    registerButtons(...buttons: CustomButtonInteraction[]): Promise<void>;
    /**
     * Caches the select menus to respond to their interactions once they are triggered
     * @param selectMenus The select menus to register
     *
     * @note This method is intended for JavaScript users. TypeScript users should use the decorator `@RegisterSelectMenu` instead
     * @see RegisterSelectMenuInteraction
     */
    registerSelectMenus(...selectMenus: CustomSelectMenuInteraction[]): Promise<void>;
    /**
     * Caches the modals to respond to their interactions once they are triggered
     * @param modals The modals to register
     *
     * @note This method is intended for JavaScript users. TypeScript users should use the decorator `@RegisterModal` instead
     * @see RegisterModalInteraction
     */
    registerModals(...modals: CustomModalInteraction[]): Promise<void>;
    /**
     * Caches the interactions decorated with the @Register... decorators
     *
     * @note This method is intended for TypeScript users. JavaScript users should use the explicit methods to register the interactions
     */
    protected registerInteractions(): Promise<void>;
    /**
     * Loads the cached commands to a guild
     * @param guild The guild to create the commands in
     */
    protected createCommands(guild: Guild): Promise<void>;
    /**
     * Deletes a command from a guild
     * @param commandName The registered name of the command to delete
     * @param guild The guild to delete the command from
     */
    protected unregisterCommand(commandName: string, guild: Guild): Promise<void>;
    /**
     * Creates the registered commands in the specified guilds
     * @param guildIDs The IDs of the guilds to create the commands in. If no IDs are provided, the commands will be created in all guilds the bot is in
     */
    loadCommands(...guildIDs: string[]): Promise<void>;
    /**
     * Deletes a list of commands from the specified guilds
     * @param commandsNames The registered names of the commands to delete
     * @param guildIDs The IDs of the guilds to delete the commands from. Defaults to all guilds the bot is in
     */
    deleteCommands(commandsNames: string[], guildIDs?: string[]): Promise<void>;
    /**
     * Returns the bot as a member of a guild
     * @param guildID The ID of the guild
     * @returns Member representation of the bot
     */
    asMember(guildID: string): Promise<GuildMember | null>;
    protected handleEvents(): Promise<void>;
    /**
     * Logs the bot, registers the interactions and starts listening for interactions creation
     * @param autoRegisterInteractions This should be set to `false` if you are not using TS or not using the decorators to register the interactions
     */
    start(autoRegisterInteractions?: boolean): Promise<void>;
}

type CustomInteractionType = CommandInteraction | ButtonInteraction | StringSelectMenuInteraction | ModalSubmitInteraction;
interface CustomInteraction<T extends CustomInteractionType> {
    readonly name: string;
    execute: (interaction: T, client: ExtendedClient) => Promise<void>;
}

interface CustomButtonInteraction extends CustomInteraction<ButtonInteraction> {
    execute(interaction: ButtonInteraction, client: ExtendedClient): Promise<void>;
}

declare const ErrorMessages: {
    NoPermission: string;
};

declare function randInt(min: number, max: number): number;
/**
 * Gets all files in a directory and its subdirectories.
 * @param rootDirectory The directory to start the search.
 * @param allFiles The initial array of files.
 * @returns An array containing all files in the directory and its subdirectories.
 */
declare function recursiveFiles(rootDirectory: string, allFiles?: string[]): Promise<string[]>;
declare function extendTypes(): void;

type EmbedField = {
    name: string;
    value: string;
    inline?: boolean;
};
type EmbedAuthor = {
    name: string;
    url?: string;
    iconURL?: string;
};
type EmbedFooter = {
    text: string;
    iconURL?: string;
};
type EmbedInitialData = {
    title?: string;
    description?: string;
    color?: ColorResolvable;
    showTimestamp?: boolean;
    defaultFooter?: boolean;
};
declare class MessageEmbedBuilder {
    private embed;
    static defaultFooter: EmbedFooter | null;
    static defaultColor: ColorResolvable;
    constructor(data: EmbedInitialData);
    setDefaultColor(color: ColorResolvable): this;
    setDefaultFooter(footer: EmbedFooter | null): this;
    setTitle(title: string): this;
    setDescription(description: string): this;
    addField(field: EmbedField): this;
    setFields(...fields: EmbedField[]): this;
    setThumbnail(url: string): this;
    setImage(url: string): this;
    setAuthor(author: EmbedAuthor): this;
    setColor(color: ColorResolvable): this;
    setFooter(footer: EmbedFooter): this;
    setTimestamp(timestamp: number): this;
    setURL(url: string): this;
    build(): EmbedBuilder;
    static from(embed: Embed): MessageEmbedBuilder;
}

/**
 * Sometimes you want to do something with an interaction but not directly reply to it.
 * Decorating a class with this will automatically defer and delete the reply of the interaction,
 * avoiding the "This interaction failed" message.
 * @throws {Error} If the class does not have an 'execute' method.
 */
declare function NoReplyInteraction(): (constructor: Function) => void;

/**
 * Decorating an interaction class with this will make it so that it will only execute if the member has all of the specified permissions in the guild scope.
 * @param permissions The permissions to check for.
 * @throws {Error} If the class does not have an 'execute' method.
 */
declare function RequireMemberPermission(...permissions: PermissionResolvable[]): (constructor: Function) => void;
/**
 * Decorating an interaction class with this will make it so that it will only execute if the member has all of the specified permissions in the interaction channel.
 * @param permissions The permissions to check for.
 * @throws {Error} If the class does not have an 'execute' method.
 */
declare function RequireChannelPermission(...permissions: PermissionResolvable[]): (constructor: Function) => void;

/**
 * Decorating a command interaction class will automatically register it to the client
 * @param name The name of the command
 * @param description The description of the command
 * @param defaultPermission Whether the command should be enabled by default when the app is added to a guild. Defaults to `true`
 *
 * @note If you use this decorator, you must import/load the module in which the interaction is defined
 */
declare function RegisterChatInputCommand(name: string, description: string, defaultPermission?: boolean): <T extends {
    new (...args: any[]): CustomChatInputCommand;
}>(clazz: T) => T;
/**
 * Decorating a command interaction class will automatically register it to the client
 * @param name The name of the command
 * @param defaultPermission Whether the command should be enabled by default when the app is added to a guild. Defaults to `true`
 *
 * @note If you use this decorator, you must import/load the module in which the interaction is defined
 */
declare function RegisterMessageCommand(name: string, defaultPermission?: boolean): <T extends {
    new (...args: any[]): CustomMessageCommand;
}>(clazz: T) => T;
/**
 * Decorating a command interaction class will automatically register it to the client
 * @param name The name of the command
 * @param description The description of the command
 * @param defaultPermission Whether the command should be enabled by default when the app is added to a guild. Defaults to `true`
 *
 * @note If you use this decorator, you must import/load the module in which the interaction is defined
 */
declare function RegisterUserCommand(name: string, defaultPermission?: boolean): <T extends {
    new (...args: any[]): CustomUserCommand;
}>(clazz: T) => T;
/**
 * Decorating a button interaction class will automatically register it to the client
 * @param id The id of the button
 *
 * @note If you use this decorator, you must import/load the module in which the interaction is defined
 */
declare function RegisterButton(id: string): <T extends {
    new (...args: any[]): CustomButtonInteraction;
}>(clazz: T) => T;
/**
 * Decorating a select menu interaction class will automatically register it to the client
 * @param id The id of the select menu
 *
 * @note If you use this decorator, you must import/load the module in which the interaction is defined
 */
declare function RegisterSelectMenu(id: string): <T extends {
    new (...args: any[]): CustomSelectMenuInteraction;
}>(clazz: T) => T;
/**
 * Decorating a modal interaction class will automatically register it to the client
 * @param id The id of the modal
 *
 * @note If you use this decorator, you must import/load the module in which the interaction is defined
 */
declare function RegisterModal(id: string): <T extends {
    new (...args: any[]): CustomModalInteraction;
}>(clazz: T) => T;

export { type CommandOption, type CustomButtonInteraction, type CustomChatInputCommand, type CustomCommandInteraction, type CustomInteraction, type CustomInteractionType, type CustomMessageCommand, type CustomModalInteraction, type CustomSelectMenuInteraction, type CustomUserCommand, type EmbedAuthor, type EmbedField, type EmbedFooter, type EmbedInitialData, ErrorMessages, ExtendedClient, MessageEmbedBuilder, NoReplyInteraction, type NumberCommandOption, RegisterButton, RegisterChatInputCommand, RegisterMessageCommand, RegisterModal, RegisterSelectMenu, RegisterUserCommand, RequireChannelPermission, RequireMemberPermission, type StringCommandOption, extendTypes, randInt, recursiveFiles, index_d as types };
