
import fs from "node:fs/promises";
import path from 'node:path';
import { errorCodes, newErrorWithCode } from "../errors.js";
import { pathToFileURL } from 'url';

import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);


/**
 * This returns a function which will attempt to load a CommonJS or ES Module from the passed 'includeDirs', or any path in NODE_PATH.
 * @param {String[]} includeDirs 
 */
export default function(includeDirs = []) {
	const node_path = process.env["NODE_PATH"];

	if (node_path) {
		const envVarDelimiter = process.platform === "win32" ? ";" : ":";
		includeDirs = includeDirs.concat(node_path.split(envVarDelimiter));
	}

	includeDirs = [... new Set(includeDirs)]; // Remove any duplicates


	return async function tryImportingModule(moduleName) {

		for (const dir of includeDirs) {
			const matches = (await fs.readdir(dir, {})).filter(item => path.parse(item).name === moduleName);
		
			if (matches.length) {
				const match = matches[0];

				const matchPath = path.join(dir, match);
				const matchFileUrl = pathToFileURL(matchPath); // import() requires a file URL on Windows
		
				if (path.extname(match) === ".mjs") { // Found a loose module file in this directory
					return await import(`${matchFileUrl}`);
				}
				else if (path.extname(match) === ".js") { // Found a loose module file in this directory
					return await require(matchPath);
				}
				else if (path.extname(match) === "") { // Found a directory containing the module
		
					// First try just 'require-ing' the directory (which should work if it's a CommonJS module):
					try {
						return require(matchPath);
					}
					catch (ignore) {}

					// It's probably an ES Module, which don't support 'directory import', so we need to import the main file directly.

					// Try getting the main file from package.json:
					const packagePath = path.join(dir,match,"package.json");
					try {
						await fs.access(packagePath);
						const data = JSON.parse(await fs.readFile(packagePath, "utf8"));
						if (data.main) {
							const mainPath = path.join(dir, match, data.main);
							return await import(`${pathToFileURL(mainPath)}`);
						}
					}
					catch (ignore) {}
		
					// Try using <moduleName>.mjs:
					try {
						return await import(`${pathToFileURL(path.join(dir, match, `${moduleName}.mjs`))}`);
					} catch (ignore) {}
		
					// Try using index.mjs:
					try {
						return await import(`${pathToFileURL(path.join(dir, match, `index.mjs`))}`);
					} catch (ignore) {}
				}
			}
		}
	
		throw newErrorWithCode(errorCodes.MODULE_NOT_FOUND); // jmg1259
	}
}