const require_rolldown_runtime = require('../../../../../../_virtual/rolldown_runtime.cjs');
const require_pathe_M_eThtNZ = require('../../../../pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.cjs');
const require_main$1 = require('../../../../dotenv@17.2.3/node_modules/dotenv/lib/main.cjs');
const require_index = require('../../../../exsolve@1.0.8/node_modules/exsolve/dist/index.cjs');
const require_jiti = require('../../../../jiti@2.6.1/node_modules/jiti/lib/jiti.cjs');
const require_defu = require('../../../../defu@6.1.4/node_modules/defu/dist/defu.cjs');
const require_index$1 = require('../../../../rc9@2.1.2/node_modules/rc9/dist/index.cjs');
const require_index$2 = require('../../../../pkg-types@2.3.0/node_modules/pkg-types/dist/index.cjs');
let node_fs = require("node:fs");
let node_os = require("node:os");
let node_fs_promises = require("node:fs/promises");
let node_url = require("node:url");

//#region ../../node_modules/.pnpm/c12@3.3.3_magicast@0.5.1/node_modules/c12/dist/index.mjs
var import_main = /* @__PURE__ */ require_rolldown_runtime.__toESM(require_main$1.default, 1);
/**
* Load and interpolate environment variables into `process.env`.
* If you need more control (or access to the values), consider using `loadDotenv` instead
*
*/
async function setupDotenv(options) {
	const targetEnvironment = options.env ?? process.env;
	const environment = await loadDotenv({
		cwd: options.cwd,
		fileName: options.fileName ?? ".env",
		env: targetEnvironment,
		interpolate: options.interpolate ?? true
	});
	const dotenvVars = getDotEnvVars(targetEnvironment);
	for (const key in environment) {
		if (key.startsWith("_")) continue;
		if (targetEnvironment[key] === void 0 || dotenvVars.has(key)) targetEnvironment[key] = environment[key];
	}
	return environment;
}
/** Load environment variables into an object. */
async function loadDotenv(options) {
	const environment = Object.create(null);
	const cwd = require_pathe_M_eThtNZ.resolve(options.cwd || ".");
	const _fileName = options.fileName || ".env";
	const dotenvFiles = typeof _fileName === "string" ? [_fileName] : _fileName;
	const dotenvVars = getDotEnvVars(options.env || {});
	Object.assign(environment, options.env);
	for (const file of dotenvFiles) {
		const dotenvFile = require_pathe_M_eThtNZ.resolve(cwd, file);
		if (!(0, node_fs.statSync)(dotenvFile, { throwIfNoEntry: false })?.isFile()) continue;
		const parsed = import_main.parse(await node_fs.promises.readFile(dotenvFile, "utf8"));
		for (const key in parsed) {
			if (key in environment && !dotenvVars.has(key)) continue;
			environment[key] = parsed[key];
			dotenvVars.add(key);
		}
	}
	if (options.interpolate) interpolate(environment);
	return environment;
}
function interpolate(target, source = {}, parse = (v) => v) {
	function getValue(key) {
		return source[key] === void 0 ? target[key] : source[key];
	}
	function interpolate$1(value, parents = []) {
		if (typeof value !== "string") return value;
		return parse((value.match(/(.?\${?(?:[\w:]+)?}?)/g) || []).reduce((newValue, match) => {
			const parts = /(.?)\${?([\w:]+)?}?/g.exec(match) || [];
			const prefix = parts[1];
			let value$1, replacePart;
			if (prefix === "\\") {
				replacePart = parts[0] || "";
				value$1 = replacePart.replace(String.raw`\$`, "$");
			} else {
				const key = parts[2];
				replacePart = (parts[0] || "").slice(prefix.length);
				if (parents.includes(key)) {
					console.warn(`Please avoid recursive environment variables ( loop: ${parents.join(" > ")} > ${key} )`);
					return "";
				}
				value$1 = getValue(key);
				value$1 = interpolate$1(value$1, [...parents, key]);
			}
			return value$1 === void 0 ? newValue : newValue.replace(replacePart, value$1);
		}, value));
	}
	for (const key in target) target[key] = interpolate$1(getValue(key));
}
function getDotEnvVars(targetEnvironment) {
	const globalRegistry = globalThis.__c12_dotenv_vars__ ||= /* @__PURE__ */ new Map();
	if (!globalRegistry.has(targetEnvironment)) globalRegistry.set(targetEnvironment, /* @__PURE__ */ new Set());
	return globalRegistry.get(targetEnvironment);
}
const _normalize = (p) => p?.replace(/\\/g, "/");
const ASYNC_LOADERS = {
	".yaml": () => Promise.resolve().then(() => require("../../../../confbox@0.2.2/node_modules/confbox/dist/yaml.cjs")).then((r) => r.parseYAML),
	".yml": () => Promise.resolve().then(() => require("../../../../confbox@0.2.2/node_modules/confbox/dist/yaml.cjs")).then((r) => r.parseYAML),
	".jsonc": () => Promise.resolve().then(() => require("../../../../confbox@0.2.2/node_modules/confbox/dist/jsonc.cjs")).then((r) => r.parseJSONC),
	".json5": () => Promise.resolve().then(() => require("../../../../confbox@0.2.2/node_modules/confbox/dist/json5.cjs")).then((r) => r.parseJSON5),
	".toml": () => Promise.resolve().then(() => require("../../../../confbox@0.2.2/node_modules/confbox/dist/toml.cjs")).then((r) => r.parseTOML)
};
const SUPPORTED_EXTENSIONS = Object.freeze([
	".js",
	".ts",
	".mjs",
	".cjs",
	".mts",
	".cts",
	".json",
	".jsonc",
	".json5",
	".yaml",
	".yml",
	".toml"
]);
async function loadConfig(options) {
	options.cwd = require_pathe_M_eThtNZ.resolve(process.cwd(), options.cwd || ".");
	options.name = options.name || "config";
	options.envName = options.envName ?? process.env.NODE_ENV;
	options.configFile = options.configFile ?? (options.name === "config" ? "config" : `${options.name}.config`);
	options.rcFile = options.rcFile ?? `.${options.name}rc`;
	if (options.extend !== false) options.extend = {
		extendKey: "extends",
		...options.extend
	};
	const _merger = options.merger || require_defu.defu;
	options.jiti = options.jiti || require_jiti.createJiti(require_pathe_M_eThtNZ.join(options.cwd, options.configFile), {
		interopDefault: true,
		moduleCache: false,
		extensions: [...SUPPORTED_EXTENSIONS],
		...options.jitiOptions
	});
	const r = {
		config: {},
		cwd: options.cwd,
		configFile: require_pathe_M_eThtNZ.resolve(options.cwd, options.configFile),
		layers: [],
		_configFile: void 0
	};
	const rawConfigs = {
		overrides: options.overrides,
		main: void 0,
		rc: void 0,
		packageJson: void 0,
		defaultConfig: options.defaultConfig
	};
	if (options.dotenv) await setupDotenv({
		cwd: options.cwd,
		...options.dotenv === true ? {} : options.dotenv
	});
	const _mainConfig = await resolveConfig(".", options);
	if (_mainConfig.configFile) {
		rawConfigs.main = _mainConfig.config;
		r.configFile = _mainConfig.configFile;
		r._configFile = _mainConfig._configFile;
	}
	if (_mainConfig.meta) r.meta = _mainConfig.meta;
	if (options.rcFile) {
		const rcSources = [];
		rcSources.push(require_index$1.read({
			name: options.rcFile,
			dir: options.cwd
		}));
		if (options.globalRc) {
			const workspaceDir = await require_index$2.findWorkspaceDir(options.cwd).catch(() => {});
			if (workspaceDir) rcSources.push(require_index$1.read({
				name: options.rcFile,
				dir: workspaceDir
			}));
			rcSources.push(require_index$1.readUser({
				name: options.rcFile,
				dir: options.cwd
			}));
		}
		rawConfigs.rc = _merger({}, ...rcSources);
	}
	if (options.packageJson) {
		const keys = (Array.isArray(options.packageJson) ? options.packageJson : [typeof options.packageJson === "string" ? options.packageJson : options.name]).filter((t) => t && typeof t === "string");
		const pkgJsonFile = await require_index$2.readPackageJSON(options.cwd).catch(() => {});
		rawConfigs.packageJson = _merger({}, ...keys.map((key) => pkgJsonFile?.[key]));
	}
	const configs = {};
	for (const key in rawConfigs) {
		const value = rawConfigs[key];
		configs[key] = await (typeof value === "function" ? value({
			configs,
			rawConfigs
		}) : value);
	}
	if (Array.isArray(configs.main)) r.config = configs.main;
	else {
		r.config = _merger(configs.overrides, configs.main, configs.rc, configs.packageJson, configs.defaultConfig);
		if (options.extend) {
			await extendConfig(r.config, options);
			r.layers = r.config._layers;
			delete r.config._layers;
			r.config = _merger(r.config, ...r.layers.map((e) => e.config));
		}
	}
	r.layers = [...[
		configs.overrides && {
			config: configs.overrides,
			configFile: void 0,
			cwd: void 0
		},
		{
			config: configs.main,
			configFile: options.configFile,
			cwd: options.cwd
		},
		configs.rc && {
			config: configs.rc,
			configFile: options.rcFile
		},
		configs.packageJson && {
			config: configs.packageJson,
			configFile: "package.json"
		}
	].filter((l) => l && l.config), ...r.layers];
	if (options.defaults) r.config = _merger(r.config, options.defaults);
	if (options.omit$Keys) {
		for (const key in r.config) if (key.startsWith("$")) delete r.config[key];
	}
	if (options.configFileRequired && !r._configFile) throw new Error(`Required config (${r.configFile}) cannot be resolved.`);
	return r;
}
async function extendConfig(config, options) {
	config._layers = config._layers || [];
	if (!options.extend) return;
	let keys = options.extend.extendKey;
	if (typeof keys === "string") keys = [keys];
	const extendSources = [];
	for (const key of keys) {
		extendSources.push(...(Array.isArray(config[key]) ? config[key] : [config[key]]).filter(Boolean));
		delete config[key];
	}
	for (let extendSource of extendSources) {
		const originalExtendSource = extendSource;
		let sourceOptions = {};
		if (extendSource.source) {
			sourceOptions = extendSource.options || {};
			extendSource = extendSource.source;
		}
		if (Array.isArray(extendSource)) {
			sourceOptions = extendSource[1] || {};
			extendSource = extendSource[0];
		}
		if (typeof extendSource !== "string") {
			console.warn(`Cannot extend config from \`${JSON.stringify(originalExtendSource)}\` in ${options.cwd}`);
			continue;
		}
		const _config = await resolveConfig(extendSource, options, sourceOptions);
		if (!_config.config) {
			console.warn(`Cannot extend config from \`${extendSource}\` in ${options.cwd}`);
			continue;
		}
		await extendConfig(_config.config, {
			...options,
			cwd: _config.cwd
		});
		config._layers.push(_config);
		if (_config.config._layers) {
			config._layers.push(..._config.config._layers);
			delete _config.config._layers;
		}
	}
}
const GIGET_PREFIXES = [
	"gh:",
	"github:",
	"gitlab:",
	"bitbucket:",
	"https://",
	"http://"
];
const NPM_PACKAGE_RE = /^(@[\da-z~-][\d._a-z~-]*\/)?[\da-z~-][\d._a-z~-]*($|\/.*)/;
async function resolveConfig(source, options, sourceOptions = {}) {
	if (options.resolve) {
		const res$1 = await options.resolve(source, options);
		if (res$1) return res$1;
	}
	const _merger = options.merger || require_defu.defu;
	const customProviderKeys = Object.keys(sourceOptions.giget?.providers || {}).map((key) => `${key}:`);
	const gigetPrefixes = customProviderKeys.length > 0 ? [...new Set([...customProviderKeys, ...GIGET_PREFIXES])] : GIGET_PREFIXES;
	if (options.giget !== false && gigetPrefixes.some((prefix) => source.startsWith(prefix))) {
		const { downloadTemplate } = await Promise.resolve().then(() => require("../../../../giget@2.0.0/node_modules/giget/dist/index.cjs"));
		const { digest } = await Promise.resolve().then(() => require("../../../../ohash@2.0.11/node_modules/ohash/dist/index.cjs"));
		const cloneName = source.replace(/\W+/g, "_").split("_").splice(0, 3).join("_") + "_" + digest(source).slice(0, 10).replace(/[-_]/g, "");
		let cloneDir;
		const localNodeModules = require_pathe_M_eThtNZ.resolve(options.cwd, "node_modules");
		const parentDir = require_pathe_M_eThtNZ.dirname(options.cwd);
		if (require_pathe_M_eThtNZ.basename(parentDir) === ".c12") cloneDir = require_pathe_M_eThtNZ.join(parentDir, cloneName);
		else if ((0, node_fs.existsSync)(localNodeModules)) cloneDir = require_pathe_M_eThtNZ.join(localNodeModules, ".c12", cloneName);
		else cloneDir = process.env.XDG_CACHE_HOME ? require_pathe_M_eThtNZ.resolve(process.env.XDG_CACHE_HOME, "c12", cloneName) : require_pathe_M_eThtNZ.resolve((0, node_os.homedir)(), ".cache/c12", cloneName);
		if ((0, node_fs.existsSync)(cloneDir) && !sourceOptions.install) await (0, node_fs_promises.rm)(cloneDir, { recursive: true });
		source = (await downloadTemplate(source, {
			dir: cloneDir,
			install: sourceOptions.install,
			force: sourceOptions.install,
			auth: sourceOptions.auth,
			...options.giget,
			...sourceOptions.giget
		})).dir;
	}
	if (NPM_PACKAGE_RE.test(source)) source = tryResolve(source, options) || source;
	const ext = require_pathe_M_eThtNZ.extname(source);
	const isDir = !ext || ext === require_pathe_M_eThtNZ.basename(source);
	const cwd = require_pathe_M_eThtNZ.resolve(options.cwd, isDir ? source : require_pathe_M_eThtNZ.dirname(source));
	if (isDir) source = options.configFile;
	const res = {
		config: void 0,
		configFile: void 0,
		cwd,
		source,
		sourceOptions
	};
	res.configFile = tryResolve(require_pathe_M_eThtNZ.resolve(cwd, source), options) || tryResolve(require_pathe_M_eThtNZ.resolve(cwd, ".config", source.replace(/\.config$/, "")), options) || tryResolve(require_pathe_M_eThtNZ.resolve(cwd, ".config", source), options) || source;
	if (!(0, node_fs.existsSync)(res.configFile)) return res;
	res._configFile = res.configFile;
	const configFileExt = require_pathe_M_eThtNZ.extname(res.configFile) || "";
	if (configFileExt in ASYNC_LOADERS) res.config = (await ASYNC_LOADERS[configFileExt]())(await (0, node_fs_promises.readFile)(res.configFile, "utf8"));
	else res.config = await options.jiti.import(res.configFile, { default: true });
	if (typeof res.config === "function") res.config = await res.config(options.context);
	if (options.envName) {
		const envConfig = {
			...res.config["$" + options.envName],
			...res.config.$env?.[options.envName]
		};
		if (Object.keys(envConfig).length > 0) res.config = _merger(envConfig, res.config);
	}
	res.meta = require_defu.defu(res.sourceOptions.meta, res.config.$meta);
	delete res.config.$meta;
	if (res.sourceOptions.overrides) res.config = _merger(res.sourceOptions.overrides, res.config);
	res.configFile = _normalize(res.configFile);
	res.source = _normalize(res.source);
	return res;
}
function tryResolve(id, options) {
	const res = require_index.resolveModulePath(id, {
		try: true,
		from: (0, node_url.pathToFileURL)(require_pathe_M_eThtNZ.join(options.cwd || ".", options.configFile || "/")),
		suffixes: ["", "/index"],
		extensions: SUPPORTED_EXTENSIONS,
		cache: false
	});
	return res ? require_pathe_M_eThtNZ.normalize(res) : void 0;
}

//#endregion
exports.loadConfig = loadConfig;