import { getEnumValues } from "./util.js";
import { extractDefs, finalize, initializeContext, process } from "./to-json-schema.js";
var formatMap = {
	guid: "uuid",
	url: "uri",
	datetime: "date-time",
	json_string: "json-string",
	regex: ""
};
const stringProcessor = (l, F, I, L) => {
	let R = I;
	R.type = "string";
	let { minimum: B, maximum: V, format: H, patterns: U, contentEncoding: W } = l._zod.bag;
	if (typeof B == "number" && (R.minLength = B), typeof V == "number" && (R.maxLength = V), H && (R.format = formatMap[H] ?? H, R.format === "" && delete R.format, H === "time" && delete R.format), W && (R.contentEncoding = W), U && U.size > 0) {
		let l = [...U];
		l.length === 1 ? R.pattern = l[0].source : l.length > 1 && (R.allOf = [...l.map((l) => ({
			...F.target === "draft-07" || F.target === "draft-04" || F.target === "openapi-3.0" ? { type: "string" } : {},
			pattern: l.source
		}))]);
	}
}, numberProcessor = (l, F, I, L) => {
	let R = I, { minimum: z, maximum: B, format: V, multipleOf: H, exclusiveMaximum: U, exclusiveMinimum: W } = l._zod.bag;
	typeof V == "string" && V.includes("int") ? R.type = "integer" : R.type = "number", typeof W == "number" && (F.target === "draft-04" || F.target === "openapi-3.0" ? (R.minimum = W, R.exclusiveMinimum = !0) : R.exclusiveMinimum = W), typeof z == "number" && (R.minimum = z, typeof W == "number" && F.target !== "draft-04" && (W >= z ? delete R.minimum : delete R.exclusiveMinimum)), typeof U == "number" && (F.target === "draft-04" || F.target === "openapi-3.0" ? (R.maximum = U, R.exclusiveMaximum = !0) : R.exclusiveMaximum = U), typeof B == "number" && (R.maximum = B, typeof U == "number" && F.target !== "draft-04" && (U <= B ? delete R.maximum : delete R.exclusiveMaximum)), typeof H == "number" && (R.multipleOf = H);
}, booleanProcessor = (l, F, I, L) => {
	I.type = "boolean";
}, bigintProcessor = (l, F, I, L) => {
	if (F.unrepresentable === "throw") throw Error("BigInt cannot be represented in JSON Schema");
}, symbolProcessor = (l, F, I, L) => {
	if (F.unrepresentable === "throw") throw Error("Symbols cannot be represented in JSON Schema");
}, nullProcessor = (l, F, I, L) => {
	F.target === "openapi-3.0" ? (I.type = "string", I.nullable = !0, I.enum = [null]) : I.type = "null";
}, undefinedProcessor = (l, F, I, L) => {
	if (F.unrepresentable === "throw") throw Error("Undefined cannot be represented in JSON Schema");
}, voidProcessor = (l, F, I, L) => {
	if (F.unrepresentable === "throw") throw Error("Void cannot be represented in JSON Schema");
}, neverProcessor = (l, F, I, L) => {
	I.not = {};
}, anyProcessor = (l, F, I, L) => {}, unknownProcessor = (l, F, I, L) => {}, dateProcessor = (l, F, I, L) => {
	if (F.unrepresentable === "throw") throw Error("Date cannot be represented in JSON Schema");
}, enumProcessor = (F, I, L, R) => {
	let z = F._zod.def, B = getEnumValues(z.entries);
	B.every((l) => typeof l == "number") && (L.type = "number"), B.every((l) => typeof l == "string") && (L.type = "string"), L.enum = B;
}, literalProcessor = (l, F, I, L) => {
	let R = l._zod.def, z = [];
	for (let l of R.values) if (l === void 0) {
		if (F.unrepresentable === "throw") throw Error("Literal `undefined` cannot be represented in JSON Schema");
	} else if (typeof l == "bigint") {
		if (F.unrepresentable === "throw") throw Error("BigInt literals cannot be represented in JSON Schema");
		z.push(Number(l));
	} else z.push(l);
	if (z.length !== 0) if (z.length === 1) {
		let l = z[0];
		I.type = l === null ? "null" : typeof l, F.target === "draft-04" || F.target === "openapi-3.0" ? I.enum = [l] : I.const = l;
	} else z.every((l) => typeof l == "number") && (I.type = "number"), z.every((l) => typeof l == "string") && (I.type = "string"), z.every((l) => typeof l == "boolean") && (I.type = "boolean"), z.every((l) => l === null) && (I.type = "null"), I.enum = z;
}, nanProcessor = (l, F, I, L) => {
	if (F.unrepresentable === "throw") throw Error("NaN cannot be represented in JSON Schema");
}, templateLiteralProcessor = (l, F, I, L) => {
	let R = I, z = l._zod.pattern;
	if (!z) throw Error("Pattern not found in template literal");
	R.type = "string", R.pattern = z.source;
}, fileProcessor = (l, F, I, L) => {
	let R = I, z = {
		type: "string",
		format: "binary",
		contentEncoding: "binary"
	}, { minimum: B, maximum: V, mime: H } = l._zod.bag;
	B !== void 0 && (z.minLength = B), V !== void 0 && (z.maxLength = V), H ? H.length === 1 ? (z.contentMediaType = H[0], Object.assign(R, z)) : (Object.assign(R, z), R.anyOf = H.map((l) => ({ contentMediaType: l }))) : Object.assign(R, z);
}, successProcessor = (l, F, I, L) => {
	I.type = "boolean";
}, customProcessor = (l, F, I, L) => {
	if (F.unrepresentable === "throw") throw Error("Custom types cannot be represented in JSON Schema");
}, functionProcessor = (l, F, I, L) => {
	if (F.unrepresentable === "throw") throw Error("Function types cannot be represented in JSON Schema");
}, transformProcessor = (l, F, I, L) => {
	if (F.unrepresentable === "throw") throw Error("Transforms cannot be represented in JSON Schema");
}, mapProcessor = (l, F, I, L) => {
	if (F.unrepresentable === "throw") throw Error("Map cannot be represented in JSON Schema");
}, setProcessor = (l, F, I, L) => {
	if (F.unrepresentable === "throw") throw Error("Set cannot be represented in JSON Schema");
}, arrayProcessor = (l, F, I, L) => {
	let z = I, B = l._zod.def, { minimum: V, maximum: H } = l._zod.bag;
	typeof V == "number" && (z.minItems = V), typeof H == "number" && (z.maxItems = H), z.type = "array", z.items = process(B.element, F, {
		...L,
		path: [...L.path, "items"]
	});
}, objectProcessor = (l, F, I, L) => {
	let z = I, B = l._zod.def;
	z.type = "object", z.properties = {};
	let V = B.shape;
	for (let l in V) z.properties[l] = process(V[l], F, {
		...L,
		path: [
			...L.path,
			"properties",
			l
		]
	});
	let H = new Set(Object.keys(V)), U = new Set([...H].filter((l) => {
		let I = B.shape[l]._zod;
		return F.io === "input" ? I.optin === void 0 : I.optout === void 0;
	}));
	U.size > 0 && (z.required = Array.from(U)), B.catchall?._zod.def.type === "never" ? z.additionalProperties = !1 : B.catchall ? B.catchall && (z.additionalProperties = process(B.catchall, F, {
		...L,
		path: [...L.path, "additionalProperties"]
	})) : F.io === "output" && (z.additionalProperties = !1);
}, unionProcessor = (l, F, I, L) => {
	let z = l._zod.def, B = z.inclusive === !1, V = z.options.map((l, I) => process(l, F, {
		...L,
		path: [
			...L.path,
			B ? "oneOf" : "anyOf",
			I
		]
	}));
	B ? I.oneOf = V : I.anyOf = V;
}, intersectionProcessor = (l, F, I, L) => {
	let z = l._zod.def, B = process(z.left, F, {
		...L,
		path: [
			...L.path,
			"allOf",
			0
		]
	}), V = process(z.right, F, {
		...L,
		path: [
			...L.path,
			"allOf",
			1
		]
	}), H = (l) => "allOf" in l && Object.keys(l).length === 1;
	I.allOf = [...H(B) ? B.allOf : [B], ...H(V) ? V.allOf : [V]];
}, tupleProcessor = (l, F, I, L) => {
	let z = I, B = l._zod.def;
	z.type = "array";
	let V = F.target === "draft-2020-12" ? "prefixItems" : "items", H = F.target === "draft-2020-12" || F.target === "openapi-3.0" ? "items" : "additionalItems", U = B.items.map((l, I) => process(l, F, {
		...L,
		path: [
			...L.path,
			V,
			I
		]
	})), W = B.rest ? process(B.rest, F, {
		...L,
		path: [
			...L.path,
			H,
			...F.target === "openapi-3.0" ? [B.items.length] : []
		]
	}) : null;
	F.target === "draft-2020-12" ? (z.prefixItems = U, W && (z.items = W)) : F.target === "openapi-3.0" ? (z.items = { anyOf: U }, W && z.items.anyOf.push(W), z.minItems = U.length, W || (z.maxItems = U.length)) : (z.items = U, W && (z.additionalItems = W));
	let { minimum: G, maximum: K } = l._zod.bag;
	typeof G == "number" && (z.minItems = G), typeof K == "number" && (z.maxItems = K);
}, recordProcessor = (l, F, I, L) => {
	let z = I, B = l._zod.def;
	z.type = "object";
	let V = B.keyType, H = V._zod.bag?.patterns;
	if (B.mode === "loose" && H && H.size > 0) {
		let l = process(B.valueType, F, {
			...L,
			path: [
				...L.path,
				"patternProperties",
				"*"
			]
		});
		z.patternProperties = {};
		for (let F of H) z.patternProperties[F.source] = l;
	} else (F.target === "draft-07" || F.target === "draft-2020-12") && (z.propertyNames = process(B.keyType, F, {
		...L,
		path: [...L.path, "propertyNames"]
	})), z.additionalProperties = process(B.valueType, F, {
		...L,
		path: [...L.path, "additionalProperties"]
	});
	let U = V._zod.values;
	if (U) {
		let l = [...U].filter((l) => typeof l == "string" || typeof l == "number");
		l.length > 0 && (z.required = l);
	}
}, nullableProcessor = (l, F, I, L) => {
	let z = l._zod.def, B = process(z.innerType, F, L), V = F.seen.get(l);
	F.target === "openapi-3.0" ? (V.ref = z.innerType, I.nullable = !0) : I.anyOf = [B, { type: "null" }];
}, nonoptionalProcessor = (l, F, I, L) => {
	let z = l._zod.def;
	process(z.innerType, F, L);
	let B = F.seen.get(l);
	B.ref = z.innerType;
}, defaultProcessor = (l, F, I, L) => {
	let z = l._zod.def;
	process(z.innerType, F, L);
	let B = F.seen.get(l);
	B.ref = z.innerType, I.default = JSON.parse(JSON.stringify(z.defaultValue));
}, prefaultProcessor = (l, F, I, L) => {
	let z = l._zod.def;
	process(z.innerType, F, L);
	let B = F.seen.get(l);
	B.ref = z.innerType, F.io === "input" && (I._prefault = JSON.parse(JSON.stringify(z.defaultValue)));
}, catchProcessor = (l, F, I, L) => {
	let z = l._zod.def;
	process(z.innerType, F, L);
	let B = F.seen.get(l);
	B.ref = z.innerType;
	let V;
	try {
		V = z.catchValue(void 0);
	} catch {
		throw Error("Dynamic catch values are not supported in JSON Schema");
	}
	I.default = V;
}, pipeProcessor = (l, F, I, L) => {
	let z = l._zod.def, B = F.io === "input" ? z.in._zod.def.type === "transform" ? z.out : z.in : z.out;
	process(B, F, L);
	let V = F.seen.get(l);
	V.ref = B;
}, readonlyProcessor = (l, F, I, L) => {
	let z = l._zod.def;
	process(z.innerType, F, L);
	let B = F.seen.get(l);
	B.ref = z.innerType, I.readOnly = !0;
}, promiseProcessor = (l, F, I, L) => {
	let z = l._zod.def;
	process(z.innerType, F, L);
	let B = F.seen.get(l);
	B.ref = z.innerType;
}, optionalProcessor = (l, F, I, L) => {
	let z = l._zod.def;
	process(z.innerType, F, L);
	let B = F.seen.get(l);
	B.ref = z.innerType;
}, lazyProcessor = (l, F, I, L) => {
	let z = l._zod.innerType;
	process(z, F, L);
	let B = F.seen.get(l);
	B.ref = z;
}, allProcessors = {
	string: stringProcessor,
	number: numberProcessor,
	boolean: booleanProcessor,
	bigint: bigintProcessor,
	symbol: symbolProcessor,
	null: nullProcessor,
	undefined: undefinedProcessor,
	void: voidProcessor,
	never: neverProcessor,
	any: anyProcessor,
	unknown: unknownProcessor,
	date: dateProcessor,
	enum: enumProcessor,
	literal: literalProcessor,
	nan: nanProcessor,
	template_literal: templateLiteralProcessor,
	file: fileProcessor,
	success: successProcessor,
	custom: customProcessor,
	function: functionProcessor,
	transform: transformProcessor,
	map: mapProcessor,
	set: setProcessor,
	array: arrayProcessor,
	object: objectProcessor,
	union: unionProcessor,
	intersection: intersectionProcessor,
	tuple: tupleProcessor,
	record: recordProcessor,
	nullable: nullableProcessor,
	nonoptional: nonoptionalProcessor,
	default: defaultProcessor,
	prefault: prefaultProcessor,
	catch: catchProcessor,
	pipe: pipeProcessor,
	readonly: readonlyProcessor,
	promise: promiseProcessor,
	optional: optionalProcessor,
	lazy: lazyProcessor
};
function toJSONSchema(l, z) {
	if ("_idmap" in l) {
		let B = l, V = initializeContext({
			...z,
			processors: allProcessors
		}), H = {};
		for (let l of B._idmap.entries()) {
			let [F, I] = l;
			process(I, V);
		}
		let U = {};
		V.external = {
			registry: B,
			uri: z?.uri,
			defs: H
		};
		for (let l of B._idmap.entries()) {
			let [L, R] = l;
			extractDefs(V, R), U[L] = finalize(V, R);
		}
		return Object.keys(H).length > 0 && (U.__shared = { [V.target === "draft-2020-12" ? "$defs" : "definitions"]: H }), { schemas: U };
	}
	let B = initializeContext({
		...z,
		processors: allProcessors
	});
	return process(l, B), extractDefs(B, l), finalize(B, l);
}
export { arrayProcessor, booleanProcessor, catchProcessor, customProcessor, defaultProcessor, enumProcessor, intersectionProcessor, lazyProcessor, literalProcessor, neverProcessor, nonoptionalProcessor, nullProcessor, nullableProcessor, numberProcessor, objectProcessor, optionalProcessor, pipeProcessor, prefaultProcessor, readonlyProcessor, recordProcessor, stringProcessor, toJSONSchema, transformProcessor, unionProcessor, unknownProcessor };
