import { existsSync, promises } from "node:fs";
import process from "node:process";
import { createRecoveryConfigLoader } from "@unocss/config";
import { BetterMap, createGenerator, cssIdRE, toArray } from "@unocss/core";
import { createFilter } from "unplugin-utils";
import remapping from "@jridgewell/remapping";
import MagicString from "magic-string";
import { cyan, dim, green } from "colorette";
import { consola } from "consola";
import { basename, dirname, normalize, relative, resolve } from "pathe";
import { debounce } from "perfect-debounce";
import { glob } from "tinyglobby";
import presetUno from "@unocss/preset-uno";

//#region ../../virtual-shared/integration/src/constants.ts
const INCLUDE_COMMENT = "@unocss-include";
const IGNORE_COMMENT = "@unocss-ignore";
const CSS_PLACEHOLDER = "@unocss-placeholder";
const SKIP_START_COMMENT = "@unocss-skip-start";
const SKIP_END_COMMENT = "@unocss-skip-end";
const SKIP_COMMENT_RE = new RegExp(`(\/\/\\s*?${SKIP_START_COMMENT}\\s*?|\\/\\*\\s*?${SKIP_START_COMMENT}\\s*?\\*\\/|<!--\\s*?${SKIP_START_COMMENT}\\s*?-->)[\\s\\S]*?(\/\/\\s*?${SKIP_END_COMMENT}\\s*?|\\/\\*\\s*?${SKIP_END_COMMENT}\\s*?\\*\\/|<!--\\s*?${SKIP_END_COMMENT}\\s*?-->)`, "g");

//#endregion
//#region ../../virtual-shared/integration/src/defaults.ts
const defaultPipelineExclude = [cssIdRE];
const defaultPipelineInclude = [/\.(vue|svelte|[jt]sx|vine.ts|mdx?|astro|elm|php|phtml|marko|html)($|\?)/];

//#endregion
//#region ../../virtual-shared/integration/src/deprecation.ts
function deprecationCheck(config) {}

//#endregion
//#region ../../virtual-shared/integration/src/context.ts
function createContext(configOrPath, defaults = {}, extraConfigSources = [], resolveConfigResult = () => {}) {
	let root = process.cwd();
	let rawConfig = {};
	let configFileList = [];
	let uno;
	const _uno = createGenerator(rawConfig, defaults).then((r) => {
		uno = r;
		return r;
	});
	let rollupFilter = createFilter(defaultPipelineInclude, defaultPipelineExclude, { resolve: typeof configOrPath === "string" ? configOrPath : root });
	const invalidations = [];
	const reloadListeners = [];
	const modules = new BetterMap();
	const tokens = /* @__PURE__ */ new Set();
	const tasks = [];
	const affectedModules = /* @__PURE__ */ new Set();
	const loadConfig$1 = createRecoveryConfigLoader();
	let ready = reloadConfig();
	async function reloadConfig() {
		var _rawConfig$content, _rawConfig$content2, _rawConfig$content3;
		await _uno;
		const result = await loadConfig$1(root, configOrPath, extraConfigSources, defaults);
		resolveConfigResult(result);
		/* @__PURE__ */ deprecationCheck(result.config);
		rawConfig = result.config;
		configFileList = result.sources;
		await uno.setConfig(rawConfig);
		uno.config.envMode = "dev";
		rollupFilter = ((_rawConfig$content = rawConfig.content) === null || _rawConfig$content === void 0 ? void 0 : _rawConfig$content.pipeline) === false ? () => false : createFilter(((_rawConfig$content2 = rawConfig.content) === null || _rawConfig$content2 === void 0 || (_rawConfig$content2 = _rawConfig$content2.pipeline) === null || _rawConfig$content2 === void 0 ? void 0 : _rawConfig$content2.include) || defaultPipelineInclude, ((_rawConfig$content3 = rawConfig.content) === null || _rawConfig$content3 === void 0 || (_rawConfig$content3 = _rawConfig$content3.pipeline) === null || _rawConfig$content3 === void 0 ? void 0 : _rawConfig$content3.exclude) || defaultPipelineExclude, { resolve: typeof configOrPath === "string" ? configOrPath : root });
		tokens.clear();
		await Promise.all(modules.map((code, id) => uno.applyExtractors(code.replace(SKIP_COMMENT_RE, ""), id, tokens)));
		invalidate();
		dispatchReload();
		return result;
	}
	async function updateRoot(newRoot) {
		if (newRoot !== root) {
			root = newRoot;
			ready = reloadConfig();
		}
		return await ready;
	}
	function invalidate() {
		invalidations.forEach((cb) => cb());
	}
	function dispatchReload() {
		reloadListeners.forEach((cb) => cb());
	}
	async function extract(code, id) {
		const uno$1 = await _uno;
		if (id) modules.set(id, code);
		const len = tokens.size;
		await uno$1.applyExtractors(code.replace(SKIP_COMMENT_RE, ""), id, tokens);
		if (tokens.size > len) invalidate();
	}
	function filter(code, id) {
		if (code.includes(IGNORE_COMMENT)) return false;
		return code.includes(INCLUDE_COMMENT) || code.includes(CSS_PLACEHOLDER) || rollupFilter(id.replace(/\?v=\w+$/, ""));
	}
	async function getConfig() {
		await ready;
		return rawConfig;
	}
	async function flushTasks() {
		const _tasks = [...tasks];
		await Promise.all(_tasks);
		if (tasks[0] === _tasks[0]) tasks.splice(0, _tasks.length);
	}
	/**
	* Get regexes to match virtual module ids
	*/
	const vmpCache = /* @__PURE__ */ new Map();
	async function getVMPRegexes() {
		const prefix = (await getConfig()).virtualModulePrefix || "__uno";
		if (vmpCache.has(prefix)) return vmpCache.get(prefix);
		const regexes = {
			prefix,
			RESOLVED_ID_WITH_QUERY_RE: /* @__PURE__ */ new RegExp(`[/\\\\]${prefix}(_.*?)?\\.css(\\?.*)?$`),
			RESOLVED_ID_RE: /* @__PURE__ */ new RegExp(`[/\\\\]${prefix}(?:_(.*?))?\.css$`)
		};
		vmpCache.set(prefix, regexes);
		return regexes;
	}
	return {
		get ready() {
			return ready;
		},
		tokens,
		modules,
		affectedModules,
		tasks,
		flushTasks,
		invalidate,
		onInvalidate(fn) {
			invalidations.push(fn);
		},
		filter,
		reloadConfig,
		onReload(fn) {
			reloadListeners.push(fn);
		},
		get uno() {
			if (!uno) throw new Error("Run `await context.ready` before accessing `context.uno`");
			return uno;
		},
		extract,
		getConfig,
		get root() {
			return root;
		},
		updateRoot,
		getConfigFileList: () => configFileList,
		getVMPRegexes
	};
}

