/** @license MIT | @cube-dev/ui-kit v0.0.0-canary-a795c5b | Cube Dev Team */
import { configure } from "../../config.js";
import { extractKeyframesFromStyles, extractStylesForSelector, extractStylesWithChunks } from "../../extractor.js";
import { CSSWriter } from "../../css-writer.js";
import { mergeStyles } from "../../utils/merge-styles.js";
import { resolveRecipes } from "../../utils/resolve-recipes.js";
import { declare } from "@babel/helper-plugin-utils";
import * as t from "@babel/types";

//#region src/tasty/zero/babel.ts
/**
* Babel plugin for zero-runtime tasty static site generation.
*
* Transforms:
* - `tastyStatic(styles)` → StaticStyle object { className, styles, toString() }
* - `tastyStatic(base, styles)` → StaticStyle object with merged styles
* - `tastyStatic(selector, styles)` → removed entirely
*
* Usage:
* ```javascript
* // babel.config.js
* module.exports = {
*   plugins: [
*     ['@cube-dev/ui-kit/tasty/zero/babel', { output: 'public/tasty.css' }]
*   ]
* };
* ```
*/
var babel_default = declare((api, options) => {
	api.assertVersion(7);
	const outputPath = options.output || "tasty.css";
	const config = options.config || {};
	const devMode = config.devMode ?? false;
	configure(config);
	const cssWriter = new CSSWriter(outputPath, { devMode });
	const globalRegistry = {};
	return {
		name: "tasty-zero",
		pre() {
			this.staticStyleRegistry = {};
			if (devMode && this.filename) this.sourceFile = this.filename.split("/").pop() || this.filename;
		},
		visitor: {
			ImportDeclaration(path) {
				const source = path.node.source.value;
				if (source === "@cube-dev/ui-kit/tasty/static" || source.endsWith("/tasty/static")) path.remove();
			},
			CallExpression(path, state) {
				const callee = path.node.callee;
				if (!t.isIdentifier(callee, { name: "tastyStatic" })) return;
				const args = path.node.arguments;
				if (args.length === 0) throw path.buildCodeFrameError("tastyStatic() requires at least one argument");
				const firstArg = args[0];
				if (t.isStringLiteral(firstArg)) handleSelectorMode(path, args, cssWriter, state.sourceFile, config.keyframes);
				else if (t.isObjectExpression(firstArg)) handleStylesMode(path, args, cssWriter, state, globalRegistry, config.keyframes);
				else if (t.isIdentifier(firstArg)) handleExtensionMode(path, args, cssWriter, state, globalRegistry, config.keyframes);
				else throw path.buildCodeFrameError("tastyStatic() first argument must be an object (styles), identifier (base StaticStyle), or string (selector)");
			},
			VariableDeclarator(path, state) {
				const init = path.node.init;
				const id = path.node.id;
				if (t.isIdentifier(id) && t.isObjectExpression(init) && isStaticStyleObject(init)) {
					const variableName = id.name;
					const styles = extractStylesFromStaticStyleObject(init, path);
					const className = extractClassNameFromStaticStyleObject(init);
					if (styles && className) {
						state.staticStyleRegistry[variableName] = {
							styles,
							className
						};
						globalRegistry[variableName] = {
							styles,
							className
						};
					}
				}
			}
		},
		post() {
			if (cssWriter.size > 0) cssWriter.write();
		}
	};
});
/**
* Check if an object expression looks like a StaticStyle object
*/
function isStaticStyleObject(node) {
	const hasClassName = node.properties.some((p) => t.isObjectProperty(p) && t.isIdentifier(p.key, { name: "className" }));
	const hasStyles = node.properties.some((p) => t.isObjectProperty(p) && t.isIdentifier(p.key, { name: "styles" }));
	return hasClassName && hasStyles;
}
/**
* Extract styles object from a StaticStyle object expression
*/
function extractStylesFromStaticStyleObject(node, path) {
	for (const prop of node.properties) if (t.isObjectProperty(prop) && t.isIdentifier(prop.key, { name: "styles" }) && t.isObjectExpression(prop.value)) return evaluateObjectExpression(prop.value, path);
	return null;
}
/**
* Extract className from a StaticStyle object expression
*/
function extractClassNameFromStaticStyleObject(node) {
	for (const prop of node.properties) if (t.isObjectProperty(prop) && t.isIdentifier(prop.key, { name: "className" }) && t.isStringLiteral(prop.value)) return prop.value.value;
	return null;
}
/**
* Handle tastyStatic(styles) - returns StaticStyle object
*/
function handleStylesMode(path, args, cssWriter, state, globalRegistry, globalKeyframes) {
	const stylesArg = args[0];
	if (!t.isObjectExpression(stylesArg)) throw path.buildCodeFrameError("tastyStatic(styles) argument must be a static object literal");
	const styles = resolveRecipes(evaluateObjectExpression(stylesArg, path));
	const { keyframes, nameMap } = extractKeyframesFromStyles(styles, globalKeyframes);
	for (const kf of keyframes) cssWriter.add(kf.css, kf.css, state.sourceFile);
	const chunks = extractStylesWithChunks(styles);
	for (const chunk of chunks) {
		const css = nameMap.size > 0 ? replaceAnimationNamesInCSS(chunk.css, nameMap) : chunk.css;
		cssWriter.add(chunk.className, css, state.sourceFile);
	}
	const className = chunks.length > 0 ? chunks.map((c) => c.className).join(" ") : "";
	const staticStyleObject = createStaticStyleAST(className, styles);
	path.replaceWith(staticStyleObject);
	registerIfVariableDeclaration(path, className, styles, state, globalRegistry);
}
/**
* Handle tastyStatic(base, styles) - extends base with additional styles
*/
function handleExtensionMode(path, args, cssWriter, state, globalRegistry, globalKeyframes) {
	if (args.length < 2) throw path.buildCodeFrameError("tastyStatic(base, styles) requires two arguments");
	const baseArg = args[0];
	const stylesArg = args[1];
	if (!t.isIdentifier(baseArg)) throw path.buildCodeFrameError("tastyStatic(base, styles) first argument must be an identifier");
	if (!t.isObjectExpression(stylesArg)) throw path.buildCodeFrameError("tastyStatic(base, styles) second argument must be a static object literal");
	const baseName = baseArg.name;
	const baseEntry = state.staticStyleRegistry[baseName] || globalRegistry[baseName];
	if (!baseEntry) throw path.buildCodeFrameError(`Cannot find base StaticStyle '${baseName}'. Make sure it is defined before being extended.`);
	const overrideStyles = evaluateObjectExpression(stylesArg, path);
	const mergedStyles = resolveRecipes(mergeStyles(baseEntry.styles, overrideStyles));
	const { keyframes, nameMap } = extractKeyframesFromStyles(mergedStyles, globalKeyframes);
	for (const kf of keyframes) cssWriter.add(kf.css, kf.css, state.sourceFile);
	const chunks = extractStylesWithChunks(mergedStyles);
	for (const chunk of chunks) {
		const css = nameMap.size > 0 ? replaceAnimationNamesInCSS(chunk.css, nameMap) : chunk.css;
		cssWriter.add(chunk.className, css, state.sourceFile);
	}
	const className = chunks.length > 0 ? chunks.map((c) => c.className).join(" ") : "";
	const staticStyleObject = createStaticStyleAST(className, mergedStyles);
	path.replaceWith(staticStyleObject);
	registerIfVariableDeclaration(path, className, mergedStyles, state, globalRegistry);
}
/**
* Handle tastyStatic(selector, styles) - removes the call entirely
*/
function handleSelectorMode(path, args, cssWriter, sourceFile, globalKeyframes) {
	if (args.length < 2) throw path.buildCodeFrameError("tastyStatic(selector, styles) requires two arguments");
	const selectorArg = args[0];
	const stylesArg = args[1];
	if (!t.isStringLiteral(selectorArg)) throw path.buildCodeFrameError("tastyStatic(selector, styles) first argument must be a string literal");
	if (!t.isObjectExpression(stylesArg)) throw path.buildCodeFrameError("tastyStatic(selector, styles) second argument must be a static object literal");
	const selector = selectorArg.value;
	const styles = resolveRecipes(evaluateObjectExpression(stylesArg, path));
	const { keyframes, nameMap } = extractKeyframesFromStyles(styles, globalKeyframes);
	for (const kf of keyframes) cssWriter.add(kf.css, kf.css, sourceFile);
	const result = extractStylesForSelector(selector, styles);
	const css = nameMap.size > 0 ? replaceAnimationNamesInCSS(result.css, nameMap) : result.css;
	cssWriter.add(selector, css, sourceFile);
	const parent = path.parentPath;
	if (parent && t.isExpressionStatement(parent.node)) parent.remove();
	else path.replaceWith(t.identifier("undefined"));
}
/**
* Create a StaticStyle object AST node
*/
function createStaticStyleAST(className, styles) {
	return t.objectExpression([
		t.objectProperty(t.identifier("className"), t.stringLiteral(className)),
		t.objectProperty(t.identifier("styles"), valueToAST(styles)),
		t.objectMethod("method", t.identifier("toString"), [], t.blockStatement([t.returnStatement(t.memberExpression(t.thisExpression(), t.identifier("className")))]))
	]);
}
/**
* Register a StaticStyle in the registry if it's being assigned to a variable
*/
function registerIfVariableDeclaration(path, className, styles, state, globalRegistry) {
	const parent = path.parentPath;
	if (parent && t.isVariableDeclarator(parent.node)) {
		const id = parent.node.id;
		if (t.isIdentifier(id)) {
			const variableName = id.name;
			state.staticStyleRegistry[variableName] = {
				styles,
				className
			};
			globalRegistry[variableName] = {
				styles,
				className
			};
		}
	}
}
/**
* Convert a JavaScript value to an AST node
*/
function valueToAST(value) {
	if (value === null) return t.nullLiteral();
	if (value === void 0) return t.identifier("undefined");
	if (typeof value === "string") return t.stringLiteral(value);
	if (typeof value === "number") return t.numericLiteral(value);
	if (typeof value === "boolean") return t.booleanLiteral(value);
	if (Array.isArray(value)) return t.arrayExpression(value.map(valueToAST));
	if (typeof value === "object") {
		const properties = Object.entries(value).map(([key, val]) => t.objectProperty(/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ? t.identifier(key) : t.stringLiteral(key), valueToAST(val)));
		return t.objectExpression(properties);
	}
	return t.identifier("undefined");
}
/**
* Evaluate an ObjectExpression to a plain JavaScript object.
* Only supports static values that can be determined at build time.
*/
function evaluateObjectExpression(node, path) {
	const result = {};
	for (const prop of node.properties) {
		if (t.isSpreadElement(prop)) throw path.buildCodeFrameError("Spread elements are not supported in tastyStatic() - styles must be fully static");
		if (!t.isObjectProperty(prop)) throw path.buildCodeFrameError("Only object properties are supported in tastyStatic()");
		let key;
		if (t.isIdentifier(prop.key)) key = prop.key.name;
		else if (t.isStringLiteral(prop.key)) key = prop.key.value;
		else throw path.buildCodeFrameError("Dynamic property keys are not supported in tastyStatic()");
		result[key] = evaluateExpression(prop.value, path);
	}
	return result;
}
/**
* Evaluate an expression to a JavaScript value.
*/
function evaluateExpression(node, path) {
	if (t.isStringLiteral(node)) return node.value;
	if (t.isNumericLiteral(node)) return node.value;
	if (t.isBooleanLiteral(node)) return node.value;
	if (t.isNullLiteral(node)) return null;
	if (t.isIdentifier(node, { name: "undefined" })) return;
	if (t.isArrayExpression(node)) return node.elements.map((el) => {
		if (el === null) return null;
		if (t.isSpreadElement(el)) throw path.buildCodeFrameError("Spread elements are not supported in tastyStatic()");
		return evaluateExpression(el, path);
	});
	if (t.isObjectExpression(node)) return evaluateObjectExpression(node, path);
	if (t.isTemplateLiteral(node)) {
		if (node.expressions.length > 0) throw path.buildCodeFrameError("Template literals with expressions are not supported in tastyStatic()");
		return node.quasis.map((q) => q.value.cooked).join("");
	}
	if (t.isUnaryExpression(node, { operator: "-" })) {
		const arg = evaluateExpression(node.argument, path);
		if (typeof arg === "number") return -arg;
	}
	throw path.buildCodeFrameError(`Dynamic expressions are not supported in tastyStatic() - got ${node.type}. All values must be static literals.`);
}
/**
* Replace animation names in CSS string.
* Wraps the keyframes replaceAnimationNames to work on full CSS blocks.
*/
function replaceAnimationNamesInCSS(css, nameMap) {
	if (nameMap.size === 0) return css;
	return css.replace(/(animation(?:-name)?)\s*:\s*([^;}]+)/gi, (match, prop, value) => {
		let newValue = value;
		for (const [original, replacement] of nameMap) {
			const pattern = new RegExp(`\\b${escapeRegex(original)}\\b`, "g");
			newValue = newValue.replace(pattern, replacement);
		}
		return `${prop}: ${newValue}`;
	});
}
/**
* Escape special regex characters.
*/
function escapeRegex(str) {
	return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}

//#endregion
export { babel_default as default };
//# sourceMappingURL=babel.js.map