import { isDefined } from "@scalar/helpers/array/is-defined";
import { unpackProxyObject } from "@scalar/workspace-store/helpers/unpack-proxy";
import { resolve } from "@scalar/workspace-store/resolve";
//#region src/v2/blocks/operation-code-sample/helpers/get-example-from-schema.ts
/** Maximum recursion depth to prevent infinite loops in circular references */
var MAX_LEVELS_DEEP = 10;
/** Default name used for additional properties when no custom name is provided */
var DEFAULT_ADDITIONAL_PROPERTIES_NAME = "additionalProperty";
/**
* Pre-computed date/time values to avoid expensive Date operations on every call.
* These are calculated once at module load time for better performance.
*/
var currentISOString = (/* @__PURE__ */ new Date()).toISOString();
var currentDateString = currentISOString.split("T")[0];
var currentTimeString = currentISOString.split("T")[1].split(".")[0];
/**
* Mapping of OpenAPI string formats to example values.
* Used to generate realistic examples for different string formats.
*/
var genericExampleValues = {
	"date-time": currentISOString,
	"date": currentDateString,
	"email": "hello@example.com",
	"hostname": "example.com",
	"idn-email": "jane.doe@example.com",
	"idn-hostname": "example.com",
	"ipv4": "127.0.0.1",
	"ipv6": "51d4:7fab:bfbf:b7d7:b2cb:d4b4:3dad:d998",
	"iri-reference": "/entitiy/1",
	"iri": "https://example.com/entity/123",
	"json-pointer": "/nested/objects",
	"password": "super-secret",
	"regex": "/[a-z]/",
	"relative-json-pointer": "1/nested/objects",
	"time": currentTimeString,
	"uri-reference": "../folder",
	"uri-template": "https://example.com/{id}",
	"uri": "https://example.com",
	"uuid": "123e4567-e89b-12d3-a456-426614174000",
	"object-id": "6592008029c8c3e4dc76256c"
};
/**
* Extract enum values from the propertyNames keyword of an object schema.
* JSON Schema's propertyNames constrains which keys are valid in a map/dict.
*/
var getPropertyNamesEnumValues = (schema) => {
	if (!("propertyNames" in schema) || !schema.propertyNames) return;
	const resolved = resolve.schema(schema.propertyNames);
	if (resolved && "enum" in resolved && Array.isArray(resolved.enum) && resolved.enum.length > 0) return resolved.enum;
};
/**
* Generate example values for string types based on their format.
* Special handling for binary format which returns a File object.
*/
var guessFromFormat = (schema, makeUpRandomData = false, fallback = "") => {
	if ("type" in schema && schema.type === "string" && "format" in schema && schema.format === "binary") return "@filename";
	if (makeUpRandomData && "format" in schema && schema.format) return genericExampleValues[schema.format] ?? fallback;
	return fallback;
};
/**
* WeakMap cache for memoizing resolved example results.
* Uses the resolved schema object as the key for efficient lookups.
*/
var resultCache = /* @__PURE__ */ new WeakMap();
/** Cache required property names per parent schema for O(1) membership checks */
var requiredNamesCache = /* @__PURE__ */ new WeakMap();
/** Normalize schema identity for cache and cycle tracking */
var getSchemaCacheTarget = (schema) => unpackProxyObject(schema, { depth: 1 });
/**
* Retrieves the set of required property names from a schema.
* Caches the result in a WeakMap for efficient lookups.
*/
var getRequiredNames = (parentSchema) => {
	if (!parentSchema) return;
	const cached = requiredNamesCache.get(parentSchema);
	if (cached) return cached;
	if ("required" in parentSchema) {
		const required = parentSchema.required;
		if (Array.isArray(required) && required.length > 0) {
			const set = new Set(required);
			requiredNamesCache.set(parentSchema, set);
			return set;
		}
	}
};
/**
* Cache the result for a schema if it is an object type.
* Primitive values are not cached to avoid unnecessary WeakMap operations.
* Stores a map of cacheKey strings which is made up of the options object.
*/
var cache = (schema, result, cacheKey) => {
	if (typeof result !== "object" || result === null) return result;
	const rawSchema = getSchemaCacheTarget(schema);
	const cacheMap = resultCache.get(rawSchema) ?? /* @__PURE__ */ new Map();
	if (cacheMap) cacheMap.set(cacheKey, result);
	resultCache.set(rawSchema, cacheMap);
	return result;
};
/**
* Check if a schema uses composition keywords (allOf, oneOf, anyOf).
* These require special handling for merging or selecting schemas.
*/
var isComposed = (schema) => !!(schema.allOf || schema.oneOf || schema.anyOf);
/**
* Determine if a property should be omitted based on the options.
* Properties are omitted if they are not required and the option is enabled.
*/
var shouldOmitProperty = (schema, parentSchema, propertyName, options) => {
	if (schema.deprecated || options?.mode === "write" && schema.readOnly || options?.mode === "read" && schema.writeOnly) return true;
	if (options?.omitEmptyAndOptionalProperties !== true) return false;
	if ("type" in schema && (schema.type === "object" || schema.type === "array") || isComposed(schema)) return false;
	if ("examples" in schema && Array.isArray(schema.examples) && schema.examples.length > 0 || "example" in schema && schema.example !== void 0 || "default" in schema && schema.default !== void 0 || "const" in schema && schema.const !== void 0 || "enum" in schema && Array.isArray(schema.enum) && schema.enum.length > 0) return false;
	const name = propertyName ?? schema.title ?? "";
	const requiredNames = getRequiredNames(parentSchema);
	return !(requiredNames ? requiredNames.has(name) : false);
};
/**
* Merge two example values with predictable semantics.
* Arrays are concatenated, objects are merged, otherwise the new value wins.
*/
var mergeExamples = (baseValue, newValue) => {
	if (Array.isArray(baseValue) && Array.isArray(newValue)) return [...baseValue, ...newValue];
	if (baseValue && typeof baseValue === "object" && newValue && typeof newValue === "object") return {
		...baseValue,
		...newValue
	};
	return newValue;
};
var getCompositionSelectionKey = (schemaPath, composition) => [...schemaPath, composition].join(".");
var getCompositionSelectionIndex = (schemaPath, composition, options, length) => {
	const rawIndex = options?.compositionSelection?.[getCompositionSelectionKey(schemaPath, composition)];
	if (typeof rawIndex !== "number" || Number.isNaN(rawIndex)) return;
	return Math.max(0, Math.min(rawIndex, length - 1));
};
/**
* Build an example for an object schema, including properties, patternProperties,
* additionalProperties, and composition (allOf/oneOf/anyOf) merging.
*/
var handleObjectSchema = (schema, options, level, seen, cacheKey, schemaPath) => {
	const response = {};
	if ("properties" in schema && schema.properties) {
		const propertyNames = Object.keys(schema.properties);
		const limit = propertyNames.length;
		for (let i = 0; i < limit; i++) {
			const propertyName = propertyNames[i];
			const propertySchema = resolve.schema(schema.properties[propertyName]);
			if (!propertySchema) continue;
			const propertyXmlName = options?.xml && "xml" in propertySchema ? propertySchema.xml?.name : void 0;
			const value = getExampleFromSchema(propertySchema, options, {
				level: level + 1,
				parentSchema: schema,
				name: propertyName,
				schemaPath: [...schemaPath, propertyName],
				seen
			});
			if (typeof value !== "undefined") response[propertyXmlName ?? propertyName] = value;
		}
	}
	if ("patternProperties" in schema && schema.patternProperties) for (const pattern of Object.keys(schema.patternProperties)) {
		const propertySchema = resolve.schema(schema.patternProperties[pattern]);
		if (!propertySchema) continue;
		response[pattern] = getExampleFromSchema(propertySchema, options, {
			level: level + 1,
			parentSchema: schema,
			name: pattern,
			schemaPath: [...schemaPath, pattern],
			seen
		});
	}
	if ("additionalProperties" in schema && schema.additionalProperties) {
		const additional = typeof schema.additionalProperties === "boolean" ? schema.additionalProperties : resolve.schema(schema.additionalProperties);
		const isAnyType = schema.additionalProperties === true || typeof schema.additionalProperties === "object" && Object.keys(schema.additionalProperties).length === 0;
		const hasCustomName = typeof additional === "object" && "x-additionalPropertiesName" in additional && typeof additional["x-additionalPropertiesName"] === "string" && additional["x-additionalPropertiesName"].trim().length > 0;
		const propertyNamesEnum = hasCustomName ? void 0 : getPropertyNamesEnumValues(schema);
		const additionalName = hasCustomName ? additional["x-additionalPropertiesName"].trim() : DEFAULT_ADDITIONAL_PROPERTIES_NAME;
		const additionalValue = isAnyType ? "anything" : typeof additional === "object" ? getExampleFromSchema(additional, options, {
			level: level + 1,
			schemaPath: [...schemaPath, additionalName],
			seen
		}) : "anything";
		if (propertyNamesEnum && propertyNamesEnum.length > 0) response[String(propertyNamesEnum[0])] = additionalValue;
		else response[additionalName] = additionalValue;
	}
	const compositionKeyword = schema.oneOf ? "oneOf" : schema.anyOf ? "anyOf" : void 0;
	const oneOfAnyOf = compositionKeyword ? schema[compositionKeyword] : void 0;
	if (compositionKeyword && oneOfAnyOf?.length) {
		const index = getCompositionSelectionIndex(schemaPath, compositionKeyword, options, oneOfAnyOf.length) ?? 0;
		const chosen = resolve.schema(oneOfAnyOf[index]);
		if (chosen) Object.assign(response, getExampleFromSchema(chosen, options, {
			level: level + 1,
			schemaPath,
			seen
		}));
	} else if (Array.isArray(schema.allOf) && schema.allOf.length > 0) {
		let merged = response;
		for (const item of schema.allOf) {
			const ex = getExampleFromSchema(resolve.schema(item), options, {
				level: level + 1,
				parentSchema: schema,
				seen
			});
			merged = mergeExamples(merged, ex);
		}
		if (merged && typeof merged === "object") Object.assign(response, merged);
	}
	if (options?.xml && "xml" in schema && schema.xml?.name && level === 0) {
		const wrapped = {};
		wrapped[schema.xml.name] = response;
		return cache(schema, wrapped, cacheKey);
	}
	return cache(schema, response, cacheKey);
};
/** Build an example for an array schema, including items, allOf, oneOf/anyOf, and XML wrapping */
var handleArraySchema = (schema, options, level, seen, cacheKey, schemaPath) => {
	const items = "items" in schema ? resolve.schema(schema.items) : void 0;
	const itemsSchemaPath = [...schemaPath, "items"];
	const itemsXmlTagName = items && typeof items === "object" && "xml" in items ? items.xml?.name : void 0;
	const wrapItems = !!(options?.xml && "xml" in schema && schema.xml?.wrapped && itemsXmlTagName);
	if (schema.example !== void 0) return cache(schema, wrapItems ? { [itemsXmlTagName]: schema.example } : schema.example, cacheKey);
	if (items && typeof items === "object") {
		if (Array.isArray(items.allOf) && items.allOf.length > 0) {
			const allOf = items.allOf.filter(isDefined);
			const first = resolve.schema(allOf[0]);
			if (first && typeof first === "object" && "type" in first && first.type === "object") {
				const merged = getExampleFromSchema({
					type: "object",
					allOf
				}, options, {
					level: level + 1,
					parentSchema: schema,
					schemaPath: itemsSchemaPath,
					seen
				});
				return cache(schema, wrapItems ? [{ [itemsXmlTagName]: merged }] : [merged], cacheKey);
			}
			const examples = allOf.map((s) => getExampleFromSchema(resolve.schema(s), options, {
				level: level + 1,
				parentSchema: schema,
				schemaPath: itemsSchemaPath,
				seen
			})).filter(isDefined);
			return cache(schema, wrapItems ? examples.map((e) => ({ [itemsXmlTagName]: e })) : examples, cacheKey);
		}
		const compositionKeyword = items.oneOf ? "oneOf" : items.anyOf ? "anyOf" : void 0;
		const union = compositionKeyword ? items[compositionKeyword] : void 0;
		if (compositionKeyword && union && union.length > 0) {
			const selected = union[getCompositionSelectionIndex(itemsSchemaPath, compositionKeyword, options, union.length) ?? 0];
			const ex = getExampleFromSchema(resolve.schema(selected), options, {
				level: level + 1,
				parentSchema: schema,
				schemaPath: itemsSchemaPath,
				seen
			});
			return cache(schema, wrapItems ? [{ [itemsXmlTagName]: ex }] : [ex], cacheKey);
		}
	}
	const isObject = items && typeof items === "object" && ("type" in items && items.type === "object" || "properties" in items);
	const isArray = items && typeof items === "object" && ("type" in items && items.type === "array" || "items" in items);
	if (items && typeof items === "object" && ("type" in items && items.type || isObject || isArray)) {
		const ex = getExampleFromSchema(items, options, {
			level: level + 1,
			schemaPath: itemsSchemaPath,
			seen
		});
		return cache(schema, wrapItems ? [{ [itemsXmlTagName]: ex }] : [ex], cacheKey);
	}
	return cache(schema, [], cacheKey);
};
/** Return primitive example value for single-type schemas, or undefined if not primitive */
var getPrimitiveValue = (schema, makeUpRandomData, emptyString) => {
	if ("type" in schema && schema.type && !Array.isArray(schema.type)) switch (schema.type) {
		case "string": return guessFromFormat(schema, makeUpRandomData, emptyString ?? "");
		case "boolean": return true;
		case "integer": return "minimum" in schema && typeof schema.minimum === "number" ? schema.minimum : 1;
		case "number": return "minimum" in schema && typeof schema.minimum === "number" ? schema.minimum : 1;
		case "array": return [];
		default: return;
	}
};
/** Return primitive example value for union-type schemas (type: string[]) */
var getUnionPrimitiveValue = (schema, makeUpRandomData, emptyString) => {
	if ("type" in schema && Array.isArray(schema.type)) {
		if (schema.type.includes("null")) return null;
		const first = schema.type[0];
		if (first) switch (first) {
			case "string": return guessFromFormat(schema, makeUpRandomData, emptyString ?? "");
			case "boolean": return true;
			case "integer": return "minimum" in schema && typeof schema.minimum === "number" ? schema.minimum : 1;
			case "number": return "minimum" in schema && typeof schema.minimum === "number" ? schema.minimum : 1;
			case "null": return null;
			default: return;
		}
	}
};
/** Create stable cache key from the options object */
var createOptionsCacheKey = (options) => JSON.stringify({
	emptyString: options?.emptyString,
	xml: options?.xml,
	mode: options?.mode,
	variables: options?.variables,
	omitEmptyAndOptionalProperties: options?.omitEmptyAndOptionalProperties,
	compositionSelection: options?.compositionSelection ? Object.entries(options.compositionSelection).sort(([a], [b]) => a.localeCompare(b)) : void 0
});
/**
* Generate an example value from a given OpenAPI SchemaObject.
*
* This function recursively processes OpenAPI schemas to create realistic example data.
* It handles all OpenAPI schema types including primitives, objects, arrays, and
* composition schemas (allOf, oneOf, anyOf).
* Uses a tonne of caching for maximum performance.
*
* @param schema - The OpenAPI SchemaObject to generate an example from.
* @param options - Options to customize example generation.
* @param level - The current recursion depth.
* @param parentSchema - The parent schema, if any.
* @param name - The name of the property being processed.
* @returns An example value for the given schema.
*/
var getExampleFromSchema = (schema, options, { level = 0, parentSchema, name, seen = /* @__PURE__ */ new WeakSet(), schemaPath = [] } = {}) => {
	const _schema = resolve.schema(schema);
	if (!isDefined(_schema)) return;
	const targetValue = getSchemaCacheTarget(_schema);
	if (seen.has(targetValue)) return;
	seen.add(targetValue);
	/** Make the cache key unique per options and schema path */
	const cacheKey = createOptionsCacheKey(options) + (schemaPath.length > 0 ? `:path:${schemaPath.join(".")}` : "");
	const cached = resultCache.get(targetValue)?.get(cacheKey);
	if (typeof cached !== "undefined") {
		seen.delete(targetValue);
		return cached;
	}
	if (level > MAX_LEVELS_DEEP) {
		seen.delete(targetValue);
		return "[Max Depth Exceeded]";
	}
	const makeUpRandomData = !!options?.emptyString;
	if (shouldOmitProperty(_schema, parentSchema, name, options)) {
		seen.delete(targetValue);
		return;
	}
	if ("x-variable" in _schema && _schema["x-variable"]) {
		const value = options?.variables?.[_schema["x-variable"]];
		if (value !== void 0) {
			if ("type" in _schema && (_schema.type === "number" || _schema.type === "integer")) {
				seen.delete(targetValue);
				return cache(_schema, Number(value), cacheKey);
			}
			seen.delete(targetValue);
			return cache(_schema, value, cacheKey);
		}
	}
	if (Array.isArray(_schema.examples) && _schema.examples.length > 0) {
		seen.delete(targetValue);
		return cache(_schema, _schema.examples[0], cacheKey);
	}
	if (_schema.example !== void 0) {
		seen.delete(targetValue);
		return cache(_schema, _schema.example, cacheKey);
	}
	if (_schema.default !== void 0) {
		seen.delete(targetValue);
		return cache(_schema, _schema.default, cacheKey);
	}
	if (_schema.const !== void 0) {
		seen.delete(targetValue);
		return cache(_schema, _schema.const, cacheKey);
	}
	if (Array.isArray(_schema.enum) && _schema.enum.length > 0) {
		seen.delete(targetValue);
		return cache(_schema, _schema.enum[0], cacheKey);
	}
	if ("properties" in _schema || "type" in _schema && _schema.type === "object") {
		const result = handleObjectSchema(_schema, options, level, seen, cacheKey, schemaPath);
		seen.delete(targetValue);
		return result;
	}
	if ("type" in _schema && _schema.type === "array" || "items" in _schema) {
		const result = handleArraySchema(_schema, options, level, seen, cacheKey, schemaPath);
		seen.delete(targetValue);
		return result;
	}
	const primitive = getPrimitiveValue(_schema, makeUpRandomData, options?.emptyString);
	if (primitive !== void 0) {
		seen.delete(targetValue);
		return cache(_schema, primitive, cacheKey);
	}
	const compositionKeyword = _schema.oneOf ? "oneOf" : _schema.anyOf ? "anyOf" : void 0;
	const discriminate = compositionKeyword ? _schema[compositionKeyword] : void 0;
	if (compositionKeyword && Array.isArray(discriminate) && discriminate.length > 0) {
		const index = getCompositionSelectionIndex(schemaPath, compositionKeyword, options, discriminate.length);
		const candidate = index !== void 0 ? discriminate[index] : discriminate.find((item) => {
			const resolved = resolve.schema(item);
			return resolved && (!("type" in resolved) || resolved.type !== "null");
		});
		if (candidate) {
			const resolved = resolve.schema(candidate);
			if (resolved) {
				seen.delete(targetValue);
				return cache(_schema, getExampleFromSchema(resolved, options, {
					level: level + 1,
					schemaPath,
					seen
				}), cacheKey);
			}
		}
		seen.delete(targetValue);
		return cache(_schema, null, cacheKey);
	}
	if (Array.isArray(_schema.allOf) && _schema.allOf.length > 0) {
		let merged = void 0;
		const items = _schema.allOf;
		for (const item of items) {
			const ex = getExampleFromSchema(item, options, {
				level: level + 1,
				parentSchema: _schema,
				schemaPath,
				seen
			});
			if (merged === void 0) merged = ex;
			else if (merged && typeof merged === "object" && ex && typeof ex === "object") merged = mergeExamples(merged, ex);
			else if (ex !== void 0) merged = ex;
		}
		seen.delete(targetValue);
		return cache(_schema, merged ?? null, cacheKey);
	}
	const unionPrimitive = getUnionPrimitiveValue(_schema, makeUpRandomData, options?.emptyString);
	if (unionPrimitive !== void 0) {
		seen.delete(targetValue);
		return cache(_schema, unionPrimitive, cacheKey);
	}
	seen.delete(targetValue);
	return cache(_schema, null, cacheKey);
};
//#endregion
export { getExampleFromSchema };

//# sourceMappingURL=get-example-from-schema.js.map