import { HandlerKind } from "../types/rpc.js";
import { millisOrDurationToMillis, serde } from "@restatedev/restate-sdk-core";

//#region src/endpoint/components.ts
function handlerInputDiscovery(handler, defaultSerde) {
	const serde$1 = handler.options?.input ?? defaultSerde;
	let contentType = void 0;
	let jsonSchema = void 0;
	if (serde$1.jsonSchema) {
		jsonSchema = serde$1.jsonSchema;
		contentType = handler.options?.accept ?? serde$1.contentType;
	} else if (handler.options?.accept) contentType = handler.options?.accept;
	else if (serde$1.contentType) contentType = serde$1.contentType;
	else return {};
	return {
		required: false,
		contentType,
		jsonSchema
	};
}
function handlerOutputDiscovery(handler, defaultSerde) {
	const serde$1 = handler.options?.output ?? defaultSerde;
	const setContentTypeIfEmpty = handler.options?.setOutputContentTypeIfEmpty ?? false;
	let contentType = void 0;
	let jsonSchema = void 0;
	if (serde$1.jsonSchema) {
		jsonSchema = serde$1.jsonSchema;
		contentType = serde$1.contentType ?? "application/json";
	} else if (serde$1.contentType) contentType = serde$1.contentType;
	else return { setContentTypeIfEmpty };
	return {
		setContentTypeIfEmpty,
		jsonSchema,
		contentType
	};
}
function createExecutionOptions(serviceOptions, handlerOptions) {
	const defaultSerde = handlerOptions?.serde ?? serviceOptions?.serde ?? serde.json;
	const hooks = [...serviceOptions?.hooks ?? [], ...handlerOptions?.hooks ?? []];
	return {
		defaultSerde,
		asTerminalError: handlerOptions?.asTerminalError ?? serviceOptions?.asTerminalError,
		hooks: hooks.length > 0 ? hooks : void 0,
		explicitCancellation: handlerOptions?.explicitCancellation ?? serviceOptions?.explicitCancellation
	};
}
const PREVIEW_METADATA_KEY_PREFIX = "dev.restate.serde.preview";
/**
* Service-scoped serde namespace.
*
* Today it is populated from handler inputs/outputs under `<handler>/input`
* and `<handler>/output`. Custom service-level serdes can be registered
* alongside them under any name.
*/
var ServiceSerdeRegistry = class {
	serdes = /* @__PURE__ */ new Map();
	registerHandlerIO(handlerName, wrapper, executionOptions) {
		this.serdes.set(`${handlerName}/input`, wrapper.options?.input ?? executionOptions.defaultSerde);
		this.serdes.set(`${handlerName}/output`, wrapper.options?.output ?? executionOptions.defaultSerde);
	}
	resolve(name) {
		return this.serdes.get(name);
	}
	previewMetadata() {
		const metadata = {};
		for (const [name, s] of this.serdes) if (s.preview) metadata[`${PREVIEW_METADATA_KEY_PREFIX}.${name}`] = "true";
		return Object.keys(metadata).length > 0 ? metadata : void 0;
	}
};
function mergeMetadata(baseMetadata, additionalMetadata) {
	if (!baseMetadata && !additionalMetadata) return;
	return {
		...baseMetadata ?? {},
		...additionalMetadata ?? {}
	};
}
var ServiceComponent = class {
	handlers = /* @__PURE__ */ new Map();
	serdeRegistry = new ServiceSerdeRegistry();
	constructor(componentName, description, metadata, options) {
		this.componentName = componentName;
		this.description = description;
		this.metadata = metadata;
		this.options = options;
	}
	name() {
		return this.componentName;
	}
	add(name, handlerWrapper) {
		const handler = new ServiceHandler$1(name, handlerWrapper, this);
		this.handlers.set(name, handler);
		this.serdeRegistry.registerHandlerIO(name, handlerWrapper, handler.executionOptions);
	}
	discovery() {
		const handlers = [...this.handlers.entries()].map(([name, handler]) => {
			return {
				name,
				...commonHandlerOptions(handler.handlerWrapper, handler.executionOptions.defaultSerde)
			};
		});
		return {
			name: this.componentName,
			ty: "SERVICE",
			handlers,
			documentation: this.description,
			metadata: mergeMetadata(this.metadata, this.serdeRegistry.previewMetadata()),
			...commonServiceOptions(this.options)
		};
	}
	handlerMatching(url) {
		return this.handlers.get(url.handlerName);
	}
	serdeMatching(name) {
		return this.serdeRegistry.resolve(name);
	}
};
var ServiceHandler$1 = class {
	executionOptions;
	constructor(handlerName, handlerWrapper, parent) {
		this.handlerName = handlerName;
		this.handlerWrapper = handlerWrapper;
		this.parent = parent;
		this.executionOptions = createExecutionOptions(this.parent.options, handlerWrapper.options);
	}
	name() {
		return this.handlerName;
	}
	component() {
		return this.parent;
	}
	kind() {
		return this.handlerWrapper.kind;
	}
	invoke(context, input) {
		return this.handlerWrapper.invoke(context, input);
	}
};
var VirtualObjectComponent = class {
	handlers = /* @__PURE__ */ new Map();
	serdeRegistry = new ServiceSerdeRegistry();
	constructor(componentName, description, metadata, options) {
		this.componentName = componentName;
		this.description = description;
		this.metadata = metadata;
		this.options = options;
	}
	name() {
		return this.componentName;
	}
	add(name, wrapper) {
		const handler = new VirtualObjectHandler(name, wrapper, this);
		this.handlers.set(name, handler);
		this.serdeRegistry.registerHandlerIO(name, wrapper, handler.executionOptions);
	}
	discovery() {
		const handlers = [...this.handlers.entries()].map(([name, handler]) => {
			return {
				name,
				ty: handler.kind() === HandlerKind.EXCLUSIVE ? "EXCLUSIVE" : "SHARED",
				...commonHandlerOptions(handler.handlerWrapper, handler.executionOptions.defaultSerde)
			};
		});
		return {
			name: this.componentName,
			ty: "VIRTUAL_OBJECT",
			handlers,
			documentation: this.description,
			metadata: mergeMetadata(this.metadata, this.serdeRegistry.previewMetadata()),
			...commonServiceOptions(this.options)
		};
	}
	handlerMatching(url) {
		return this.handlers.get(url.handlerName);
	}
	serdeMatching(name) {
		return this.serdeRegistry.resolve(name);
	}
};
var VirtualObjectHandler = class {
	executionOptions;
	constructor(handlerName, handlerWrapper, parent) {
		this.handlerName = handlerName;
		this.handlerWrapper = handlerWrapper;
		this.parent = parent;
		this.executionOptions = createExecutionOptions(this.parent.options, handlerWrapper.options);
	}
	name() {
		return this.handlerName;
	}
	component() {
		return this.parent;
	}
	kind() {
		return this.handlerWrapper.kind;
	}
	invoke(context, input) {
		return this.handlerWrapper.invoke(context, input);
	}
};
var WorkflowComponent = class {
	handlers = /* @__PURE__ */ new Map();
	serdeRegistry = new ServiceSerdeRegistry();
	constructor(componentName, description, metadata, options) {
		this.componentName = componentName;
		this.description = description;
		this.metadata = metadata;
		this.options = options;
	}
	name() {
		return this.componentName;
	}
	add(name, wrapper) {
		const handler = new WorkflowHandler$1(name, wrapper, this);
		this.handlers.set(name, handler);
		this.serdeRegistry.registerHandlerIO(name, wrapper, handler.executionOptions);
	}
	discovery() {
		const handlers = [...this.handlers.entries()].map(([name, handler]) => {
			return {
				name,
				ty: handler.kind() === HandlerKind.WORKFLOW ? "WORKFLOW" : "SHARED",
				workflowCompletionRetention: handler.kind() === HandlerKind.WORKFLOW && this.options?.workflowRetention !== void 0 ? millisOrDurationToMillis(this.options?.workflowRetention) : void 0,
				...commonHandlerOptions(handler.handlerWrapper, handler.executionOptions.defaultSerde)
			};
		});
		return {
			name: this.componentName,
			ty: "WORKFLOW",
			handlers,
			documentation: this.description,
			metadata: mergeMetadata(this.metadata, this.serdeRegistry.previewMetadata()),
			...commonServiceOptions(this.options)
		};
	}
	handlerMatching(url) {
		return this.handlers.get(url.handlerName);
	}
	serdeMatching(name) {
		return this.serdeRegistry.resolve(name);
	}
};
var WorkflowHandler$1 = class {
	executionOptions;
	constructor(handlerName, handlerWrapper, parent) {
		this.handlerName = handlerName;
		this.handlerWrapper = handlerWrapper;
		this.parent = parent;
		this.executionOptions = createExecutionOptions(this.parent.options, handlerWrapper.options);
	}
	name() {
		return this.handlerName;
	}
	component() {
		return this.parent;
	}
	kind() {
		return this.handlerWrapper.kind;
	}
	invoke(context, input) {
		return this.handlerWrapper.invoke(context, input);
	}
};
const PREVIEW_PATH_REGEX = /(?:^|\/)serdes\/(?<componentName>[^/]+)\/(?<operation>encode|decode)\/(?<serdeName>.+?)\/?$/;
function parseUrlComponents(urlPath) {
	if (!urlPath) return {
		type: "unknown",
		path: ""
	};
	const preview = PREVIEW_PATH_REGEX.exec(urlPath);
	if (preview?.groups) return {
		type: "preview",
		componentName: preview.groups.componentName,
		operation: preview.groups.operation,
		serdeName: decodeURIComponent(preview.groups.serdeName)
	};
	const fragments = urlPath.split("/");
	if (fragments.length >= 3 && fragments[fragments.length - 3] === "invoke") return {
		type: "invoke",
		componentName: fragments[fragments.length - 2],
		handlerName: fragments[fragments.length - 1]
	};
	if (fragments.length > 0 && fragments[fragments.length - 1] === "discover") return { type: "discover" };
	if (fragments.length > 0 && fragments[fragments.length - 1] === "health") return { type: "health" };
	return {
		type: "unknown",
		path: urlPath
	};
}
function commonServiceOptions(options) {
	return {
		journalRetention: options?.journalRetention !== void 0 ? millisOrDurationToMillis(options.journalRetention) : void 0,
		idempotencyRetention: options?.idempotencyRetention !== void 0 ? millisOrDurationToMillis(options.idempotencyRetention) : void 0,
		inactivityTimeout: options?.inactivityTimeout !== void 0 ? millisOrDurationToMillis(options.inactivityTimeout) : void 0,
		abortTimeout: options?.abortTimeout !== void 0 ? millisOrDurationToMillis(options.abortTimeout) : void 0,
		ingressPrivate: options?.ingressPrivate,
		enableLazyState: options !== void 0 && "enableLazyState" in options ? options.enableLazyState : void 0,
		retryPolicyExponentiationFactor: options?.retryPolicy?.exponentiationFactor,
		retryPolicyInitialInterval: options?.retryPolicy?.initialInterval !== void 0 ? millisOrDurationToMillis(options?.retryPolicy?.initialInterval) : void 0,
		retryPolicyMaxInterval: options?.retryPolicy?.maxInterval !== void 0 ? millisOrDurationToMillis(options?.retryPolicy?.maxInterval) : void 0,
		retryPolicyMaxAttempts: options?.retryPolicy?.maxAttempts,
		retryPolicyOnMaxAttempts: options?.retryPolicy?.onMaxAttempts === "kill" ? "KILL" : options?.retryPolicy?.onMaxAttempts === "pause" ? "PAUSE" : void 0
	};
}
function commonHandlerOptions(wrapper, defaultSerde) {
	return {
		input: handlerInputDiscovery(wrapper, defaultSerde),
		output: handlerOutputDiscovery(wrapper, defaultSerde),
		journalRetention: wrapper.options?.journalRetention !== void 0 ? millisOrDurationToMillis(wrapper.options?.journalRetention) : void 0,
		idempotencyRetention: wrapper.options?.idempotencyRetention !== void 0 ? millisOrDurationToMillis(wrapper.options?.idempotencyRetention) : void 0,
		inactivityTimeout: wrapper.options?.inactivityTimeout !== void 0 ? millisOrDurationToMillis(wrapper.options?.inactivityTimeout) : void 0,
		abortTimeout: wrapper.options?.abortTimeout !== void 0 ? millisOrDurationToMillis(wrapper.options?.abortTimeout) : void 0,
		ingressPrivate: wrapper.options?.ingressPrivate,
		enableLazyState: wrapper.options !== void 0 && "enableLazyState" in wrapper.options ? wrapper.options?.enableLazyState : void 0,
		retryPolicyExponentiationFactor: wrapper.options?.retryPolicy?.exponentiationFactor,
		retryPolicyInitialInterval: wrapper.options?.retryPolicy?.initialInterval !== void 0 ? millisOrDurationToMillis(wrapper.options?.retryPolicy?.initialInterval) : void 0,
		retryPolicyMaxInterval: wrapper.options?.retryPolicy?.maxInterval !== void 0 ? millisOrDurationToMillis(wrapper.options?.retryPolicy?.maxInterval) : void 0,
		retryPolicyMaxAttempts: wrapper.options?.retryPolicy?.maxAttempts,
		retryPolicyOnMaxAttempts: wrapper.options?.retryPolicy?.onMaxAttempts === "kill" ? "KILL" : wrapper.options?.retryPolicy?.onMaxAttempts === "pause" ? "PAUSE" : void 0,
		documentation: wrapper.options?.description,
		metadata: wrapper.options?.metadata
	};
}

//#endregion
export { ServiceComponent, VirtualObjectComponent, WorkflowComponent, parseUrlComponents };
//# sourceMappingURL=components.js.map