import { ERRORS, normalizeError } from "../../../../libs/errors.js";
import { normalizeHeaders } from "../../../../libs/normalize-headers.js";
import { getCookieHeaderKeys } from "./get-cookie-header-keys.js";
import { decodeBuffer } from "./decode-buffer.js";
import { executeHook } from "@scalar/oas-utils/helpers";
import { httpStatusCodes as httpStatusCodes$1 } from "@scalar/helpers/http/http-status-codes";
//#region src/v2/blocks/operation-block/helpers/send-request.ts
/** HTTP status codes that should not include a response body */
var NO_BODY_STATUS_CODES = [
	204,
	205,
	304
];
/**
* Execute the built fetch request and return a structured response.
*
* This function handles the complete request lifecycle including plugin hooks,
* response processing, streaming detection, and error handling. It supports both
* standard responses and server-sent event streams.
*
* @param request - The request built by the buildRequest helper
* @param operation - The OpenAPI operation being executed
* @param plugins - Array of client plugins to execute hooks
* @param isUsingProxy - Whether the request is being proxied for header handling
* @returns A tuple with either an error or the response data
*/
var sendRequest = async ({ isUsingProxy, operation, request, plugins }) => {
	try {
		const { request: modifiedRequest } = await executeHook({ request }, "beforeRequest", plugins);
		const startTime = Date.now();
		const response = await fetch(modifiedRequest.clone());
		const endTime = Date.now();
		const duration = endTime - startTime;
		const contentType = response.headers.get("content-type");
		const responseHeaders = normalizeHeaders(response.headers, isUsingProxy);
		const responseUrl = new URL(response.url);
		const fullPath = responseUrl.pathname + responseUrl.search;
		const statusText = response.statusText || httpStatusCodes$1[response.status]?.name || "";
		const method = modifiedRequest.method;
		const shouldSkipBody = NO_BODY_STATUS_CODES.includes(response.status);
		/**
		* Handle server-sent event streams separately.
		* These responses need a reader instead of buffered data.
		* We check this early to avoid unnecessary body reading.
		*/
		if (contentType?.startsWith("text/event-stream") && response.body) return buildStreamingResponse({
			response,
			modifiedRequest,
			operation,
			plugins,
			endTime,
			duration,
			responseHeaders,
			statusText,
			method,
			fullPath
		});
		return buildStandardResponse({
			response,
			modifiedRequest,
			operation,
			plugins,
			endTime,
			duration,
			responseHeaders,
			statusText,
			method,
			fullPath,
			contentType,
			shouldSkipBody
		});
	} catch (error) {
		return [normalizeError(error, ERRORS.REQUEST_FAILED), null];
	}
};
/**
* Build a streaming response for server-sent events.
* Streaming responses use a reader instead of buffering the entire body.
*/
var buildStreamingResponse = async ({ response, modifiedRequest, operation, plugins, endTime, duration, responseHeaders, statusText, method, fullPath }) => {
	const normalizedResponse = new Response(null, {
		status: response.status,
		statusText,
		headers: response.headers
	});
	await executeHook({
		response: normalizedResponse,
		request: modifiedRequest,
		operation
	}, "responseReceived", plugins);
	const cookieHeaderKeys = getCookieHeaderKeys(normalizedResponse.headers);
	return [null, {
		timestamp: endTime,
		request: modifiedRequest,
		response: {
			...normalizedResponse,
			headers: responseHeaders,
			cookieHeaderKeys,
			reader: response.body.getReader(),
			duration,
			method,
			path: fullPath
		},
		originalResponse: normalizedResponse.clone()
	}];
};
/**
* Build a standard response with buffered body data.
* This handles all non-streaming responses including JSON, text, and binary data.
*/
var buildStandardResponse = async ({ response, modifiedRequest, operation, plugins, endTime, duration, responseHeaders, statusText, method, fullPath, contentType, shouldSkipBody }) => {
	const arrayBuffer = await response.clone().arrayBuffer();
	const responseData = decodeBuffer(arrayBuffer, contentType ?? "text/plain;charset=UTF-8");
	/**
	* Create a new Response using the arrayBuffer we already read.
	* ArrayBuffers can be reused to create new Response objects without additional memory.
	*/
	const normalizedResponse = new Response(shouldSkipBody ? null : arrayBuffer, {
		status: response.status,
		statusText,
		headers: response.headers
	});
	await executeHook({
		response: normalizedResponse,
		request: modifiedRequest,
		operation
	}, "responseReceived", plugins);
	const cookieHeaderKeys = getCookieHeaderKeys(normalizedResponse.headers);
	return [null, {
		timestamp: endTime,
		request: modifiedRequest,
		response: {
			...normalizedResponse,
			headers: responseHeaders,
			cookieHeaderKeys,
			data: responseData,
			size: arrayBuffer.byteLength,
			duration,
			method,
			status: response.status,
			path: fullPath
		},
		originalResponse: response.clone()
	}];
};
//#endregion
export { sendRequest };

//# sourceMappingURL=send-request.js.map