/*! © 2026 Yahoo, Inc. UDS Tailwind and Purger v0.0.0-development */
const require_runtime = require('../../_virtual/_rolldown/runtime.cjs');
const require_expressions = require('./ast/expressions.cjs');
const require_jsx = require('./ast/jsx.cjs');
let ts_morph = require("ts-morph");

//#region src/purger/optimized/purgeFromCode.ts
/**
* Get component info with all its dependencies (using pre-generated data)
*/
const getComponentWithDeps = (componentName) => {
	const visited = /* @__PURE__ */ new Set();
	const result = [];
	const collect = (name) => {
		if (visited.has(name)) return;
		visited.add(name);
		const info = resolveComponentInfo(name);
		if (!info) return;
		result.push(info);
		info.internalComponents.forEach((depName) => collect(depName));
	};
	collect(componentName);
	return result;
};
/**
* Auto-variants lookup (loaded at module init)
*/
let autoVariantsCache = null;
/**
* Pre-generated component data (loaded at module init)
*/
let componentCache = null;
/**
* Map of normalized component name -> actual component cache key
* Useful when internal components are imported without namespace separators
* (e.g., MenuItemBase vs Menu.ItemBase).
*/
let componentNameLookup = null;
const buildComponentNameLookup = (data) => {
	const lookup = {};
	Object.keys(data).forEach((key) => {
		const normalized = normalizeComponentName(key);
		if (!lookup[normalized]) lookup[normalized] = key;
	});
	return lookup;
};
const resolveComponentInfo = (name) => {
	if (componentCache && componentCache[name]) return componentCache[name];
	const normalized = normalizeComponentName(name);
	const mappedName = componentNameLookup?.[normalized];
	if (mappedName && componentCache) return componentCache[mappedName];
};
const getModuleSpecifierValue = (importDecl) => {
	return importDecl.getModuleSpecifierValue() ?? importDecl.getModuleSpecifier().getText().replace(/^['"]|['"]$/g, "");
};
const isTypeOnlyNamedImport = (importDecl, importName) => {
	if (importDecl.isTypeOnly()) return true;
	return importDecl.getNamedImports().find((namedImport) => namedImport.getName() === importName)?.isTypeOnly() ?? false;
};
const isUdsComponentModule = (moduleSpecifier) => {
	const cleaned = moduleSpecifier.replace(/^['"]|['"]$/g, "");
	return cleaned === "@yahoo/uds" || cleaned.startsWith("@yahoo/uds/");
};
/**
* Normalize component name to match autoVariants keys (lower camel, no punctuation).
*/
const normalizeComponentName = (name) => {
	const cleaned = name.replace(/\W/g, "");
	return cleaned.charAt(0).toLowerCase() + cleaned.slice(1);
};
/**
* Fallback: infer prop -> variant key mapping from autoVariants when the
* generated component data misses it (e.g., helpers like buildAvatarRootClasses).
*/
const getAutoVariantKeysForProp = (componentName, propName) => {
	if (!autoVariantsCache) return [];
	const segments = componentName.match(/[A-Z][a-z0-9]*/g) ?? [];
	const candidates = new Set([normalizeComponentName(componentName)]);
	if (segments.length > 0) Array.from({ length: segments.length }, (_, index) => index + 1).forEach((i) => {
		const partial = segments.slice(0, i).join("");
		candidates.add(normalizeComponentName(partial));
	});
	const propLower = propName.toLowerCase();
	return Object.keys(autoVariantsCache).filter((key) => {
		const keyLower = key.toLowerCase();
		return Array.from(candidates).some((candidate) => keyLower.startsWith(candidate) && keyLower.includes(propLower));
	});
};
const getVariantKeysForProp = (componentInfo, propName) => {
	const keys = new Set(componentInfo.propToVariantKeys?.[propName] ?? []);
	getAutoVariantKeysForProp(componentInfo.name, propName).forEach((inferred) => keys.add(inferred));
	return [...keys];
};
const extractClassNamePrimitives = (sourceFile) => {
	const classes = [];
	sourceFile.getDescendantsOfKind(ts_morph.SyntaxKind.JsxAttribute).forEach((attr) => {
		if (attr.getNameNode().getText() !== "className") return;
		const initializer = attr.getInitializer();
		if (!initializer) return;
		const values = [];
		if (ts_morph.Node.isStringLiteral(initializer)) values.push(initializer.getLiteralText());
		else if (ts_morph.Node.isJsxExpression(initializer)) {
			const expr = initializer.getExpression();
			if (expr) values.push(...require_expressions.extractStringLiterals(expr));
		}
		values.forEach((raw) => {
			classes.push(...raw.split(/\s+/).filter(Boolean));
		});
	});
	sourceFile.getDescendantsOfKind(ts_morph.SyntaxKind.PropertyAssignment).forEach((prop) => {
		if (prop.getName() !== "className") return;
		const initializer = prop.getInitializer();
		if (!initializer) return;
		require_expressions.extractStringLiterals(initializer).forEach((raw) => {
			classes.push(...raw.split(/\s+/).filter(Boolean));
		});
	});
	return classes;
};
const purgeFromCodeOptimized = async (code, options) => {
	const { variants, autoVariants, componentData } = options;
	if (!autoVariantsCache) autoVariantsCache = autoVariants;
	if (!componentCache) {
		componentCache = componentData;
		componentNameLookup = buildComponentNameLookup(componentData);
	}
	const startTime = performance.now();
	const sourceFile = new ts_morph.Project({ useInMemoryFileSystem: true }).createSourceFile(options.filePath ?? "input.tsx", code, { overwrite: true });
	const stats = {
		filesScanned: 1,
		timeMs: 0,
		classesGenerated: 0,
		spreadsTraced: 0,
		expressionsResolved: 0
	};
	const imports = [];
	sourceFile.getImportDeclarations().forEach((importDecl) => {
		if (isUdsComponentModule(getModuleSpecifierValue(importDecl))) importDecl.getNamedImports().forEach((namedImport) => {
			if (!namedImport.isTypeOnly() && !importDecl.isTypeOnly()) imports.push(namedImport.getName());
		});
	});
	const componentProps = /* @__PURE__ */ new Map();
	const referencedComponents = /* @__PURE__ */ new Set();
	const getStylesProps = extractGetStylesCalls(sourceFile, stats, variants);
	imports.forEach((imp) => {
		findComponentReferences(sourceFile, imp).forEach((reference) => {
			const componentName = reference.getTagNameNode().getText() || imp;
			referencedComponents.add(componentName);
			const propsMap = componentProps.get(componentName) ?? /* @__PURE__ */ new Map();
			extractPropsFromReference(reference, stats, sourceFile).forEach(([propName, values]) => {
				if (values.length > 0) {
					const existing = propsMap.get(propName) ?? /* @__PURE__ */ new Set();
					values.forEach((val) => existing.add(val));
					propsMap.set(propName, existing);
				}
			});
			componentProps.set(componentName, propsMap);
		});
		if (!componentProps.has(imp)) componentProps.set(imp, /* @__PURE__ */ new Map());
	});
	const allComponents = [];
	const seenComponents = /* @__PURE__ */ new Set();
	new Set([...imports, ...referencedComponents]).forEach((componentName) => {
		getComponentWithDeps(componentName).forEach((comp) => {
			if (!seenComponents.has(comp.name)) {
				seenComponents.add(comp.name);
				allComponents.push(comp);
			}
		});
	});
	const safelist = [];
	[...getStylesProps.entries()].forEach(([propName, values]) => {
		const variantGroup = variants[propName];
		if (variantGroup) values.forEach((value) => {
			const cls = variantGroup[value];
			if (cls) safelist.push(cls.replaceAll("\\", ""));
		});
	});
	allComponents.forEach((componentInfo) => {
		const userProps = componentProps.get(componentInfo.name) ?? /* @__PURE__ */ new Map();
		Object.entries(componentInfo.defaultProps).forEach(([propName, propValue]) => {
			if (userProps.has(propName)) return;
			const variantGroup = variants[propName];
			if (variantGroup) {
				const cls = variantGroup[propValue];
				if (cls) safelist.push(cls.replaceAll("\\", ""));
			}
			const variantKeys = getVariantKeysForProp(componentInfo, propName);
			if (variantKeys.length > 0) variantKeys.forEach((variantKey) => {
				const mappedVariantGroup = variants[variantKey] ?? autoVariantsCache[variantKey];
				if (mappedVariantGroup) {
					const cls = mappedVariantGroup[propValue];
					if (cls) safelist.push(cls.replaceAll("\\", ""));
				}
			});
		});
		Object.entries(componentInfo.getStylesLiterals).forEach(([propName, propValue]) => {
			const variantGroup = variants[propName.replace(/:\d+$/, "")];
			if (variantGroup) {
				const cls = variantGroup[propValue];
				if (cls) safelist.push(cls.replaceAll("\\", ""));
			}
		});
		if (componentInfo.cxLiterals) componentInfo.cxLiterals.forEach((cls) => safelist.push(cls));
		if (componentInfo.propToVariantKeys) {
			const componentDefaults = options.variantDefaults?.[componentInfo.name] ?? {};
			Object.keys(componentInfo.propToVariantKeys).forEach((propName) => {
				if (userProps.has(propName)) return;
				const defaultValue = componentDefaults[propName];
				getVariantKeysForProp(componentInfo, propName).forEach((variantKey) => {
					const variantGroup = autoVariantsCache[variantKey];
					if (variantGroup) {
						if (variantGroup["default"]) safelist.push(variantGroup["default"]);
						if (defaultValue && variantGroup[defaultValue]) safelist.push(variantGroup[defaultValue]);
					}
				});
			});
		}
		Object.entries(componentInfo.internalComponentProps).forEach(([_internalCompName, propsRecord]) => {
			Object.entries(propsRecord).forEach(([propName, propValues]) => {
				if (propName === "className") {
					propValues.forEach((propValue) => {
						propValue.split(/\s+/).filter(Boolean).forEach((cls) => safelist.push(cls));
					});
					return;
				}
				const variantGroup = variants[propName];
				if (variantGroup) propValues.forEach((propValue) => {
					const cls = variantGroup[propValue];
					if (cls) safelist.push(cls.replaceAll("\\", ""));
				});
			});
		});
		[...userProps.entries()].forEach(([propName, usedValues]) => {
			if (propName === "className") {
				[...usedValues].forEach((value) => {
					value.split(/\s+/).filter(Boolean).forEach((cls) => safelist.push(cls));
				});
				return;
			}
			const variantGroup = variants[propName];
			if (variantGroup) [...usedValues].forEach((value) => {
				const cls = variantGroup[value];
				if (cls) safelist.push(cls.replaceAll("\\", ""));
			});
			[componentInfo, ...getComponentWithDeps(componentInfo.name).slice(1)].forEach((comp) => {
				const variantKeys = getVariantKeysForProp(comp, propName);
				if (variantKeys.length > 0) variantKeys.forEach((variantKey) => {
					const mappedVariantGroup = variants[variantKey];
					if (mappedVariantGroup) [...usedValues].forEach((value) => {
						const cls = mappedVariantGroup[value];
						if (cls) safelist.push(cls.replaceAll("\\", ""));
					});
				});
			});
		});
	});
	if (options.includeAllClassNamePrimitives) safelist.push(...extractClassNamePrimitives(sourceFile));
	const finalSafelist = [...new Set(safelist)];
	stats.timeMs = Math.round(performance.now() - startTime);
	stats.classesGenerated = finalSafelist.length;
	return {
		safelist: finalSafelist,
		imports,
		components: [...seenComponents],
		stats
	};
};
/**
* Find JSX references for a component in the source file
*/
const findComponentReferences = (sourceFile, componentName) => {
	const references = [];
	const seenTags = /* @__PURE__ */ new Set();
	const collectMatchingTags = (localName) => {
		sourceFile.getDescendants().filter((node) => ts_morph.Node.isJsxOpeningElement(node) || ts_morph.Node.isJsxSelfClosingElement(node)).forEach((node) => {
			const tagName = node.getTagNameNode().getText();
			if (tagName === localName || tagName.startsWith(`${localName}.`)) {
				const key = `${tagName}:${node.getStart()}`;
				if (!seenTags.has(key)) {
					seenTags.add(key);
					references.push(node);
				}
			}
		});
	};
	sourceFile.getImportDeclarations().forEach((importDecl) => {
		if (!isUdsComponentModule(getModuleSpecifierValue(importDecl))) return;
		importDecl.getNamedImports().forEach((namedImport) => {
			if (namedImport.getName() !== componentName || isTypeOnlyNamedImport(importDecl, componentName)) return;
			const localName = namedImport.getAliasNode()?.getText() ?? componentName;
			require_jsx.findJsxReferences(namedImport.getFirstDescendantByKindOrThrow(ts_morph.ts.SyntaxKind.Identifier)).forEach((reference) => {
				const key = `${reference.getTagNameNode().getText()}:${reference.getStart()}`;
				if (!seenTags.has(key)) {
					seenTags.add(key);
					references.push(reference);
				}
			});
			collectMatchingTags(localName);
		});
	});
	return references;
};
/**
* Extract props from a JSX reference.
*/
const extractPropsFromReference = (reference, stats, sourceFile) => {
	const props = [];
	reference.getAttributes().forEach((attr) => {
		if (attr.asKind(ts_morph.SyntaxKind.JsxAttribute)) {
			const jsxAttr = attr.asKindOrThrow(ts_morph.SyntaxKind.JsxAttribute);
			const propName = jsxAttr.getNameNode().getText();
			const values = [];
			const initializer = jsxAttr.getInitializer();
			if (initializer && ts_morph.Node.isStringLiteral(initializer)) {
				values.push(initializer.getLiteralText());
				stats.expressionsResolved++;
			} else if (initializer && initializer.asKind(ts_morph.SyntaxKind.JsxExpression)) {
				const expression = initializer.asKindOrThrow(ts_morph.SyntaxKind.JsxExpression).getExpression();
				if (expression) {
					const resolved = require_expressions.extractStringLiterals(expression);
					values.push(...resolved);
					if (resolved.length > 0) stats.expressionsResolved++;
				}
			}
			props.push([propName, values]);
		}
		if (attr.asKind(ts_morph.SyntaxKind.JsxSpreadAttribute)) {
			stats.spreadsTraced++;
			traceSpreadInFile(attr.asKindOrThrow(ts_morph.SyntaxKind.JsxSpreadAttribute).getExpression().getText(), sourceFile).forEach(([propName, values]) => {
				if (values.length > 0) props.push([propName, values]);
			});
		}
	});
	return props;
};
/**
* Trace spread props to their source within the same file.
*/
const traceSpreadInFile = (spreadName, sourceFile) => {
	const props = [];
	const varDecl = sourceFile.getVariableDeclaration(spreadName);
	if (!varDecl) return props;
	const initializer = varDecl.getInitializer();
	if (!initializer) return props;
	const objLiteral = initializer.asKind(ts_morph.SyntaxKind.ObjectLiteralExpression) ? initializer.asKindOrThrow(ts_morph.SyntaxKind.ObjectLiteralExpression) : initializer.asKind(ts_morph.SyntaxKind.AsExpression) ? initializer.asKindOrThrow(ts_morph.SyntaxKind.AsExpression).getExpression().asKind(ts_morph.SyntaxKind.ObjectLiteralExpression) ? initializer.asKindOrThrow(ts_morph.SyntaxKind.AsExpression).getExpression().asKindOrThrow(ts_morph.SyntaxKind.ObjectLiteralExpression) : null : null;
	if (!objLiteral) return props;
	objLiteral.getProperties().forEach((prop) => {
		if (prop.asKind(ts_morph.SyntaxKind.PropertyAssignment)) {
			const propAssign = prop.asKindOrThrow(ts_morph.SyntaxKind.PropertyAssignment);
			const propName = propAssign.getName();
			const propInit = propAssign.getInitializer();
			if (propInit) {
				const values = require_expressions.extractStringLiterals(propInit);
				if (values.length > 0) props.push([propName, values]);
			}
		}
	});
	return props;
};
/**
* Extract props from getStyles() calls in user code.
* This handles cases like:
*   const styles = getStyles({ backgroundColor: 'brand', spacing: '4' });
*/
const extractGetStylesCalls = (sourceFile, stats, variants) => {
	const props = /* @__PURE__ */ new Map();
	const VALID_VARIANTS = new Set(Object.keys(variants));
	sourceFile.getDescendantsOfKind(ts_morph.SyntaxKind.CallExpression).forEach((call) => {
		if (call.getExpression().getText() !== "getStyles") return;
		const args = call.getArguments();
		if (args.length === 0) return;
		const firstArg = args[0];
		if (!firstArg.asKind(ts_morph.SyntaxKind.ObjectLiteralExpression)) return;
		firstArg.asKindOrThrow(ts_morph.SyntaxKind.ObjectLiteralExpression).getProperties().forEach((prop) => {
			if (prop.asKind(ts_morph.SyntaxKind.PropertyAssignment)) {
				const propAssign = prop.asKindOrThrow(ts_morph.SyntaxKind.PropertyAssignment);
				const propName = propAssign.getName();
				const propInit = propAssign.getInitializer();
				if (propInit && VALID_VARIANTS.has(propName)) {
					const values = require_expressions.extractStringLiterals(propInit);
					if (values.length > 0) {
						const existing = props.get(propName) ?? /* @__PURE__ */ new Set();
						values.forEach((v) => existing.add(v));
						props.set(propName, existing);
						stats.expressionsResolved++;
					}
				}
			} else if (prop.asKind(ts_morph.SyntaxKind.ShorthandPropertyAssignment)) {
				const shorthand = prop.asKindOrThrow(ts_morph.SyntaxKind.ShorthandPropertyAssignment);
				const propName = shorthand.getName();
				if (VALID_VARIANTS.has(propName)) {
					const values = require_expressions.extractStringLiterals(shorthand.getNameNode());
					if (values.length > 0) {
						const existing = props.get(propName) ?? /* @__PURE__ */ new Set();
						values.forEach((v) => existing.add(v));
						props.set(propName, existing);
						stats.expressionsResolved++;
					}
				}
			}
		});
	});
	return props;
};

//#endregion
exports.purgeFromCodeOptimized = purgeFromCodeOptimized;