/*! © 2026 Yahoo, Inc. UDS v0.0.0-development */
import { cyan, green, magenta, red } from "../packages/cli/dist/lib/colors.js";
import { print } from "../packages/cli/dist/lib/print.js";
import { measureAsync } from "./perf.js";
import { purgeFromCodeOptimized } from "../purger/optimized/purgeFromCode.js";
import { formatEntryValue } from "../../../tailwind-internal/dist/utils/entryPoints.js";
import path from "node:path";
import fs from "node:fs";
import { createRequire } from "node:module";
import fg from "fast-glob";
//#region ../css/dist/css/nodeUtils.mjs
/*! © 2026 Yahoo, Inc. UDS CSS v0.0.0-development */
const loadConfigFile = async (configPath) => {
	const absolutePath = path.isAbsolute(configPath) ? configPath : path.join(process.cwd(), configPath);
	if (!fs.existsSync(absolutePath)) return null;
	try {
		const module = await import(absolutePath);
		return module.default ?? module.config ?? module;
	} catch (error) {
		throw new Error(`Failed to load config file: ${absolutePath}\n${error instanceof Error ? error.message : "Unknown error"}`);
	}
};
const scanDirectoryForSafelist = async (dir, colorModes, variants, autoVariants, componentData, variantDefaults, runtimeConfigValues, includeAllClassNamePrimitives = false, pool) => {
	const files = await measureAsync("scan:glob", () => fg("**/*.{js,jsx,mjs,cjs,ts,tsx}", {
		cwd: dir,
		absolute: true,
		ignore: ["**/node_modules/**"]
	}).then((f) => f.sort((left, right) => left.localeCompare(right))));
	const processFile = (filePath) => {
		const code = fs.readFileSync(filePath, "utf-8");
		if (pool) return pool.processFile({
			code,
			filePath,
			colorModes,
			variantDefaults,
			runtimeConfigValues,
			includeAllClassNamePrimitives
		});
		return purgeFromCodeOptimized(code, {
			colorModes,
			variantDefaults,
			runtimeConfigValues,
			variants,
			autoVariants,
			componentData,
			includeAllClassNamePrimitives,
			filePath
		});
	};
	const results = await measureAsync("scan:purge-all-files", () => Promise.all(files.map(processFile)));
	const allClasses = results.flatMap((result) => result.safelist);
	const allComponents = new Set(results.flatMap((result) => result.components));
	const filesWithComponents = results.filter((result) => result.components.length > 0).length;
	return {
		safelist: allClasses,
		components: [...allComponents],
		filesScanned: files.length,
		filesWithComponents,
		filePaths: files
	};
};
const scanFileForSafelist = async (filePath, colorModes, variants, autoVariants, componentData, variantDefaults, runtimeConfigValues, includeAllClassNamePrimitives = false) => {
	const result = await purgeFromCodeOptimized(fs.readFileSync(filePath, "utf-8"), {
		colorModes,
		variantDefaults,
		runtimeConfigValues,
		variants,
		autoVariants,
		componentData,
		includeAllClassNamePrimitives
	});
	return {
		safelist: result.safelist,
		components: result.components,
		filesScanned: 1,
		filesWithComponents: result.components.length > 0 ? 1 : 0,
		filePaths: [filePath]
	};
};
const scanDirectoriesForSafelist = async (dirs, colorModes, variants, autoVariants, componentData, variantDefaults, runtimeConfigValues, includeAllClassNamePrimitives = false, pool) => {
	const results = await Promise.all(dirs.map((dir) => {
		if (fs.existsSync(dir) && fs.statSync(dir).isFile()) return scanFileForSafelist(dir, colorModes, variants, autoVariants, componentData, variantDefaults, runtimeConfigValues, includeAllClassNamePrimitives);
		return scanDirectoryForSafelist(dir, colorModes, variants, autoVariants, componentData, variantDefaults, runtimeConfigValues, includeAllClassNamePrimitives, pool);
	}));
	return {
		safelist: results.flatMap((result) => result.safelist),
		components: [...new Set(results.flatMap((result) => result.components))],
		filesScanned: results.reduce((total, result) => total + result.filesScanned, 0),
		filesWithComponents: results.reduce((total, result) => total + result.filesWithComponents, 0),
		filePaths: results.flatMap((result) => result.filePaths).sort((left, right) => left.localeCompare(right))
	};
};
const findMonorepoRoot = (startDir) => {
	const findUp = (currentDir) => {
		if (fs.existsSync(path.join(currentDir, "packages"))) return currentDir;
		const parentDir = path.dirname(currentDir);
		return parentDir === currentDir ? null : findUp(parentDir);
	};
	return findUp(startDir);
};
const readPackageName = (packageJsonPath) => {
	try {
		const pkgJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
		return typeof pkgJson.name === "string" ? pkgJson.name : null;
	} catch {
		return null;
	}
};
const findPackageRootFromResolvedEntry = (resolvedEntryPath, packageName) => {
	let currentPath = fs.statSync(resolvedEntryPath).isDirectory() ? resolvedEntryPath : path.dirname(resolvedEntryPath);
	while (true) {
		const packageJsonPath = path.join(currentPath, "package.json");
		if (fs.existsSync(packageJsonPath) && readPackageName(packageJsonPath) === packageName) return currentPath;
		const parentPath = path.dirname(currentPath);
		if (parentPath === currentPath) return null;
		currentPath = parentPath;
	}
};
const findPackageRootInNodeModules = (startDir, packageName) => {
	let currentDir = startDir;
	while (true) {
		const packageJsonPath = path.join(currentDir, "node_modules", packageName, "package.json");
		if (fs.existsSync(packageJsonPath)) return path.dirname(packageJsonPath);
		const parentDir = path.dirname(currentDir);
		if (parentDir === currentDir) return null;
		currentDir = parentDir;
	}
};
const resolvePackageRoot = (workspaceDir, packageName) => {
	const requireFromWorkspace = createRequire(path.join(workspaceDir, "package.json"));
	try {
		const resolvedPackageJson = requireFromWorkspace.resolve(path.join(packageName, "package.json"));
		return path.dirname(resolvedPackageJson);
	} catch {
		try {
			const packageRoot = findPackageRootFromResolvedEntry(requireFromWorkspace.resolve(packageName), packageName);
			if (packageRoot) return packageRoot;
		} catch {}
		return findPackageRootInNodeModules(workspaceDir, packageName);
	}
};
const findPackageRootInMonorepo = (monorepoRoot, packageName) => {
	const matchingPath = fg.sync("packages/**/package.json", {
		cwd: monorepoRoot,
		absolute: true,
		ignore: ["**/node_modules/**", "**/dist/**"]
	}).find((pkgJsonPath) => {
		return readPackageName(pkgJsonPath) === packageName;
	});
	return matchingPath ? path.dirname(matchingPath) : null;
};
const findPackageRoot = (packageName) => {
	const workspaceDir = process.cwd();
	const monorepoRoot = findMonorepoRoot(workspaceDir);
	let packageRoot = resolvePackageRoot(workspaceDir, packageName);
	if (!packageRoot && monorepoRoot) packageRoot = findPackageRootInMonorepo(monorepoRoot, packageName);
	return packageRoot;
};
const buildPackageSourceCandidates = (workspaceDir, packageName, packageRoot) => {
	return [
		packageRoot ? path.join(packageRoot, "src") : null,
		packageRoot ? path.join(packageRoot, "lib") : null,
		packageRoot ? path.join(packageRoot, "dist") : null,
		packageRoot,
		path.join(workspaceDir, "node_modules", packageName, "src"),
		path.join(workspaceDir, "node_modules", packageName, "lib"),
		path.join(workspaceDir, "node_modules", packageName, "dist"),
		path.join(workspaceDir, "node_modules", packageName)
	].filter(Boolean);
};
const getFirstExistingPath = (candidates) => candidates.find((candidate) => fs.existsSync(candidate)) ?? null;
const findPackageSourceDir = (packageName) => {
	return getFirstExistingPath(buildPackageSourceCandidates(process.cwd(), packageName, findPackageRoot(packageName)));
};
const getPackageUdsScope = (packageName) => {
	const packageRoot = findPackageRoot(packageName);
	if (!packageRoot) return null;
	const packageJsonPath = path.join(packageRoot, "package.json");
	if (!fs.existsSync(packageJsonPath)) return null;
	try {
		const scope = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")).uds?.scope;
		return typeof scope === "string" && scope.trim().length > 0 ? scope.trim() : null;
	} catch {
		return null;
	}
};
const scaffoldThemeConfig = async (options) => {
	const workspaceDir = process.cwd();
	const outputPath = options.outputPath ?? "uds.theme.ts";
	const absoluteOutputPath = path.isAbsolute(outputPath) ? outputPath : path.join(workspaceDir, outputPath);
	if (fs.existsSync(absoluteOutputPath) && !options.force) {
		print(red(`Error: ${outputPath} already exists. Use --force to overwrite.`));
		process.exitCode = 1;
		return;
	}
	const template = `import { defineTheme } from '@yahoo/uds';

/**
 * UDS Theme Configuration
 * 
 * This file configures CSS generation for your app and shared packages.
 * Run \`uds css\` to generate optimized CSS.
 */
export default defineTheme({
  // Path to your uds.config.ts file
  config: '${options.configPath ?? "./uds.config.ts"}',

  // Entry directory or .tsx file path for scanning your app code
  entry: ${formatEntryValue(options.entry ?? "./src")},

  // Color modes to include (light mode is always in :root)
  colorModes: ['dark'],

  // Packages that inherit your app's theme (merged into main uds.css)
  // inherit: ['@your-org/shared-ui'],

  // Packages that generate separate scoped CSS outputs.
  // Scope class is discovered from each package.json uds.scope.
  // When entry is omitted, the package is scanned the same way as inherit.
  // scoped: {
  //   '@your-org/shared-ui': './packages/shared-ui/uds.config.ts'
  // }
  //
  // Or use the expanded form for custom output paths:
  // scoped: {
  //   '@your-org/shared-ui': {
  //     config: './packages/shared-ui/uds.config.ts',
  //     entry: './src',
  //     // outFile defaults to dist/shared-ui.css
  //     outFile: 'dist/shared-ui.css'
  //   },
  // },

  // CSS generation options (all optional)
  // css: {
  //   safelist: [],
  //   preflight: true,
  //   fontFaceDeclarations: true,
  //   optimization: {
  //     removeUnusedFonts: false,
  //     removeEmptyRules: true,
  //     deduplicateScopedCss: true
  //   }
  // }
});
`;
	fs.writeFileSync(absoluteOutputPath, template);
	print("");
	print(green("✅ Created uds.theme.ts"));
	print("");
	print(`${magenta("Next steps:")}`);
	print(`   1. Review and customize ${cyan(outputPath)}`);
	print(`   2. Run ${cyan("uds css")} to generate CSS`);
	print("");
};
//#endregion
export { findPackageRoot, findPackageSourceDir, getPackageUdsScope, loadConfigFile, scaffoldThemeConfig, scanDirectoriesForSafelist, scanDirectoryForSafelist };
