import { createLogger } from "../../utils/logger/index.js";
import { init_logger } from "../../utils/logger.js";
//#region src/agent/lifecycle/timeout-wrapper.ts
init_logger();
const log = createLogger("TimeoutWrapper");
const DEFAULT_CONFIG = {
	defaultTimeoutMs: 300 * 1e3,
	shellTimeoutMs: 300 * 1e3,
	readTimeoutMs: 30 * 1e3,
	writeTimeoutMs: 60 * 1e3,
	networkTimeoutMs: 60 * 1e3,
	gracefulShutdownMs: 5e3
};
/**
* Get timeout for specific tool type
*/
function getTimeoutForTool(toolName, config) {
	const toolLower = toolName.toLowerCase();
	if (toolLower.includes("shell") || toolLower.includes("exec")) return config.shellTimeoutMs;
	if (toolLower.includes("read") || toolLower.includes("view")) return config.readTimeoutMs;
	if (toolLower.includes("write") || toolLower.includes("edit")) return config.writeTimeoutMs;
	if (toolLower.includes("web") || toolLower.includes("http") || toolLower.includes("fetch")) return config.networkTimeoutMs;
	return config.defaultTimeoutMs;
}
/**
* Execute function with timeout protection
*
* @example
* ```typescript
* const result = await executeWithTimeout(
*   () => shell.exec('long-running-command'),
*   { toolName: 'shell', timeoutMs: 60000 }
* );
* ```
*/
async function executeWithTimeout(operation, config) {
	const fullConfig = { ...DEFAULT_CONFIG };
	const timeoutMs = config.timeoutMs || getTimeoutForTool(config.toolName, fullConfig);
	const startTime = Date.now();
	let timeoutId = null;
	let isSettled = false;
	return new Promise((resolve, reject) => {
		timeoutId = setTimeout(() => {
			if (isSettled) return;
			isSettled = true;
			const executionTime = Date.now() - startTime;
			const desc = config.description ? ` (${config.description})` : "";
			log.error({
				toolName: config.toolName,
				timeoutMs,
				executionTimeMs: executionTime,
				description: config.description
			}, `Tool "${config.toolName}" timed out after ${timeoutMs}ms (elapsed ${executionTime}ms)${desc}`);
			reject(new TimeoutError(config.toolName, timeoutMs, config.description, executionTime));
		}, timeoutMs);
		operation().then((result) => {
			if (isSettled) return;
			isSettled = true;
			if (timeoutId) {
				clearTimeout(timeoutId);
				timeoutId = null;
			}
			const executionTime = Date.now() - startTime;
			log.debug({
				toolName: config.toolName,
				executionTimeMs: executionTime
			}, "Tool execution completed within timeout");
			resolve(result);
		}).catch((error) => {
			if (isSettled) return;
			isSettled = true;
			if (timeoutId) {
				clearTimeout(timeoutId);
				timeoutId = null;
			}
			reject(error);
		});
	});
}
/**
* Execute with timeout and return detailed result
*/
async function executeWithTimeoutResult(operation, config) {
	const startTime = Date.now();
	try {
		return {
			success: true,
			result: await executeWithTimeout(operation, config),
			timedOut: false,
			executionTimeMs: Date.now() - startTime
		};
	} catch (error) {
		const isTimeout = error instanceof TimeoutError;
		return {
			success: false,
			error: error instanceof Error ? error : new Error(String(error)),
			timedOut: isTimeout,
			executionTimeMs: Date.now() - startTime
		};
	}
}
/**
* Custom timeout error
*/
var TimeoutError = class TimeoutError extends Error {
	toolName;
	timeoutMs;
	executionTimeMs;
	description;
	constructor(toolName, timeoutMs, description, executionTimeMs = timeoutMs) {
		const timeoutSec = Math.round(timeoutMs / 1e3);
		const message = description ? `Tool '${toolName}' timed out after ${timeoutSec}s: ${description}` : `Tool '${toolName}' timed out after ${timeoutSec}s. Consider breaking the operation into smaller steps.`;
		super(message);
		this.name = "TimeoutError";
		this.toolName = toolName;
		this.timeoutMs = timeoutMs;
		this.description = description;
		this.executionTimeMs = executionTimeMs;
		if (Error.captureStackTrace) Error.captureStackTrace(this, TimeoutError);
	}
	/**
	* Get user-friendly error message with suggestions
	*/
	getUserMessage() {
		const suggestions = [];
		if (this.toolName.toLowerCase().includes("shell")) {
			suggestions.push("Break the command into smaller steps");
			suggestions.push("Add timeouts to individual commands");
			suggestions.push("Check for infinite loops or waiting for input");
		} else if (this.toolName.toLowerCase().includes("read")) {
			suggestions.push("Read the file in smaller chunks");
			suggestions.push("Use grep to find specific content first");
		} else if (this.toolName.toLowerCase().includes("write")) suggestions.push("Write content in smaller batches");
		else if (this.toolName.toLowerCase().includes("web")) {
			suggestions.push("Check network connectivity");
			suggestions.push("Try again later");
		}
		let message = `⚠️ ${this.message}`;
		if (suggestions.length > 0) message += "\n\nSuggestions:\n" + suggestions.map((s) => `• ${s}`).join("\n");
		return message;
	}
};
/**
* Wrap a function with timeout protection
*/
function withTimeout(fn, config) {
	return async (...args) => {
		const description = typeof config.description === "function" ? config.description(...args) : config.description;
		return executeWithTimeout(() => fn(...args), {
			toolName: config.toolName,
			timeoutMs: config.timeoutMs,
			description
		});
	};
}
/**
* Timeout manager for tracking execution statistics
*/
var TimeoutManager = class {
	config;
	executions = [];
	constructor(config = {}) {
		this.config = {
			...DEFAULT_CONFIG,
			...config
		};
	}
	/**
	* Execute with timeout and track statistics
	*/
	async execute(operation, toolConfig) {
		const startTime = Date.now();
		let timedOut = false;
		try {
			const result = await executeWithTimeout(operation, toolConfig);
			this.executions.push({
				toolName: toolConfig.toolName,
				executionTimeMs: Date.now() - startTime,
				timedOut: false,
				timestamp: Date.now()
			});
			return result;
		} catch (error) {
			if (error instanceof TimeoutError) timedOut = true;
			this.executions.push({
				toolName: toolConfig.toolName,
				executionTimeMs: Date.now() - startTime,
				timedOut,
				timestamp: Date.now()
			});
			throw error;
		}
	}
	/**
	* Get execution statistics
	*/
	getStats() {
		const byTool = {};
		for (const exec of this.executions) {
			if (!byTool[exec.toolName]) byTool[exec.toolName] = {
				count: 0,
				timeouts: 0,
				totalTime: 0
			};
			byTool[exec.toolName].count++;
			if (exec.timedOut) byTool[exec.toolName].timeouts++;
			byTool[exec.toolName].totalTime += exec.executionTimeMs;
		}
		const totalExecutions = this.executions.length;
		const timeoutCount = this.executions.filter((e) => e.timedOut).length;
		const totalTime = this.executions.reduce((sum, e) => sum + e.executionTimeMs, 0);
		return {
			totalExecutions,
			timeoutCount,
			timeoutRate: totalExecutions > 0 ? timeoutCount / totalExecutions : 0,
			averageExecutionTimeMs: totalExecutions > 0 ? totalTime / totalExecutions : 0,
			byTool: Object.fromEntries(Object.entries(byTool).map(([name, stats]) => [name, {
				count: stats.count,
				timeouts: stats.timeouts,
				avgExecutionTimeMs: stats.count > 0 ? stats.totalTime / stats.count : 0
			}]))
		};
	}
	/**
	* Clean up old execution records
	*/
	cleanup(maxAgeMs = 1440 * 60 * 1e3) {
		const cutoff = Date.now() - maxAgeMs;
		this.executions = this.executions.filter((e) => e.timestamp > cutoff);
	}
};
//#endregion
export { DEFAULT_CONFIG as DEFAULT_TIMEOUT_CONFIG, TimeoutError, TimeoutManager, executeWithTimeout, executeWithTimeoutResult, withTimeout };

//# sourceMappingURL=timeout-wrapper.js.map