/*! © 2026 Yahoo, Inc. UDS v0.0.0-development */
import { comparePriority, isAtomicState, isModifierAtomic } from "../types/StateAxis.js";
import { atomicAndCompoundStateKeys } from "./resolvePropertyStates.js";
//#region ../tailwind-internal/dist/packages/automated-config/dist/utils/resolveSlotByCascade.js
/*! © 2026 Yahoo, Inc. UDS Tailwind Internal v0.0.0-development */
/*! © 2026 Yahoo, Inc. UDS Default Config v0.0.0-development */
/**
* Mirrors `resolvePropertyStates`'s emission order using only the atoms that
* appear in the property's actual state map, so consumers that need a cascade
* tie-break can compare these indices (later = stronger). The atom + compound
* ordering comes from the shared `atomicAndCompoundStateKeys` generator, which
* keeps this rank identical to the CSS the generator emits.
*/
function computeCascadeOrder(propertyStates) {
	const presentAtoms = /* @__PURE__ */ new Set();
	for (const stateName of Object.keys(propertyStates)) {
		if (stateName === "rest" || propertyStates[stateName] == null) continue;
		for (const atom of stateName.split("&")) presentAtoms.add(atom);
	}
	const atomics = [...presentAtoms].filter(isAtomicState).sort(comparePriority);
	const order = ["rest"];
	for (const stateKey of atomicAndCompoundStateKeys(atomics)) order.push(stateKey);
	return order;
}
/**
* Resolves a state slot following CSS-cascade semantics: a `rest` slot or a
* non-rest slot with `isEnabled === true` resolves to itself; an unflagged
* non-rest slot resolves to the most-specific enabled state whose atoms are a
* subset of the requested state's atoms. A present-but-disabled single MODIFIER
* atom is the exception: it participates at the `rest` value (never its own
* stored value), so a dropped higher-priority modifier (e.g. `invalid`, left
* flag-less because it equals `rest`) suppresses a lower-priority enabled atom
* inside a compound rather than letting it brighten through — an invalid field
* shouldn't get the hover color when `invalid` resets to `rest`. A disabled
* INTERACTIVE atom does NOT participate: it contributes no rule of its own, so
* an enabled lower-priority interactive survives (e.g. `focus-within` styling
* persists while `hover`/`pressed`, left at `rest`, is active). Disabled
* COMPOUNDS and absent atoms do not participate either.
*
* Same-size candidates are tie-broken by the cascade emission order from
* `resolvePropertyStates` — i.e. the rule that the browser would have applied
* last under equal specificity. The single rule is: later in emission order =
* stronger. At the 1-atom level that makes the higher-`STATE_PRIORITY` atom
* win, so modifiers (`invalid`, `readonly`) beat interactives (`hover`,
* `pressed`) because they sit later in `STATE_PRIORITY`. At the 2-atom level a
* pure-modifier compound from subset `[m1, m2]` beats any modifier+interactive
* compound built from an *earlier* single-modifier subset (e.g.
* `invalid&readonly` beats `invalid&hover`), since `modifierSubsets` emits the
* size-2 subset after the size-1 subsets that precede it; compounds from a
* *later* single-modifier subset (e.g. `readonly&hover`) still emit afterward
* and win. Falls back to `rest` when no enabled subset exists.
*
* Two consumers rely on this:
*   - `generateDeclaration` (exhaustive emission for `atomicStates` layers) resolves
*     the value for every declared state — including the many compounds the
*     sparse stored config never persists — so each emitted rule carries the
*     value the cascade would have produced, with no gap a nested foreign theme
*     could fill.
*   - The Figma plugin emits a single library variable value per (component,
*     layer, property, state) matching that same CSS, so disabled slots don't
*     show up as orphaned customizations in the Figma library.
*/
function resolveSlotByCascade(stateName, propertyStates) {
	const direct = propertyStates[stateName];
	if (stateName === "rest") return direct;
	if (direct?.isEnabled === true) return direct;
	const cascadeOrder = computeCascadeOrder(propertyStates);
	const rankOf = /* @__PURE__ */ new Map();
	cascadeOrder.forEach((s, i) => rankOf.set(s, i));
	const targetAtoms = new Set(stateName.split("&"));
	let best = null;
	const restSlot = propertyStates.rest;
	for (const [candidateKey, slot] of Object.entries(propertyStates)) {
		if (!slot) continue;
		if (candidateKey === stateName) continue;
		const atoms = candidateKey === "rest" ? [] : candidateKey.split("&");
		if (!atoms.every((a) => targetAtoms.has(a))) continue;
		const enabled = candidateKey === "rest" || slot.isEnabled === true;
		let effectiveSlot;
		if (enabled) effectiveSlot = slot;
		else if (atoms.length === 1 && isModifierAtomic(atoms[0])) effectiveSlot = restSlot;
		else continue;
		if (!effectiveSlot) continue;
		const rank = rankOf.get(candidateKey) ?? -1;
		const size = atoms.length;
		if (!best || size > best.size || size === best.size && rank > best.rank) best = {
			rank,
			size,
			slot: effectiveSlot
		};
	}
	return best?.slot ?? propertyStates.rest;
}
//#endregion
export { resolveSlotByCascade };
