/*! © 2026 Yahoo, Inc. UDS Tailwind and Purger v0.0.0-development */
import { red } from "../cli/dist/lib/colors.js";
import { print } from "../cli/dist/lib/print.js";
import { defaultTokensConfig } from "../config/dist/index.js";
import { tailwindPlugin } from "../plugin.js";
import { autoVariants } from "../automated-config/dist/generated/autoVariants.js";
import { findReferencesAsJsxElements, getReactFunctionDeclaration, getUsedPropsInReference } from "./tsMorph.js";
import { SyntaxKind } from "ts-morph";
import postcss from "postcss";
import tailwindcss from "tailwindcss";

//#region src/utils/generatePurgeCSSData.ts
const NO_FILE = "noFile";
/**
* Returns a list of exported Components from UDS
* both stable and experimental
*/
const getExportedComponents = (UDS, UDS_EXPERIMENTAL) => {
	const udsStableExports = Object.keys(UDS);
	const udsExperimentalExports = Object.keys(UDS_EXPERIMENTAL);
	return udsStableExports.concat(udsExperimentalExports).filter((key) => {
		const regexStartsWithCapitalLetter = /* @__PURE__ */ new RegExp("^[A-Z].[^_]");
		const hasUnderscore = key.includes("_");
		const startsWithCapitalLetter = regexStartsWithCapitalLetter.test(key);
		return !hasUnderscore && startsWithCapitalLetter;
	});
};
/**
* Some UDS components are built using other UDS components,
* we need to know those dependencies so generate the correct
*/
const getComponentsDependencies = (project, componentsList, exportsToFilePath) => {
	const componentsListSet = new Set(componentsList);
	const componentUDSDependencies = {};
	componentsList.forEach((component) => {
		componentUDSDependencies[component] = getComponentUdsDependencies(project, componentsListSet, component, exportsToFilePath);
	});
	return componentUDSDependencies;
};
/**
* We need to make sure that components from UDS that use other components
* from UDS also gets included
*/
const getComponentUdsDependencies = (project, componentsList, componentName, exportsToFilePath) => {
	return project.getSourceFileOrThrow(exportsToFilePath[componentName]).getImportDeclarations().map((declaration) => {
		return declaration.getNamedImports().map((namedImport) => namedImport.getName());
	}).flat().filter((namedImport) => componentsList.has(namedImport));
};
const getComponentsProps = (project, list, variants, variantsList, exportsToFilePath) => {
	const map = {};
	list.forEach((componentName) => {
		map[componentName] = getInitializedAndReferencedProps(project, componentName, variants, variantsList, exportsToFilePath);
	});
	return map;
};
/**
* Converts the variants object used in CVA to
*/
const convertVariantsIntoTailwindClass = (variants) => {
	return Object.keys(variants);
};
/**
* Get the params with default values,
* required and the ones used in references
*/
const getInitializedAndReferencedProps = (project, componentName, variants, variantsList, exportsToFilePath) => {
	const sourceFile = project.getSourceFileOrThrow(exportsToFilePath[componentName] ?? NO_FILE);
	const functionDeclarations = sourceFile.getFunctions();
	const variableDeclarations = sourceFile.getVariableDeclarations();
	const node = [...functionDeclarations, ...variableDeclarations].filter((declaration) => declaration.getName() === componentName)[0];
	const functionDeclaration = getReactFunctionDeclaration(node);
	if (!functionDeclaration) print(red(`No function declaration found for ${componentName}`));
	const parameterDeclaration = functionDeclaration?.getParameters();
	if (!parameterDeclaration || parameterDeclaration.length === 0) {
		print(red(`No parameter declaration found for ${componentName}`));
		return [];
	}
	if (!parameterDeclaration[0].getChildrenOfKind(SyntaxKind.ObjectBindingPattern)[0]) return [];
	const references = findReferencesAsJsxElements(node.getFirstDescendantByKindOrThrow(SyntaxKind.Identifier));
	const propsWithDefaultValues = parameterDeclaration[0].getChildrenOfKind(SyntaxKind.ObjectBindingPattern)[0].getElements().filter((el) => !!el.getInitializer()).map((el) => {
		const stringLiteral = el.getDescendantsOfKind(SyntaxKind.StringLiteral)[0];
		const propName = el.getName();
		const values = [];
		if (stringLiteral) values.push(stringLiteral.getLiteralText());
		return [propName, values];
	}).filter(([propName]) => variantsList.includes(propName));
	const propsUsedInReferences = references.map((r) => getUsedPropsInReference(r, variants)).flat().filter(([propName]) => variantsList.includes(propName));
	const mapPropToUsedOptions = /* @__PURE__ */ new Map();
	propsWithDefaultValues.concat(propsUsedInReferences).forEach(([propName, propValues]) => {
		if (propValues.length === 0) propValues = Object.keys(variants[propName]);
		const options = mapPropToUsedOptions.get(propName) ?? /* @__PURE__ */ new Set();
		propValues.forEach((val) => options.add(val));
		mapPropToUsedOptions.set(propName, options);
	});
	return Array.from(mapPropToUsedOptions).map(([propName, options]) => [propName, Array.from(options)]);
};
/**
* Gets the Tailwind CSS classes used in a component
*/
const getTwClassesInComponent = async (componentsList, exportsToFilePath) => {
	const CSS_DATA = `
    @tailwind components;
    @tailwind utilities;
  `;
	const res = {};
	const promises = componentsList.map((component) => {
		return postcss([tailwindcss({
			content: [exportsToFilePath[component]],
			plugins: [tailwindPlugin({ config: defaultTokensConfig })]
		})]).process(CSS_DATA, {
			from: "app.css",
			to: "./dist/app.css"
		});
	});
	(await Promise.all(promises)).forEach((result, i) => {
		const currentComponent = componentsList[i];
		res[currentComponent] = result.root.nodes.map((node) => {
			if (node.selector) return node.selector.replace(".", "");
			return [];
		}).join(" ").replace(/\s+/g, " ");
	});
	return res;
};
/**
* Goes through the list of all exports from UDS (stable and experimental)
* and return a map of each exports and the source file path where its declared
*/
const getExportsToFilePath = (project) => {
	const stableComponentsMainFile = project.getSourceFileOrThrow("./src/components/index.ts");
	const experimentalComponentsMainFile = project.getSourceFileOrThrow("./src/components/experimental/index.ts");
	const exportToFilePath = {};
	for (const [name, declarations] of stableComponentsMainFile.getExportedDeclarations()) exportToFilePath[name] = declarations.map((d) => d.getSourceFile().getFilePath())[0];
	for (const [name, declarations] of experimentalComponentsMainFile.getExportedDeclarations()) exportToFilePath[name] = declarations.map((d) => d.getSourceFile().getFilePath())[0];
	return exportToFilePath;
};
/**
* Adds auto-generated variants to the Tailwind CSS classes of components.
*
* This function extracts component names from auto variants keys, groups class names by component,
* updates component classes using auto-generated variant classes, and propagates base classes to subcomponents.
*
* @param componentToTwClasses - A map of component names to their current Tailwind CSS classes.
* @returns Updated map with auto variants added to the component classes.
*/
const addAutoVariantsToComponentClasses = (componentToTwClasses) => {
	const componentNameRegex = /^([a-z]+)[A-Z]/;
	const componentNameMap = {};
	const componentNameLookup = /* @__PURE__ */ new Map();
	Object.keys(componentToTwClasses).forEach((actualName) => {
		componentNameLookup.set(actualName.toLowerCase(), actualName);
	});
	Object.keys(autoVariants).forEach((key) => {
		const match = key.match(componentNameRegex);
		if (match && match[1]) {
			const extractedName = match[1].charAt(0).toUpperCase() + match[1].slice(1);
			const actualComponentName = componentNameLookup.get(extractedName.toLowerCase()) || extractedName;
			if (!componentNameMap[actualComponentName]) componentNameMap[actualComponentName] = [];
			Object.values(autoVariants[key]).forEach((className) => {
				componentNameMap[actualComponentName].push(className);
			});
		}
	});
	Object.entries(componentNameMap).forEach(([componentName, classes]) => {
		componentToTwClasses[componentName] = `${componentToTwClasses[componentName] || ""} ${classes.join(" ")}`.trim();
	});
	const components = Object.keys(componentNameMap);
	Object.keys(componentToTwClasses).forEach((key) => {
		components.forEach((comp) => {
			const compName = comp.charAt(0).toUpperCase() + comp.slice(1);
			if (key.startsWith(compName) && key !== compName) {
				const baseClasses = componentToTwClasses[compName] || "";
				if (baseClasses) componentToTwClasses[key] = `${componentToTwClasses[key]} ${baseClasses}`.trim();
			}
		});
	});
	return componentToTwClasses;
};

//#endregion
export { addAutoVariantsToComponentClasses, convertVariantsIntoTailwindClass, getComponentsDependencies, getComponentsProps, getExportedComponents, getExportsToFilePath, getTwClassesInComponent };
//# sourceMappingURL=generatePurgeCSSData.js.map