/** @license MIT | @cube-dev/ui-kit v0.0.0-canary-af8d194 | Cube Dev Team */
import { CUSTOM_UNITS, getGlobalFuncs, getGlobalParser, normalizeColorTokenValue, setGlobalPredefinedTokens } from "./utils/styles.js";
import { isDevEnv } from "./utils/is-dev-env.js";
import { normalizeHandlerDefinition, registerHandler } from "./styles/predefined.js";
import { StyleInjector } from "./injector/injector.js";
import { setGlobalPredefinedStates } from "./states/index.js";
import { isSelector } from "./pipeline/index.js";

//#region src/tasty/config.ts
/**
* Tasty Configuration Module
*
* Centralizes all tasty configuration, including:
* - Style injector settings (nonce, cleanup thresholds, etc.)
* - Global predefined states for advanced state mapping
* - stylesGenerated flag that locks configuration after first style generation
*
* Configuration must be done BEFORE any styles are generated.
* After the first `inject()` call, configuration is locked and attempts to
* reconfigure will emit a warning and be ignored.
*/
const emittedWarnings = /* @__PURE__ */ new Set();
const devMode = isDevEnv();
/**
* Emit a warning only once
*/
function warnOnce(key, message) {
	if (devMode && !emittedWarnings.has(key)) {
		emittedWarnings.add(key);
		console.warn(message);
	}
}
let stylesGenerated = false;
let currentConfig = null;
let globalKeyframes = null;
let globalProperties = null;
let globalRecipes = null;
const GLOBAL_INJECTOR_KEY = "__TASTY_GLOBAL_INJECTOR__";
/**
* Create default configuration with optional test environment detection
*/
function createDefaultConfig(isTest) {
	return {
		maxRulesPerSheet: 8192,
		unusedStylesThreshold: 500,
		bulkCleanupDelay: 5e3,
		idleCleanup: true,
		forceTextInjection: isTest ?? false,
		devMode: isDevEnv(),
		bulkCleanupBatchRatio: .5,
		unusedStylesMinAgeMs: 1e4
	};
}
/**
* Check if styles have been generated (configuration is locked)
*/
function hasStylesGenerated() {
	return stylesGenerated;
}
/**
* Set global keyframes (called from configure).
* Internal use only.
*/
function setGlobalKeyframes(keyframes) {
	if (stylesGenerated) {
		warnOnce("keyframes-after-styles", "[Tasty] Cannot update keyframes after styles have been generated.\nThe new keyframes will be ignored.");
		return;
	}
	globalKeyframes = keyframes;
}
/**
* Set global properties (called from configure).
* Internal use only.
*/
function setGlobalProperties(properties) {
	if (stylesGenerated) {
		warnOnce("properties-after-styles", "[Tasty] Cannot update properties after styles have been generated.\nThe new properties will be ignored.");
		return;
	}
	globalProperties = properties;
}
/**
* Get global recipes configuration.
* Returns null if no recipes configured (fast path for zero-overhead).
*/
function getGlobalRecipes() {
	return globalRecipes;
}
/**
* Set global recipes (called from configure).
* Internal use only.
*/
function setGlobalRecipes(recipes) {
	if (stylesGenerated) {
		warnOnce("recipes-after-styles", "[Tasty] Cannot update recipes after styles have been generated.\nThe new recipes will be ignored.");
		return;
	}
	if (devMode) for (const [name, recipeStyles] of Object.entries(recipes)) for (const key of Object.keys(recipeStyles)) {
		if (isSelector(key)) warnOnce(`recipe-selector-${name}-${key}`, `[Tasty] Recipe "${name}" contains sub-element key "${key}". Recipes must be flat styles without sub-element keys. Remove the sub-element key from the recipe definition.`);
		if (key === "recipe") warnOnce(`recipe-recursive-${name}`, `[Tasty] Recipe "${name}" contains a "recipe" key. Recipes cannot reference other recipes. Use comma-separated names for composition: recipe: 'base, elevated'.`);
	}
	globalRecipes = recipes;
}
/**
* Configure the Tasty style system.
*
* Must be called BEFORE any styles are generated (before first render that uses tasty).
* After styles are generated, configuration is locked and calls to configure() will
* emit a warning and be ignored.
*
* @example
* ```ts
* import { configure } from '@cube-dev/ui-kit';
*
* // Configure before app renders
* configure({
*   nonce: 'abc123',
*   states: {
*     '@mobile': '@media(w < 768px)',
*     '@dark': '@root(theme=dark)',
*   },
* });
* ```
*/
function configure(config = {}) {
	if (stylesGenerated) {
		warnOnce("configure-after-styles", "[Tasty] Cannot call configure() after styles have been generated.\nConfiguration must be done before the first render. The configuration will be ignored.");
		return;
	}
	let mergedStates = {};
	let mergedUnits = {};
	let mergedFuncs = {};
	let mergedHandlers = {};
	let mergedTokens = {};
	let mergedRecipes = {};
	if (config.plugins) for (const plugin of config.plugins) {
		if (plugin.states) mergedStates = {
			...mergedStates,
			...plugin.states
		};
		if (plugin.units) mergedUnits = {
			...mergedUnits,
			...plugin.units
		};
		if (plugin.funcs) mergedFuncs = {
			...mergedFuncs,
			...plugin.funcs
		};
		if (plugin.handlers) mergedHandlers = {
			...mergedHandlers,
			...plugin.handlers
		};
		if (plugin.tokens) mergedTokens = {
			...mergedTokens,
			...plugin.tokens
		};
		if (plugin.recipes) mergedRecipes = {
			...mergedRecipes,
			...plugin.recipes
		};
	}
	if (config.states) mergedStates = {
		...mergedStates,
		...config.states
	};
	if (config.units) mergedUnits = {
		...mergedUnits,
		...config.units
	};
	if (config.funcs) mergedFuncs = {
		...mergedFuncs,
		...config.funcs
	};
	if (config.handlers) mergedHandlers = {
		...mergedHandlers,
		...config.handlers
	};
	if (config.tokens) mergedTokens = {
		...mergedTokens,
		...config.tokens
	};
	if (config.recipes) mergedRecipes = {
		...mergedRecipes,
		...config.recipes
	};
	if (Object.keys(mergedStates).length > 0) setGlobalPredefinedStates(mergedStates);
	const parser = getGlobalParser();
	if (config.parserCacheSize !== void 0) parser.updateOptions({ cacheSize: config.parserCacheSize });
	if (Object.keys(mergedUnits).length > 0) {
		const currentUnits = parser.getUnits() ?? CUSTOM_UNITS;
		parser.setUnits({
			...currentUnits,
			...mergedUnits
		});
	}
	if (Object.keys(mergedFuncs).length > 0) {
		const currentFuncs = getGlobalFuncs();
		const finalFuncs = {
			...currentFuncs,
			...mergedFuncs
		};
		parser.setFuncs(finalFuncs);
		Object.assign(currentFuncs, mergedFuncs);
	}
	if (config.keyframes) setGlobalKeyframes(config.keyframes);
	if (config.properties) setGlobalProperties(config.properties);
	if (Object.keys(mergedHandlers).length > 0) for (const [name, definition] of Object.entries(mergedHandlers)) registerHandler(normalizeHandlerDefinition(name, definition));
	if (Object.keys(mergedTokens).length > 0) {
		const processedTokens = {};
		for (const [key, value] of Object.entries(mergedTokens)) if (key.startsWith("#")) {
			const normalized = normalizeColorTokenValue(value);
			if (normalized === null) continue;
			processedTokens[key] = String(normalized);
		} else if (value === false) continue;
		else processedTokens[key] = String(value);
		setGlobalPredefinedTokens(processedTokens);
	}
	if (Object.keys(mergedRecipes).length > 0) setGlobalRecipes(mergedRecipes);
	const { states: _states, parserCacheSize: _parserCacheSize, units: _units, funcs: _funcs, plugins: _plugins, keyframes: _keyframes, properties: _properties, handlers: _handlers, tokens: _tokens, recipes: _recipes, ...injectorConfig } = config;
	const fullConfig = {
		...createDefaultConfig(),
		...currentConfig,
		...injectorConfig
	};
	currentConfig = fullConfig;
	const storage = typeof window !== "undefined" ? window : globalThis;
	storage[GLOBAL_INJECTOR_KEY] = new StyleInjector(fullConfig);
}

//#endregion
export { configure, getGlobalRecipes, hasStylesGenerated };
//# sourceMappingURL=config.js.map