//#endregion
//#region ../../virtual-shared/integration/src/utils.ts
function hash(str) {
	let i;
	let l;
	let hval = 2166136261;
	for (i = 0, l = str.length; i < l; i++) {
		hval ^= str.charCodeAt(i);
		hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
	}
	return `00000${(hval >>> 0).toString(36)}`.slice(-6);
}
function transformSkipCode(code, map, SKIP_RULES_RE, keyFlag) {
	for (const item of Array.from(code.matchAll(SKIP_RULES_RE))) if (item != null) {
		const matched = item[0];
		const withHashKey = `${keyFlag}${hash(matched)}`;
		map.set(withHashKey, matched);
		code = code.replace(matched, withHashKey);
	}
	return code;
}
function restoreSkipCode(code, map) {
	for (const [withHashKey, matched] of map.entries()) code = code.replaceAll(withHashKey, matched);
	return code;
}

//#endregion
//#region ../../virtual-shared/integration/src/transformers.ts
async function applyTransformers(ctx, original, id, enforce = "default") {
	if (original.includes(IGNORE_COMMENT)) return;
	const transformers = (ctx.uno.config.transformers || []).filter((i) => (i.enforce || "default") === enforce);
	if (!transformers.length) return;
	const skipMap = /* @__PURE__ */ new Map();
	let code = original;
	let s = new MagicString(transformSkipCode(code, skipMap, SKIP_COMMENT_RE, "@unocss-skip-placeholder-"));
	const maps = [];
	for (const t of transformers) {
		if (t.idFilter) {
			if (!t.idFilter(id)) continue;
		} else if (!ctx.filter(code, id)) continue;
		await t.transform(s, id, ctx);
		if (s.hasChanged()) {
			code = restoreSkipCode(s.toString(), skipMap);
			maps.push(s.generateMap({
				hires: true,
				source: id
			}));
			s = new MagicString(code);
		}
	}
	if (code !== original) return {
		code,
		map: remapping(maps, (_, ctx$1) => {
			ctx$1.content = code;
			return null;
		})
	};
}

//#endregion
//#region package.json
var version = "66.5.12";

//#endregion
//#region src/config.ts
const defaultConfig = {
	envMode: "build",
	presets: [presetUno()]
};

//#endregion
//#region src/errors.ts
var PrettyError = class extends Error {
	constructor(message) {
		super(message);
		this.name = this.constructor.name;
		if (typeof Error.captureStackTrace === "function") Error.captureStackTrace(this, this.constructor);
		else this.stack = new Error(message).stack;
	}
};
function handleError(error) {
	if (error instanceof PrettyError) consola.error(error.message);
	process.exitCode = 1;
}

