/** @license MIT | @cube-dev/ui-kit v0.0.0-canary-b859c78 | Cube Dev Team */
import { renderStyles } from "./pipeline/index.js";
import { categorizeStyleKeys } from "./chunks/definitions.js";
import { generateChunkCacheKey } from "./chunks/cacheKey.js";
import { renderStylesForChunk } from "./chunks/renderChunk.js";
import { extractAnimationNamesFromStyles, extractLocalKeyframes, filterUsedKeyframes, hasLocalKeyframes, mergeKeyframes } from "./keyframes/index.js";
import { createHash } from "crypto";

//#region src/tasty/zero/extractor.ts
/**
* Generate a deterministic className from a cache key using content hash.
* This ensures the same styles always produce the same className,
* regardless of build order or incremental compilation.
*/
function generateClassName(cacheKey) {
	return `ts${createHash("md5").update(cacheKey).digest("hex").slice(0, 6)}`;
}
/**
* Extract styles using chunking (for className mode).
* Returns multiple classes, one per chunk.
*/
function extractStylesWithChunks(styles) {
	const chunks = [];
	const chunkMap = categorizeStyleKeys(styles);
	for (const [chunkName, chunkStyleKeys] of chunkMap) {
		if (chunkStyleKeys.length === 0) continue;
		const cacheKey = generateChunkCacheKey(styles, chunkName, chunkStyleKeys);
		const renderResult = renderStylesForChunk(styles, chunkName, chunkStyleKeys);
		if (renderResult.rules.length === 0) continue;
		const className = generateClassName(cacheKey);
		const selector = `.${className}.${className}`;
		const css = formatRulesToCSS(renderResult.rules, selector);
		chunks.push({
			className,
			css
		});
	}
	return chunks;
}
/**
* Extract styles for a specific selector (for global/selector mode).
* Returns a single CSS block.
*/
function extractStylesForSelector(selector, styles) {
	return {
		selector,
		css: formatRulesDirectly(renderStyles(styles, selector))
	};
}
/**
* Format StyleResult[] to CSS string.
* Prefixes each rule's selector with the base selector.
* Used for chunked styles where rules have relative selectors.
*/
function formatRulesToCSS(rules, baseSelector) {
	return rules.map((rule) => {
		let css = `${(Array.isArray(rule.selector) ? rule.selector : rule.selector ? rule.selector.split("|||") : [""]).map((part) => {
			let selector;
			if (!part) selector = baseSelector;
			else if (part.startsWith(":") || part.startsWith("[")) selector = `${baseSelector}${part}`;
			else if (part.startsWith(">") || part.startsWith("+") || part.startsWith("~")) selector = `${baseSelector}${part}`;
			else selector = `${baseSelector}${part}`;
			if (rule.rootPrefix) selector = `${rule.rootPrefix} ${selector}`;
			return selector;
		}).join(", ")} { ${rule.declarations} }`;
		if (rule.atRules && rule.atRules.length > 0) for (const atRule of [...rule.atRules].reverse()) css = `${atRule} {\n  ${css}\n}`;
		return css;
	}).join("\n\n");
}
/**
* Format StyleResult[] to CSS string directly without prefixing.
* Used for global styles where rules already have the full selector.
*/
function formatRulesDirectly(rules) {
	return rules.map((rule) => {
		let css = `${rule.rootPrefix ? `${rule.rootPrefix} ${rule.selector}` : rule.selector} { ${rule.declarations} }`;
		if (rule.atRules && rule.atRules.length > 0) for (const atRule of [...rule.atRules].reverse()) css = `${atRule} {\n  ${css}\n}`;
		return css;
	}).join("\n\n");
}
/**
* Generate a deterministic keyframes name from content hash.
* This ensures the same keyframes content always produces the same name,
* enabling automatic deduplication across elements and files.
*/
function generateKeyframesName(steps) {
	const content = JSON.stringify(steps);
	return `kf${createHash("md5").update(content).digest("hex").slice(0, 6)}`;
}
/**
* Extract keyframes that are used in styles.
* Merges local @keyframes with global keyframes, filters to only used ones.
* Generates hash-based names from content for automatic deduplication.
*
* @param styles - The styles object (may contain @keyframes and animation properties)
* @param globalKeyframes - Optional global keyframes from config
* @returns Keyframes to inject and name mapping for replacement
*/
function extractKeyframesFromStyles(styles, globalKeyframes) {
	const emptyResult = {
		keyframes: [],
		nameMap: /* @__PURE__ */ new Map()
	};
	const usedNames = extractAnimationNamesFromStyles(styles);
	if (usedNames.size === 0) return emptyResult;
	const usedKeyframes = filterUsedKeyframes(mergeKeyframes(hasLocalKeyframes(styles) ? extractLocalKeyframes(styles) : null, globalKeyframes ?? null), usedNames);
	if (!usedKeyframes) return emptyResult;
	const seenHashes = /* @__PURE__ */ new Set();
	const nameMap = /* @__PURE__ */ new Map();
	const keyframesToEmit = [];
	for (const [originalName, steps] of Object.entries(usedKeyframes)) {
		const hashedName = generateKeyframesName(steps);
		nameMap.set(originalName, hashedName);
		if (!seenHashes.has(hashedName)) {
			seenHashes.add(hashedName);
			const css = keyframesToCSS(hashedName, steps);
			keyframesToEmit.push({
				name: hashedName,
				css
			});
		}
	}
	return {
		keyframes: keyframesToEmit,
		nameMap
	};
}
/**
* Convert keyframes steps to CSS string.
*/
function keyframesToCSS(name, steps) {
	const stepRules = [];
	for (const [key, value] of Object.entries(steps)) if (typeof value === "string") stepRules.push(`${key} { ${value.trim()} }`);
	else if (value && typeof value === "object") {
		const declarations = Object.entries(value).map(([prop, val]) => {
			return `${camelToKebab(prop)}: ${val}`;
		}).join("; ");
		stepRules.push(`${key} { ${declarations} }`);
	}
	return `@keyframes ${name} { ${stepRules.join(" ")} }`;
}
/**
* Convert camelCase to kebab-case.
*/
function camelToKebab(str) {
	return str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
}

//#endregion
export { extractKeyframesFromStyles, extractStylesForSelector, extractStylesWithChunks };
//# sourceMappingURL=extractor.js.map