import { CLERK_CLASS_RE, HAS_RE, POSITIONAL_PSEUDO_RE } from "./cssPatterns.js";
import { detectStructuralClerkCss } from "./detectClerkStylesheetUsage.js";
import { logger } from "@clerk/shared/logger";

//#region src/utils/warnAboutCustomizationWithoutPinning.ts
function formatStructuralCssWarning(patterns) {
	return `🔒 Clerk:
[CLERK_W001] Structural CSS detected

Found: ${patterns.length > 0 ? patterns.slice(0, 3).join(", ") : "structural CSS"}${patterns.length > 3 ? ` (+${patterns.length - 3} more)` : ""}\n\nMay break on updates. Pin your version:\n  npm install @clerk/ui && import { ui } from '@clerk/ui'\n  <ClerkProvider ui={ui} />\n\nhttps://clerk.com/docs/customization/versioning\n(This notice only appears in development)`;
}
/**
* Checks if a CSS-in-JS selector has adjacency with another selector.
* For nested selectors like "& > .foo" or "& .cl-something", we check if
* there's a .cl- class combined with another selector via combinator/descendant.
*/
function hasAdjacencyWithOtherSelector(selector) {
	const rest = selector.replace(/^&\s*/, "");
	const hasClerkClass = CLERK_CLASS_RE.test(rest);
	const hasOtherSelector = /[.#\w\[:]/.test(rest.replace(/\.cl-[A-Za-z0-9_-]+/g, ""));
	return hasClerkClass || hasOtherSelector && /[>+~\s]/.test(selector);
}
/**
* Checks if a CSS-in-JS selector key indicates structural DOM assumptions.
*/
function isStructuralSelector(selector) {
	if (!selector.startsWith("&")) return false;
	if (CLERK_CLASS_RE.test(selector)) return true;
	if (POSITIONAL_PSEUDO_RE.test(selector)) return true;
	if (HAS_RE.test(selector)) return true;
	if (hasAdjacencyWithOtherSelector(selector)) return true;
	return false;
}
/**
* Recursively collects structural selectors from a CSS-in-JS value.
*/
function collectStructuralSelectors(value) {
	if (!value || typeof value !== "object") return [];
	const selectors = [];
	for (const [key, nestedValue] of Object.entries(value)) {
		if (isStructuralSelector(key)) selectors.push(key);
		selectors.push(...collectStructuralSelectors(nestedValue));
	}
	return selectors;
}
/**
* Collects structural CSS patterns from appearance.elements.
* Returns patterns in format: elements.{key} "{selector}"
*/
function collectElementPatterns(elements) {
	const patterns = [];
	for (const [elementKey, value] of Object.entries(elements)) {
		if (typeof value === "string") continue;
		const selectors = collectStructuralSelectors(value);
		for (const selector of selectors) patterns.push(`elements.${elementKey} "${selector}"`);
	}
	return patterns;
}
/**
* Warns users when they are using customization
* (structural appearance.elements or structural CSS targeting .cl- classes)
* without pinning their @clerk/ui version.
*
* Note: The caller should check clerk.instanceType === 'development' before calling.
* This function assumes it's only called in development mode.
*
* If the user has explicitly imported @clerk/ui and passed it via the `ui` option,
* they have "pinned" their version and no warning is shown.
*
* Note: We check `options.ui` (not `options.clerkUICtor`) because clerkUICtor is
* always set when loading from CDN via window.__internal_ClerkUICtor.
*/
function warnAboutCustomizationWithoutPinning(options) {
	if (options?.ui) return;
	const patterns = [];
	const appearance = options?.appearance;
	if (appearance?.elements && Object.keys(appearance.elements).length > 0) patterns.push(...collectElementPatterns(appearance.elements));
	const structuralCssHits = detectStructuralClerkCss();
	for (const hit of structuralCssHits) patterns.push(`CSS "${hit.selector}"`);
	if (patterns.length > 0) logger.warnOnce(formatStructuralCssWarning(patterns));
}

//#endregion
export { warnAboutCustomizationWithoutPinning };
//# sourceMappingURL=warnAboutCustomizationWithoutPinning.js.map