//#endregion
//#region src/watcher.ts
let watcher;
async function getWatcher(options) {
	if (watcher && !options) return watcher;
	const { watch } = await import("chokidar");
	const ignored = ["**/{.git,node_modules}/**"];
	const cwd = (options === null || options === void 0 ? void 0 : options.cwd) || process.cwd();
	const newWatcher = watch((options === null || options === void 0 ? void 0 : options.patterns).map((p) => {
		const abs = resolve(cwd, p);
		if (abs.endsWith("/**/*")) return abs.slice(0, -5);
		return abs;
	}), {
		ignoreInitial: false,
		ignorePermissionErrors: true,
		ignored,
		usePolling: true,
		interval: 100
	});
	watcher = newWatcher;
	return newWatcher;
}

//#endregion
//#region src/index.ts
const name = "unocss";
async function resolveOptions(options) {
	var _options$patterns;
	if (!((_options$patterns = options.patterns) === null || _options$patterns === void 0 ? void 0 : _options$patterns.length)) throw new PrettyError(`No glob patterns, try ${cyan(`${name} <path/to/**/*>`)}`);
	return options;
}
async function build(_options) {
	const fileCache = /* @__PURE__ */ new Map();
	const cwd = _options.cwd || process.cwd();
	const options = await resolveOptions(_options);
	async function loadConfig$1() {
		const ctx$1 = createContext(options.config, defaultConfig);
		return {
			ctx: ctx$1,
			configSources: (await ctx$1.updateRoot(cwd)).sources.map((i) => normalize(i))
		};
	}
	const { ctx, configSources } = await loadConfig$1();
	const files = await glob(options.patterns, {
		cwd,
		absolute: true,
		expandDirectories: false
	});
	await Promise.all(files.map(async (file) => {
		fileCache.set(file, await promises.readFile(file, "utf8"));
	}));
	if (options.stdout && options.outFile) {
		consola.fatal(`Cannot use --stdout and --out-file at the same time`);
		return;
	}
	consola.log(green(`${name} v${version}`));
	if (options.watch) consola.start("UnoCSS in watch mode...");
	else consola.start("UnoCSS for production...");
	const debouncedBuild = debounce(async () => {
		generate(options).catch(handleError);
	}, 100);
	const startWatcher = async () => {
		if (!options.watch) return;
		const { patterns } = options;
		const watcher$1 = await getWatcher(options);
		if (configSources.length) watcher$1.add(configSources);
		watcher$1.on("all", async (type, file) => {
			const absolutePath = resolve(cwd, file);
			if (type === "addDir" || type === "unlinkDir") return;
			if (configSources.includes(absolutePath)) {
				await ctx.reloadConfig();
				if (configSources.length) watcher$1.add(configSources);
				consola.info(`${cyan(basename(file))} changed, setting new config`);
			} else {
				consola.log(`${green(type)} ${dim(file)}`);
				if (type.startsWith("unlink")) fileCache.delete(absolutePath);
				else fileCache.set(absolutePath, await promises.readFile(absolutePath, "utf8"));
			}
			debouncedBuild();
		});
		consola.info(`Watching for changes in ${toArray(patterns).map((i) => cyan(i)).join(", ")}`);
	};
	await generate(options);
	await startWatcher().catch(handleError);
	function transformFiles(sources, enforce = "default") {
		return Promise.all(sources.map(({ id, code, transformedCode }) => new Promise((resolve$1) => {
			applyTransformers(ctx, code, id, enforce).then((transformsRes) => {
				resolve$1({
					id,
					code,
					transformedCode: (transformsRes === null || transformsRes === void 0 ? void 0 : transformsRes.code) || transformedCode
				});
			});
		})));
	}
	async function generate(options$1) {
		const afterPostTrans = await transformFiles(await transformFiles(await transformFiles(Array.from(fileCache).map(([id, code]) => ({
			id,
			code
		})), "pre")), "post");
		if (options$1.writeTransformed) await Promise.all(afterPostTrans.filter(({ transformedCode }) => !!transformedCode).map(async ({ transformedCode, id }) => {
			if (existsSync(id)) await promises.writeFile(id, transformedCode, "utf-8");
		}));
		const tokens = /* @__PURE__ */ new Set();
		for (const file of afterPostTrans) {
			const { matched: matched$1 } = await ctx.uno.generate((file.transformedCode || file.code).replace(SKIP_COMMENT_RE, ""), {
				preflights: false,
				minify: true,
				id: file.id
			});
			matched$1.forEach((i) => tokens.add(i));
		}
		const { css, matched } = await ctx.uno.generate(tokens, {
			preflights: options$1.preflights,
			minify: options$1.minify
		});
		if (options$1.stdout) {
			process.stdout.write(css);
			return;
		}
		const outFile = resolve(options$1.cwd || process.cwd(), options$1.outFile ?? "uno.css");
		const dir = dirname(outFile);
		if (!existsSync(dir)) await promises.mkdir(dir, { recursive: true });
		await promises.writeFile(outFile, css, "utf-8");
		if (!options$1.watch) consola.success(`${[...matched].length} utilities generated to ${cyan(relative(process.cwd(), outFile))}\n`);
	}
}

//#endregion
export { version as i, resolveOptions as n, handleError as r, build as t };