import { ensureError } from "../types/errors.js";
import { EndpointBuilder } from "./endpoint.js";
import { tryCreateContextualLogger } from "./handlers/utils.js";
import { createRestateHandler } from "./handlers/generic.js";
import * as http2 from "node:http2";

//#region src/endpoint/node_endpoint.ts
var NodeEndpoint = class {
	builder = new EndpointBuilder();
	bind(definition) {
		this.builder.bind(definition);
		return this;
	}
	withIdentityV1(...keys) {
		this.builder.addIdentityKeys(...keys);
		return this;
	}
	defaultServiceOptions(options) {
		this.builder.setDefaultServiceOptions(options);
		return this;
	}
	setLogger(logger) {
		this.builder.setLogger(logger);
		return this;
	}
	journalValueCodecProvider(codecProvider) {
		this.builder.setJournalValueCodecProvider(codecProvider);
		return this;
	}
	http2Handler(options) {
		return nodeHttp2Handler(this.builder.build(), options?.bidirectional === false ? "REQUEST_RESPONSE" : "BIDI_STREAM");
	}
	http1Handler(options) {
		return nodeHttp1Handler(this.builder.build(), options?.bidirectional ? "BIDI_STREAM" : "REQUEST_RESPONSE");
	}
	handler(options) {
		const endpoint = this.builder.build();
		const h2Handler = nodeHttp2Handler(endpoint, options?.bidirectional === false ? "REQUEST_RESPONSE" : "BIDI_STREAM");
		const h1Handler = nodeHttp1Handler(endpoint, options?.bidirectional ? "BIDI_STREAM" : "REQUEST_RESPONSE");
		return ((request, response) => {
			if (request.httpVersionMajor >= 2) h2Handler(request, response);
			else h1Handler(request, response);
		});
	}
	listen(port) {
		const endpoint = this.builder.build();
		const actualPort = port ?? parseInt(process.env.PORT ?? "9080");
		endpoint.rlog.info(`Restate SDK started listening on ${actualPort}...`);
		const server = http2.createServer(nodeHttp2Handler(endpoint, "BIDI_STREAM"));
		return new Promise((resolve, reject) => {
			let failed = false;
			server.once("error", (e) => {
				failed = true;
				reject(e);
			});
			server.listen(actualPort, () => {
				if (failed) return;
				const address = server.address();
				if (address === null || typeof address === "string") reject(/* @__PURE__ */ new TypeError("endpoint.listen() currently supports only binding to a PORT"));
				else resolve(address.port);
			});
		});
	}
};
function nodeHttp1Handler(endpoint, protocolMode) {
	return nodeHandlerImpl(endpoint, protocolMode);
}
function nodeHttp2Handler(endpoint, protocolMode) {
	return nodeHandlerImpl(endpoint, protocolMode);
}
function nodeHandlerImpl(endpoint, protocolMode) {
	const handler = createRestateHandler(endpoint, protocolMode, {});
	return (httpRequest, httpResponse) => {
		const url = httpRequest.url;
		const inputReader = inputReaderAdapter(httpRequest);
		const outputWriter = outputWriterAdapter(httpResponse);
		const res = httpResponse;
		const abortController = new AbortController();
		httpRequest.on("close", () => {
			abortController.abort();
		});
		const writeHead = res.writeHead.bind(res);
		handler.handle({
			url,
			headers: httpRequest.headers,
			extraArgs: []
		}).process({
			inputReader,
			outputWriter,
			writeHead,
			abortSignal: abortController.signal
		}).catch((e) => {
			const error = ensureError(e);
			(tryCreateContextualLogger(endpoint.loggerTransport, url, httpRequest.headers) ?? endpoint.rlog).error("Unexpected error: " + (error.stack ?? error.message));
		});
	};
}
function inputReaderAdapter(request) {
	return request[Symbol.asyncIterator]();
}
function outputWriterAdapter(response) {
	const res = response;
	return {
		write: function(value) {
			return new Promise((resolve, reject) => {
				res.write(value, (err) => err ? reject(err) : resolve());
			});
		},
		close: function() {
			return new Promise((resolve) => {
				res.end(() => resolve());
			});
		}
	};
}

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