managers_interaction_ModalInteractionManager.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 modal interaction manager.
 * @class
 */
class ModalInteractionManager {
    /**
     * The constructor of the modal interaction manager class.
     * @param {Client} client The client
     * @param {InteractionManager} interactionManager The interaction manager
     */
    constructor(client, interactionManager) {
        /**
         * The cache with all modal interactions
         * @type {Collection<String, ModalInteraction>}
         * @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 modal interaction
     * @param {String} path The path to the modal interaction
     * @returns {Promise<Boolean|DisGroupDevError>}
     * @public
     */
    load(path) {
        return new Promise((resolve, reject) => {
            try {
                /** @type {ModalInteraction} */
                const modalInteraction = new (require(path))(this.client, this.manager);

                if (!modalInteraction.enabled) return;

                modalInteraction.location = path;

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

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

                /**
                 * Emitted when a modal interaction is loaded.
                 * @event InteractionManager#modalInteractionLoad
                 * @param {ModalInteraction} modalInteraction The modal interaction
                 * @public
                 */
                this.manager.emit('modalInteractionLoad', modalInteraction);

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

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

                for (const modalInteractionDirectoryCategoryOrFile of modalInteractionDirectory) {
                    const modalInteractionDirectoryStat = await statDirectory(require('node:path').resolve(this.manager.options.locationModalInteractions, modalInteractionDirectoryCategoryOrFile));

                    if (modalInteractionDirectoryStat.isDirectory()) {
                        const modalInteractionDirectoryCategory = await readDirectory(require('node:path').resolve(this.manager.options.locationModalInteractions, modalInteractionDirectoryCategoryOrFile));

                        for (const modalInteractionDirectoryCategoryFile of modalInteractionDirectoryCategory) {
                            await this.load(`${this.manager.options.locationModalInteractions}/${modalInteractionDirectoryCategoryOrFile}/${modalInteractionDirectoryCategoryFile}`);
                        }
                    } else if (modalInteractionDirectoryStat.isFile()) {
                        await this.load(`${this.manager.options.locationModalInteractions}/${modalInteractionDirectoryCategoryOrFile}`);
                    }
                }

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

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

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

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

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

                /**
                 * Emitted when a modal interaction is reloaded.
                 * @event InteractionManager#modalInteractionReload
                 * @param {ModalInteraction} modalInteraction The modal interaction
                 * @public
                 */
                this.manager.emit('modalInteractionReload', modalInteraction);

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

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

                await this.loadAll();

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

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

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

                this.cache.delete(name);

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

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

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

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

module.exports = ModalInteractionManager;