/** @license MIT | @cube-dev/ui-kit v0.0.0-canary-a795c5b | Cube Dev Team */
import { isDevEnv } from "./is-dev-env.js";
import { getGlobalRecipes } from "../config.js";
import { isSelector } from "../pipeline/index.js";
import { mergeStyles } from "./merge-styles.js";

//#region src/tasty/utils/resolve-recipes.ts
/**
* Recipe resolution utility.
*
* Resolves `recipe` style properties by looking up predefined recipe styles
* from global configuration and merging them with the component's own styles.
*
* Resolution order per level (top-level and each sub-element independently):
* base_recipe_1 base_recipe_2 → component styles → post_recipe_1 post_recipe_2
*
* The `|` separator splits base recipes (before component styles)
* from post recipes (after component styles). All merges use mergeStyles
* semantics: primitives and state maps with '' key fully replace;
* state maps without '' key extend the existing value.
*
* Returns the same object reference if no recipes are present (zero overhead).
*/
const devMode = isDevEnv();
/**
* Parse a recipe string into base and post recipe name groups.
*
* Syntax: `'base1 base2 | post1 post2'`
* - Names are space-separated within each group
* - `|` separates base (before component) from post (after component) groups
* - `|` is optional; if absent, all names are base
*
* Returns `{ base: null, post: null }` if the string is empty or invalid.
*/
function parseRecipeNames(value) {
	const empty = {
		base: null,
		post: null
	};
	if (typeof value !== "string") return empty;
	const trimmed = value.trim();
	if (trimmed === "") return empty;
	const pipeIndex = trimmed.indexOf("|");
	if (pipeIndex === -1) return {
		base: splitNames(trimmed),
		post: null
	};
	const basePart = trimmed.slice(0, pipeIndex);
	const postPart = trimmed.slice(pipeIndex + 1);
	return {
		base: splitNames(basePart),
		post: splitNames(postPart)
	};
}
function splitNames(s) {
	const names = s.split(/\s+/).filter(Boolean);
	return names.length > 0 ? names : null;
}
/**
* Collect merged styles for a list of recipe names.
* Each recipe is flat-spread on top of the previous.
*/
function collectRecipeStyles(names, recipes) {
	let merged = {};
	for (const name of names) {
		const recipeStyles = recipes[name];
		if (!recipeStyles) {
			if (devMode) console.warn(`[Tasty] Recipe "${name}" not found. Make sure it is defined in configure({ recipes: { ... } }).`);
			continue;
		}
		merged = {
			...merged,
			...recipeStyles
		};
	}
	return merged;
}
/**
* Resolve recipe references in a flat styles object (no sub-elements).
* Returns null if no `recipe` key is present.
*
* Resolution: base recipes → component styles → post recipes (all via mergeStyles)
*/
function resolveRecipesForLevel(styles, recipes) {
	if (!("recipe" in styles)) return null;
	const { base, post } = parseRecipeNames(styles.recipe);
	const { recipe: _recipe, ...allRest } = styles;
	const flatStyles = {};
	const selectorStyles = {};
	for (const key of Object.keys(allRest)) if (isSelector(key)) selectorStyles[key] = allRest[key];
	else flatStyles[key] = allRest[key];
	if (!base && !post) return allRest;
	let result;
	if (base) result = mergeStyles(collectRecipeStyles(base, recipes), flatStyles);
	else result = { ...flatStyles };
	if (post) {
		const postStyles = collectRecipeStyles(post, recipes);
		result = mergeStyles(result, postStyles);
	}
	for (const key of Object.keys(selectorStyles)) result[key] = selectorStyles[key];
	return result;
}
/**
* Resolve all `recipe` style properties in a styles object.
*
* Handles both top-level and sub-element recipe references.
* Returns the same object reference if no recipes are present anywhere
* (zero overhead for the common case).
*
* @param styles - The styles object potentially containing `recipe` keys
* @returns Resolved styles with recipe values merged in, or the original object if unchanged
*/
function resolveRecipes(styles) {
	const recipes = getGlobalRecipes();
	if (!recipes) return styles;
	let changed = false;
	let result = {};
	const topResolved = resolveRecipesForLevel(styles, recipes);
	if (topResolved) {
		changed = true;
		result = topResolved;
	} else result = styles;
	const keys = Object.keys(result);
	for (const key of keys) {
		if (!isSelector(key)) continue;
		const subStyles = result[key];
		if (!subStyles || typeof subStyles !== "object" || Array.isArray(subStyles)) continue;
		const subRecord = subStyles;
		if (!("recipe" in subRecord)) continue;
		const subResolved = resolveRecipesForLevel(subRecord, recipes);
		if (subResolved) {
			if (!changed) {
				changed = true;
				result = { ...styles };
			}
			result[key] = subResolved;
		}
	}
	return changed ? result : styles;
}

//#endregion
export { resolveRecipes };
//# sourceMappingURL=resolve-recipes.js.map