managers_interaction_SelectMenuInteractionManager.js

'use strict';

const readDirectory = require('node:util').promisify(require('node:fs').readdir);
const statDirectory = require('node:util').promisify(require('node:fs').stat);
const { Collection } = require('discord.js');
const { DisGroupDevError, Messages } = require('../../errors/DisGroupDevError');

/**
 * The select menu interaction manager.
 * @class
 */
class SelectMenuInteractionManager {
    /**
     * The constructor of the select menu interaction manager class.
     * @param {Client} client The client
     * @param {InteractionManager} interactionManager The interaction manager
     */
    constructor(client, interactionManager) {
        /**
         * The cache with all select menu interactions
         * @type {Collection<String, SelectMenuInteraction>}
         * @public
         */
        this.cache = new Collection();

        /**
         * The client
         * @type {Client}
         * @public
         */
        this.client = client;

        /**
         * The interaction manager
         * @type {InteractionManager}
         * @public
         */
        this.manager = interactionManager;
    }

    /**
     * Loads one specific select menu interaction
     * @param {String} path The path to the select menu interaction
     * @returns {Promise<Boolean|DisGroupDevError>}
     * @public
     */
    load(path) {
        return new Promise((resolve, reject) => {
            try {
                /** @type {SelectMenuInteraction} */
                const selectMenuInteraction = new (require(path))(this.client, this.manager);

                if (!selectMenuInteraction.enabled) return;

                selectMenuInteraction.location = path;

                if (selectMenuInteraction.init && typeof selectMenuInteraction.init === 'function') selectMenuInteraction.init();
                if (!selectMenuInteraction.execute || typeof selectMenuInteraction.execute !== 'function') reject(new DisGroupDevError(Messages.INVALID_EXECUTE(selectMenuInteraction.name)));

                this.cache.set(selectMenuInteraction.name, selectMenuInteraction);

                /**
                 * Emitted when a select menu interaction is loaded.
                 * @event InteractionManager#selectMenuInteractionLoad
                 * @param {SelectMenuInteraction} selectMenuInteraction The select menu interaction
                 * @public
                 */
                this.manager.emit('selectMenuInteractionLoad', selectMenuInteraction);

                resolve(true);
            } catch (e) {
                throw new DisGroupDevError(e);
            }
        });
    }

    /**
     * Loads all select menu interactions
     * @returns {Promise<Boolean|DisGroupDevError>}
     * @public
     */
    loadAll() {
        return new Promise(async resolve => {
            try {
                const selectMenuInteractionDirectory = await readDirectory(this.manager.options.locationSelectMenuInteractions);

                for (const selectMenuInteractionDirectoryCategoryOrFile of selectMenuInteractionDirectory) {
                    const selectMenuInteractionDirectoryStat = await statDirectory(require('node:path').resolve(this.manager.options.locationSelectMenuInteractions, selectMenuInteractionDirectoryCategoryOrFile));

                    if (selectMenuInteractionDirectoryStat.isDirectory()) {
                        const selectMenuInteractionDirectoryCategory = await readDirectory(require('node:path').resolve(this.manager.options.locationSelectMenuInteractions, selectMenuInteractionDirectoryCategoryOrFile));

                        for (const selectMenuInteractionDirectoryCategoryFile of selectMenuInteractionDirectoryCategory) {
                            await this.load(`${this.manager.options.locationSelectMenuInteractions}/${selectMenuInteractionDirectoryCategoryOrFile}/${selectMenuInteractionDirectoryCategoryFile}`);
                        }
                    } else if (selectMenuInteractionDirectoryStat.isFile()) {
                        await this.load(`${this.manager.options.locationSelectMenuInteractions}/${selectMenuInteractionDirectoryCategoryOrFile}`);
                    }
                }

                resolve(true);
            } catch (e) {
                throw new DisGroupDevError(e);
            }
        });
    }

    /**
     * Reloads one specific select menu interaction
     * @param {String} name The name of the select menu interaction
     * @returns {Promise<Boolean|DisGroupDevError>}
     * @public
     */
    reload(name) {
        return new Promise(async (resolve, reject) => {
            if (!this.cache.has(name)) reject(new DisGroupDevError(Messages.SELECT_MENU_INTERACTION_NOT_FOUND(name)));

            const { location } = require(this.cache.get(name));

            try {
                await this.unload(name);
                await this.load(location);

                const selectMenuInteraction = this.cache.get(name);

                /**
                 * Emitted when a select menu interaction is reloaded.
                 * @event InteractionManager#selectMenuInteractionReload
                 * @param {SelectMenuInteraction} selectMenuInteraction The select menu interaction
                 * @public
                 */
                this.manager.emit('selectMenuInteractionReload', selectMenuInteraction);

                resolve(true);
            } catch (e) {
                throw new DisGroupDevError(e);
            }
        });
    }

    /**
     * Reloads all select menu interactions
     * @returns {Promise<Boolean|DisGroupDevError>}
     * @public
     */
    reloadAll() {
        return new Promise(async resolve => {
            try {
                for (const selectMenuInteraction of this.cache) {
                    await this.unload(selectMenuInteraction[1].name);
                }

                await this.loadAll();

                resolve(true);
            } catch (e) {
                throw new DisGroupDevError(e);
            }
        });
    }

    /**
     * Unloads one specific select menu interaction
     * @param {String} name The name of the select menu interaction
     * @returns {Promise<Boolean|DisGroupDevError>}
     * @public
     */
    unload(name) {
        return new Promise((resolve, reject) => {
            if (!this.cache.has(name)) reject(new DisGroupDevError(Messages.SELECT_MENU_INTERACTION_NOT_FOUND(name)));

            try {
                delete require.cache[require.resolve(this.cache.get(name).location)];

                this.cache.delete(name);

                /**
                 * Emitted when a select menu interaction is unloaded.
                 * @event InteractionManager#selectMenuInteractionUnload
                 * @param {String} name The name of the select menu interaction
                 * @public
                 */
                this.manager.emit('selectMenuInteractionUnload', name);

                resolve(true);
            } catch (e) {
                throw new DisGroupDevError(e);
            }
        });
    }

    /**
     * Unloads all select menu interactions
     * @returns {Promise<Boolean|DisGroupDevError>}
     * @public
     */
    unloadAll() {
        return new Promise(async resolve => {
            try {
                for (const selectMenuInteraction of this.cache) {
                    await this.unload(selectMenuInteraction[1].name);
                }

                resolve(true);
            } catch (e) {
                throw new DisGroupDevError(e);
            }
        });
    }
}

module.exports = SelectMenuInteractionManager;