"use strict";
/* Socket Lib - Built with rolldown */
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_primordials_error = require('../primordials/error.js');
const require_primordials_math = require('../primordials/math.js');
const require_primordials_number = require('../primordials/number.js');
const require_http_request_request_attempt = require('./request-attempt.js');
const require_http_request_response_types = require('./response-types.js');
const require_http_request_response_reader = require('./response-reader.js');
let node_timers_promises = require("node:timers/promises");

//#region src/http-request/request.ts
/**
* @file Core HTTP/HTTPS request loop — the retry orchestrator. `httpRequest` is
*   the main entry point: it wraps `httpRequestAttempt` with retry /
*   exponential-backoff logic and an optional `onRetry` callback. Heavy lifting
*   lives in sibling leaves and is re-exported here so existing
*   `http-request/request` importers keep working unchanged:
*
*   - `httpRequestAttempt` — single attempt + redirect chasing —
*     `./request-attempt`
*   - `readIncomingResponse` — IncomingMessage → HttpResponse —
*     `./response-reader`
*/
/**
* Make an HTTP/HTTPS request with retry logic and redirect support. Provides a
* fetch-like API using Node.js native http/https modules.
*
* This is the main entry point for making HTTP requests. It handles retries,
* redirects, timeouts, and provides a fetch-compatible response interface.
*
* @example
*   ;```ts
*   // Simple GET request
*   const response = await httpRequest('https://api.example.com/data')
*   const data = response.json()
*
*   // POST with JSON body
*   const response = await httpRequest('https://api.example.com/users', {
*     method: 'POST',
*     headers: { 'Content-Type': 'application/json' },
*     body: JSON.stringify({ name: 'Alice', email: 'alice@example.com' }),
*   })
*
*   // With retries and timeout
*   const response = await httpRequest('https://api.example.com/data', {
*     retries: 3,
*     retryDelay: 1000,
*     timeout: 60000,
*   })
*
*   // Don't follow redirects
*   const response = await httpRequest('https://example.com/redirect', {
*     followRedirects: false,
*   })
*   console.log(response.status) // 301, 302, etc.
*   ```
*
* @param url - The URL to request (must start with http:// or https://)
* @param options - Request configuration options.
*
* @returns Promise resolving to response object with `.json()`, `.text()`, etc.
*
* @throws {Error} When all retries are exhausted, timeout occurs, or
*   non-retryable error happens.
*/
async function httpRequest(url, options) {
	const { body, ca, followRedirects = true, headers = {}, hooks, maxRedirects = 5, maxResponseSize, method = "GET", onRetry, retries = 0, retryDelay = 1e3, signal, stream = false, throwOnError = false, timeout = 3e4 } = {
		__proto__: null,
		...options
	};
	const isStreamBody = body !== void 0 && typeof body === "object" && typeof body.pipe === "function";
	if (isStreamBody && retries > 0) throw new require_primordials_error.ErrorCtor("Streaming body (Readable/FormData) cannot be used with retries. Streams are consumed on first attempt and cannot be replayed. Set retries: 0 or buffer the body as a string/Buffer.");
	const baseAttemptOpts = {
		body,
		ca,
		followRedirects: isStreamBody ? false : followRedirects,
		headers,
		hooks,
		maxRedirects,
		maxResponseSize,
		method,
		signal,
		stream,
		timeout
	};
	let lastError;
	let lastDelaySeconds = 0;
	for (let attempt = 0; attempt <= retries; attempt++) {
		const attemptOpts = attempt > 0 ? {
			...baseAttemptOpts,
			headers: {
				...headers,
				"Retry-Attempt": `${attempt}`,
				"Retry-Max": `${retries}`,
				"Retry-After": `${lastDelaySeconds}`
			}
		} : baseAttemptOpts;
		try {
			const response = await require_http_request_request_attempt.httpRequestAttempt(url, attemptOpts);
			if (throwOnError && !response.ok) throw new require_http_request_response_types.HttpResponseError(response);
			return response;
		} catch (e) {
			lastError = e;
			if (attempt === retries) break;
			if (signal?.aborted) break;
			const delayMs = retryDelay * 2 ** attempt;
			if (onRetry) {
				const retryResult = onRetry(attempt + 1, e, delayMs);
				if (retryResult === false) break;
				const actualDelay = typeof retryResult === "number" && !require_primordials_number.NumberIsNaN(retryResult) ? require_primordials_math.MathMax(0, retryResult) : delayMs;
				lastDelaySeconds = require_primordials_math.MathRound(actualDelay / 1e3);
				await (0, node_timers_promises.setTimeout)(actualDelay);
			} else {
				lastDelaySeconds = require_primordials_math.MathRound(delayMs / 1e3);
				await (0, node_timers_promises.setTimeout)(delayMs);
			}
		}
	}
	throw lastError || new require_primordials_error.ErrorCtor("Request failed after retries");
}

//#endregion
exports.httpRequest = httpRequest;
exports.httpRequestAttempt = require_http_request_request_attempt.httpRequestAttempt;
exports.readIncomingResponse = require_http_request_response_reader.readIncomingResponse;