import { SelectorType } from "../../../css-what/lib/es/types.js";
import { attributeRules } from "./attributes.js";
import { compilePseudoSelector } from "./pseudo-selectors/index.js";
//#region node_modules/css-select/lib/esm/general.js
function getElementParent(node, adapter) {
	const parent = adapter.getParent(node);
	if (parent && adapter.isTag(parent)) return parent;
	return null;
}
function compileGeneralSelector(next, selector, options, context, compileToken) {
	const { adapter, equals } = options;
	switch (selector.type) {
		case SelectorType.PseudoElement: throw new Error("Pseudo-elements are not supported by css-select");
		case SelectorType.ColumnCombinator: throw new Error("Column combinators are not yet supported by css-select");
		case SelectorType.Attribute:
			if (selector.namespace != null) throw new Error("Namespaced attributes are not yet supported by css-select");
			if (!options.xmlMode || options.lowerCaseAttributeNames) selector.name = selector.name.toLowerCase();
			return attributeRules[selector.action](next, selector, options);
		case SelectorType.Pseudo: return compilePseudoSelector(next, selector, options, context, compileToken);
		case SelectorType.Tag: {
			if (selector.namespace != null) throw new Error("Namespaced tag names are not yet supported by css-select");
			let { name } = selector;
			if (!options.xmlMode || options.lowerCaseTags) name = name.toLowerCase();
			return function tag(elem) {
				return adapter.getName(elem) === name && next(elem);
			};
		}
		case SelectorType.Descendant: {
			if (options.cacheResults === false || typeof WeakSet === "undefined") return function descendant(elem) {
				let current = elem;
				while (current = getElementParent(current, adapter)) if (next(current)) return true;
				return false;
			};
			const isFalseCache = /* @__PURE__ */ new WeakSet();
			return function cachedDescendant(elem) {
				let current = elem;
				while (current = getElementParent(current, adapter)) if (!isFalseCache.has(current)) {
					if (adapter.isTag(current) && next(current)) return true;
					isFalseCache.add(current);
				}
				return false;
			};
		}
		case "_flexibleDescendant": return function flexibleDescendant(elem) {
			let current = elem;
			do
				if (next(current)) return true;
			while (current = getElementParent(current, adapter));
			return false;
		};
		case SelectorType.Parent: return function parent(elem) {
			return adapter.getChildren(elem).some((elem) => adapter.isTag(elem) && next(elem));
		};
		case SelectorType.Child: return function child(elem) {
			const parent = adapter.getParent(elem);
			return parent != null && adapter.isTag(parent) && next(parent);
		};
		case SelectorType.Sibling: return function sibling(elem) {
			const siblings = adapter.getSiblings(elem);
			for (let i = 0; i < siblings.length; i++) {
				const currentSibling = siblings[i];
				if (equals(elem, currentSibling)) break;
				if (adapter.isTag(currentSibling) && next(currentSibling)) return true;
			}
			return false;
		};
		case SelectorType.Adjacent:
			if (adapter.prevElementSibling) return function adjacent(elem) {
				const previous = adapter.prevElementSibling(elem);
				return previous != null && next(previous);
			};
			return function adjacent(elem) {
				const siblings = adapter.getSiblings(elem);
				let lastElement;
				for (let i = 0; i < siblings.length; i++) {
					const currentSibling = siblings[i];
					if (equals(elem, currentSibling)) break;
					if (adapter.isTag(currentSibling)) lastElement = currentSibling;
				}
				return !!lastElement && next(lastElement);
			};
		case SelectorType.Universal:
			if (selector.namespace != null && selector.namespace !== "*") throw new Error("Namespaced universal selectors are not yet supported by css-select");
			return next;
	}
}
//#endregion
export { compileGeneralSelector };
