Lakukan optimalisasi pada kode berikut serta ganti menggunakan chokidar: // inspired from https://github.com/Nurutomo/mahbod/blob/main/src/util/PluginManager.ts
import fs, { existsSync, watch } from 'fs'
import path, { join, resolve } from 'path'
import * as os from 'os'
import syntaxerror from 'syntax-error'
import yargs from 'yargs'
import { fileURLToPath, pathToFileURL } from 'url'
import { createRequire } from 'module'
import Stream, { Readable } from 'stream'

/** 
 * @param {ImportMeta | string} pathURL 
 * @param {boolean?} rmPrefix if value is `'true'`, it will remove `'file://'` prefix, if windows it will automatically false
 */
const __filename = function filename(pathURL = import.meta, rmPrefix = os.platform() !== 'win32') {
    const path = /** @type {ImportMeta} */ (pathURL).url || /** @type {String} */ (pathURL)
    return rmPrefix ? /file:\/\/\//.test(path) ? fileURLToPath(path) : path : /file:\/\/\//.test(path) ? path : pathToFileURL(path).href
}

/** @param {ImportMeta | string} pathURL */
const __dirnames = function dirname(pathURL) {
    const dir = __filename(pathURL, true)
    const regex = /\/$/
    return regex.test(dir) ? dir : fs.existsSync(dir) && fs.statSync(dir).isDirectory() ? dir.replace(regex, '') : path.dirname(dir) // windows
}

async function importLoader(module) {
    module = __filename(module)
    const module_ = await import(`${module}?id=${Date.now()}`)
    const result = module_ && 'default' in module_ ? module_.default : module_
    return result
}

const __dirname = __dirnames(import.meta)
const rootDirectory = __dirnames(join(__dirname, '../'))
const pluginFolder = __dirnames(join(__dirname, '../plugins'))
const pluginFilter = filename => /\.(mc)?js$/.test(filename)

let watcher = {},
    plugins = {},
    pluginFolders = []
    
/**
 * load files from plugin folder as plugins 
 * @param {string} pluginFolder 
 * @param {(filename: string) => boolean} pluginFilter 
 * @param {{ 
 *  logger: import('./connection.js').Socket['logger'];
 *  recursiveRead: boolean;
 * }} opts if `'recursiveRead'` is true, it will load folder (call `loadPluginsFiles` function) inside pluginFolder not just load the files
 */
async function loadPluginFiles(pluginFolder = pluginFolder, pluginFilter = pluginFilter, opts = {
    recursiveRead: false
}) {
    const folder = resolve(pluginFolder)
    if (folder in watcher) return
    pluginFolders.push(folder)
    const paths = await fs.promises.readdir(pluginFolder)
    await Promise.all(paths.map(async path => {
        const resolved = join(folder, path)
        // trim file:// prefix because lstat will throw error
        const dirname = __filename(resolved, true)
        const formatedFilename = formatFilename(resolved)
        try {
            const stats = await fs.promises.lstat(dirname)
            // if folder 
            if (!stats.isFile()) {
                // and if `recursiveRead` is true
                if (opts.recursiveRead) await loadPluginFiles(dirname, pluginFilter, opts)
                // return because import only can load file
                return
            }
            // if windows it will have file:// prefix because if not it will throw error
            const filename = __filename(resolved)
            const isValidFile = pluginFilter(filename)
            if (!isValidFile) return
            const module = await importLoader(filename)
            if (module) plugins[formatedFilename] = module
        } catch (e) {
            opts.logger?.error(e, `error while requiring ${formatedFilename}`)
            delete plugins[formatedFilename]
        }
    }))
    const watching = watch(folder, reload.bind(null, {
        logger: opts.logger,
        pluginFolder,
        pluginFilter
    }))
    watching.on('close', () => deletePluginFolder(folder, true))
    watcher[folder] = watching
    return plugins = sortedPlugins(plugins)
}

/**
 * It will delete and doesn't watch the folder
 * @param {string} folder ;
 * @param {boolean?} isAlreadyClosed 
 */
function deletePluginFolder(folder, isAlreadyClosed = false) {
    const resolved = resolve(folder)
    if (!(resolved in watcher)) return
    if (!isAlreadyClosed) watcher[resolved].close()
    delete watcher[resolved]
    pluginFolders.splice(pluginFolders.indexOf(resolved), 1)
}

/**
 * reload file to load latest changes
 * @param {{
 *  logger?: import('./connection.js').Socket['logger'];
 *  pluginFolder?: string;
 *  pluginFilter?: (filename: string) => boolean;
 * }} opts
 * @param {*} _ev 
 * @param {*} filename 
 * @returns 
 */
async function reload({
    logger,
    pluginFolder = pluginFolder,
    pluginFilter = pluginFilter
}, _ev, filename) {
    if (pluginFilter(filename)) {
        // trim file:// prefix because lstat will throw exception
        const file = __filename(join(pluginFolder, filename), true)
        const formatedFilename = formatFilename(file)
        if (formatedFilename in plugins) {
            if (existsSync(file)) logger?.info(`updated plugin - '${formatedFilename}'`)
            else {
                logger?.warn(`deleted plugin - '${formatedFilename}'`)
                return delete plugins[formatedFilename]
            }
        } else logger?.info(`new plugin - '${formatedFilename}'`)
        const src = await fs.promises.readFile(file)
        // check syntax error
        let err = syntaxerror(src, filename, {
            sourceType: 'module',
            allowAwaitOutsideFunction: true
        })
        if (err) logger?.error(err, `syntax error while loading '${formatedFilename}'`)
        else try {
            const module = await importLoader(file)
            if (module) plugins[formatedFilename] = module
        } catch (e) {
            logger?.error(e, `error require plugin '${formatedFilename}'`)
            delete plugins[formatedFilename]
        } finally {
            plugins = sortedPlugins(plugins)
        }
    }
}

/**
 * `'/home/games-wabot/plugins/games/tebakgambar.js'` formated to `'plugins/games/tebakgambar.js'`
 * @param {string} filename 
 * @returns {string}
 */
function formatFilename(filename) {
    let dir = join(rootDirectory, './')
    // fix invalid regular expresion when run in windows
    if (os.platform() === 'win32') dir = dir.replace(/\\/g, '\\\\')
    // '^' mean only replace if starts with
    const regex = new RegExp(`^${dir}`)
    const formated = filename.replace(regex, '')
    return formated
}
/**
 * Sorted plugins by of their key
 * @param {{
 *  [k: string]: any;
 * }} plugins 
 * @returns {{
 *  [k: string]: any;
 * }} 
 */
function sortedPlugins(plugins) {
    return Object.fromEntries(Object.entries(plugins).sort(([a], [b]) => a.localeCompare(b)))
}
export {
    pluginFolder,
    pluginFilter,
    plugins,
    watcher,
    pluginFolders,
    loadPluginFiles,
    deletePluginFolder,
    reload
}