import { compareVersions } from "./compareVersion.mjs";
import { join, relative, resolve } from "node:path";
import { prepareIntlayer, runOnce } from "@intlayer/chokidar";
import { getAlias, getAppLogger, getConfiguration, getProjectRequire, normalizePath } from "@intlayer/config";
import { getDictionaries } from "@intlayer/dictionaries-entry";
import { IntlayerPlugin } from "@intlayer/webpack";
import merge from "deepmerge";
import fg from "fast-glob";
import nextPackageJSON from "next/package.json" with { type: "json" };

//#region src/server/withIntlayer.ts
const isGteNext13 = compareVersions(nextPackageJSON.version, "≥", "13.0.0");
const isGteNext15 = compareVersions(nextPackageJSON.version, "≥", "15.0.0");
const isTurbopackEnabled = compareVersions(nextPackageJSON.version, "≥", "16.0.0") ? !process.env.npm_lifecycle_script?.includes("--webpack") : process.env.npm_lifecycle_script?.includes("--turbo");
const isTurbopackStable = compareVersions(nextPackageJSON.version, "≥", "15.3.0");
const getIsSwcPluginAvailable = (intlayerConfig) => {
	try {
		(intlayerConfig.build?.require ?? getProjectRequire()).resolve("@intlayer/swc");
		return true;
	} catch (_e) {
		return false;
	}
};
const resolvePluginPath = (pluginPath, intlayerConfig) => {
	const pluginPathResolved = (intlayerConfig.build?.require ?? getProjectRequire())?.resolve(pluginPath);
	if (isTurbopackEnabled) return normalizePath(`./${relative(process.cwd(), pluginPathResolved)}`);
	return pluginPathResolved;
};
const getPruneConfig = (intlayerConfig) => {
	const { optimize, traversePattern, importMode } = intlayerConfig.build;
	const { dictionariesDir, dynamicDictionariesDir, fetchDictionariesDir, mainDir, baseDir } = intlayerConfig.content;
	if (!optimize) return {};
	if (!isGteNext13) return {};
	if (!getIsSwcPluginAvailable(intlayerConfig)) return {};
	const logger = getAppLogger(intlayerConfig);
	runOnce(join(baseDir, ".intlayer", "cache", "intlayer-prune-plugin-enabled.lock"), () => logger("Intlayer prune plugin is enabled"), { cacheTimeoutMs: 1e3 * 10 });
	const dictionariesEntryPath = join(mainDir, "dictionaries.mjs");
	const dynamicDictionariesEntryPath = join(mainDir, "dynamic_dictionaries.mjs");
	const fetchDictionariesEntryPath = join(mainDir, "fetch_dictionaries.mjs");
	const filesList = [...fg.sync(traversePattern, { cwd: baseDir }).map((file) => join(baseDir, file)), dictionariesEntryPath];
	const dictionaries = getDictionaries(intlayerConfig);
	const liveSyncKeys = Object.values(dictionaries).filter((dictionary) => dictionary.live).map((dictionary) => dictionary.key);
	return { experimental: { swcPlugins: [[resolvePluginPath("@intlayer/swc", intlayerConfig), {
		dictionariesDir,
		dictionariesEntryPath,
		dynamicDictionariesDir,
		dynamicDictionariesEntryPath,
		fetchDictionariesDir,
		fetchDictionariesEntryPath,
		importMode,
		filesList,
		replaceDictionaryEntry: false,
		liveSyncKeys
	}]] } };
};
const getCommandsEvent = () => {
	const lifecycleEvent = process.env.npm_lifecycle_event;
	const lifecycleScript = process.env.npm_lifecycle_script ?? "";
	return {
		isDevCommand: lifecycleEvent === "dev" || process.argv.some((arg) => arg === "dev") || /(^|\s)(next\s+)?dev(\s|$)/.test(lifecycleScript),
		isBuildCommand: lifecycleEvent === "build" || process.argv.some((arg) => arg === "build") || /(^|\s)(next\s+)?build(\s|$)/.test(lifecycleScript),
		isStartCommand: lifecycleEvent === "start" || process.argv.some((arg) => arg === "start") || /(^|\s)(next\s+)?start(\s|$)/.test(lifecycleScript)
	};
};
/**
* A Next.js plugin that adds the intlayer configuration to the webpack configuration
* and sets the environment variables
*
* Usage:
*
* ```ts
* // next.config.js
* export default withIntlayerSync(nextConfig)
* ```
*/
const withIntlayerSync = (nextConfig = {}, configOptions) => {
	if (typeof nextConfig !== "object") nextConfig = {};
	const intlayerConfig = getConfiguration(configOptions);
	const { isBuildCommand, isDevCommand } = getCommandsEvent();
	const turboConfig = {
		resolveAlias: getAlias({
			configuration: intlayerConfig,
			formatter: (value) => `./${value}`
		}),
		rules: { "*.node": {
			as: "*.node",
			loaders: ["node-loader"]
		} }
	};
	const serverExternalPackages = [
		"esbuild",
		"module",
		"fs",
		"chokidar",
		"fsevents"
	];
	const getNewConfig = () => {
		let config = {};
		if (isGteNext15) config = {
			...config,
			serverExternalPackages
		};
		if (isGteNext13 && !isGteNext15) config = {
			...config,
			experimental: {
				...config?.experimental ?? {},
				serverComponentsExternalPackages: serverExternalPackages
			}
		};
		if (isTurbopackEnabled) if (isGteNext15 && isTurbopackStable) config = {
			...config,
			turbopack: turboConfig
		};
		else config = {
			...config,
			experimental: {
				...config?.experimental ?? {},
				turbo: turboConfig
			}
		};
		else config = {
			...config,
			webpack: (config$1, options) => {
				const { isServer, nextRuntime } = options;
				if (typeof nextConfig.webpack === "function") config$1 = nextConfig.webpack(config$1, options);
				config$1.externals.push({
					esbuild: "esbuild",
					module: "module",
					fs: "fs",
					chokidar: "chokidar",
					fsevents: "fsevents"
				});
				config$1.module.rules.push({
					test: /\.node$/,
					loader: "node-loader"
				});
				config$1.resolve.alias = {
					...config$1.resolve.alias,
					...getAlias({
						configuration: intlayerConfig,
						formatter: (value) => resolve(value)
					})
				};
				if (isDevCommand && isServer && nextRuntime === "nodejs") config$1.plugins.push(new IntlayerPlugin(intlayerConfig));
				return config$1;
			}
		};
		return config;
	};
	let pruneConfig = {};
	if (isBuildCommand) pruneConfig = getPruneConfig(intlayerConfig);
	const intlayerNextConfig = merge(pruneConfig, getNewConfig());
	return merge(nextConfig, intlayerNextConfig);
};
/**
* A Next.js plugin that adds the intlayer configuration to the webpack configuration
* and sets the environment variables
*
* Usage:
*
* ```ts
* // next.config.js
* export default withIntlayer(nextConfig)
* ```
*
* > Node withIntlayer is a promise function. Use withIntlayerSync instead if you want to use it synchronously.
* > Using the promise allows to prepare the intlayer dictionaries before the build starts.
*
*/
const withIntlayer = async (nextConfig = {}, configOptions) => {
	const { isBuildCommand, isDevCommand } = getCommandsEvent();
	if (isDevCommand || isBuildCommand) await prepareIntlayer(getConfiguration(configOptions), {
		clean: isBuildCommand,
		cacheTimeoutMs: isBuildCommand ? 1e3 * 30 : 1e3 * 60 * 60
	});
	return withIntlayerSync(nextConfig, configOptions);
};

//#endregion
export { withIntlayer, withIntlayerSync };
//# sourceMappingURL=withIntlayer.mjs.map