/*! © 2026 Yahoo, Inc. UDS v0.0.0-development */
const require_StateAxis = require("../types/StateAxis.cjs");
const require_canonicalizeStateKey = require("./canonicalizeStateKey.cjs");
//#region ../tailwind-internal/dist/packages/automated-config/dist/utils/resolvePropertyStates.js
/*! © 2026 Yahoo, Inc. UDS Tailwind Internal v0.0.0-development */
/*! © 2026 Yahoo, Inc. UDS Default Config v0.0.0-development */
/**
* Yields every modifier subset of size 1..maxSize, preserving input order
* within each subset. Used by both the resolver and the docs-class
* enumeration so the depth they support stays in lock-step.
*
* Generic over the element type so callers passing `ModifierAtomic[]` get
* `Generator<readonly ModifierAtomic[]>` back — keeps the inferred type chain
* tight enough for downstream consumers to avoid widening to `string`.
*/
function* modifierSubsets(modifiers, maxSize) {
	const indices = [];
	function* recurse(start) {
		if (indices.length > 0) yield indices.map((i) => modifiers[i]);
		if (indices.length === maxSize) return;
		for (let i = start; i < modifiers.length; i++) {
			indices.push(i);
			yield* recurse(i + 1);
			indices.pop();
		}
	}
	yield* recurse(0);
}
/**
* Yields the interactive subsets that can be simultaneously active on one
* element, in `modifierSubsets` order. `hover` and `pressed` are mutually
* exclusive — the `hover` selector carries `:where(:not(:active …))`, so a
* `hover&pressed` rule could never match — so any subset containing BOTH is
* dropped. Every other subset is kept (notably `focus-within`/`focus-visible`
* CAN coexist with a pointer state: you can hover or press a focused element).
*
* `interactives` MUST already be sorted by `comparePriority`.
*/
function* coOccurringInteractiveSubsets(interactives) {
	for (const subset of modifierSubsets(interactives, interactives.length)) {
		if (subset.includes("hover") && subset.includes("pressed")) continue;
		yield subset;
	}
}
/**
* Yields a property's atomic + compound state keys in cascade order from a
* priority-sorted atomic set:
*
*   atoms (in the given order)
*   → for each modifier subset: the pure-modifier compound (size ≥ 2) then each
*     modifier-subset × SINGLE-interactive compound
*   → each pure interactive-pair compound (size ≥ 2, co-occurring)
*   → each modifier-subset × interactive-PAIR compound
*
* The interactive-pair compounds are APPENDED after the original keys so every
* pre-existing key keeps its rank — `resolveSlotByCascade`'s tie-break and
* Figma's published values for already-declared states are therefore unchanged;
* only genuinely new co-occurring combinations (e.g. `focus-within&hover`) gain
* a key. Each is a real declared state with its own rule, so a property whose
* `focus-within` and `hover` resolve to different values renders the
* per-property-correct blend at `(0, 1+atomCount, 0)` specificity in BOTH emit
* modes — closing the only exhaustive/selective divergence (two interactives
* co-occurring with no compound to arbitrate them). `hover&pressed` pairs are
* never generated (they can't co-occur; see `coOccurringInteractiveSubsets`).
*
* `'rest'` is NOT included — callers prepend it (and decide whether to, e.g.
* `skipRestState`). `atomics` MUST already be sorted by `comparePriority`
* (weakest first) so the strongest atom emits last and wins on intra-rank
* source-order ties.
*
* Shared by `resolvePropertyStates` (the CSS-emission source of truth) and
* `resolveSlotByCascade`'s cascade-rank computation, so the emission order —
* and therefore the cascade tie-break it implies — stays identical across both.
* Change emission order here, not in either caller.
*/
function* atomicAndCompoundStateKeys(atomics) {
	for (const atom of atomics) yield atom;
	const modifiers = atomics.filter(require_StateAxis.isModifierAtomic);
	const interactives = atomics.filter(require_StateAxis.isInteractiveAtomic);
	for (const subset of modifierSubsets(modifiers, 3)) {
		if (subset.length >= 2) yield require_canonicalizeStateKey.canonicalizeStateKey(subset);
		for (const interactive of interactives) yield require_canonicalizeStateKey.canonicalizeStateKey([...subset, interactive]);
	}
	const interactivePairs = [...coOccurringInteractiveSubsets(interactives)].filter((subset) => subset.length >= 2);
	for (const interactiveSubset of interactivePairs) yield require_canonicalizeStateKey.canonicalizeStateKey(interactiveSubset);
	for (const subset of modifierSubsets(modifiers, 3)) for (const interactiveSubset of interactivePairs) yield require_canonicalizeStateKey.canonicalizeStateKey([...subset, ...interactiveSubset]);
}
/**
* Returns all canonical state keys a property reacts to, in cascade order:
*
*   rest → atomics (sorted by global `STATE_PRIORITY`, weakest first)
*   → 2-atom compounds → 3-atom compounds → ...
*
* Cross-rank ordering (atom < 2-atom compound < 3-atom compound < ...) is
* enforced by CSS class-count specificity. Each atom selector contributes
* (0,1,0), so a 2-atom compound at (0,3,0) strictly beats a 1-atom rule at
* (0,2,0) — the cascade-cancellation feature is encoded in the selector
* itself rather than rule source order.
*
* Intra-rank ties (which atom wins among the priority-sorted set, or which
* 2-atom compound wins among siblings of the same size) fall through to
* source order at the same specificity. Emission order follows the global
* `STATE_PRIORITY` array — to change which atom wins between any two
* simultaneously-matching atoms, reorder that array.
*
* Resolution sources, in order of precedence:
*
*   1. The new system: `layer.atomicStates` declares the atoms this layer can
*      compose; `property.excludeAtomics` opts the property out of selected
*      atoms. Compounds are auto-generated from the resulting set via
*      modifier × interactive expansion.
*   2. The legacy system: `property.pseudoStates` (no compound generation; the
*      array is used verbatim). Used when `layer.atomicStates` is absent so
*      unmigrated component configs continue to behave exactly as before.
*
* `'rest'` is always included unless the property has `skipRestState: true`.
*/
function resolvePropertyStates(layer, property) {
	const states = [];
	if (!(property.skipRestState === true)) states.push("rest");
	if (layer.atomicStates && layer.atomicStates.length > 0) {
		const exclude = new Set(property.excludeAtomics ?? []);
		const atomics = [...layer.atomicStates].filter((atom) => !exclude.has(atom)).sort(require_StateAxis.comparePriority);
		for (const stateKey of atomicAndCompoundStateKeys(atomics)) states.push(stateKey);
		return states;
	}
	if (property.pseudoStates) for (const s of property.pseudoStates) states.push(s);
	return states;
}
//#endregion
exports.atomicAndCompoundStateKeys = atomicAndCompoundStateKeys;
exports.resolvePropertyStates = resolvePropertyStates;
