import { createLogger } from "../../utils/logger/index.js";
import { init_logger } from "../../utils/logger.js";
import { guardSessionManager } from "./session-tool-result-guard.js";
import { prepareSessionManagerForRun } from "./session-manager-init.js";
import { defaultSessionManagerCache } from "./session-manager-cache.js";
import { applyXopcProviderApiKey, createEmbeddedAuthStorage } from "./xopc-auth-storage.js";
import { wrapStreamFnForXopcExtensions } from "./xopc-stream-bridge.js";
import { xopcToolsToDefinitions } from "./xopc-tools-bridge.js";
import { applySystemPromptOverrideToSession } from "./system-prompt-override.js";
import { existsSync } from "node:fs";
import { DefaultResourceLoader, SessionManager, SettingsManager, createAgentSession, getAgentDir } from "@earendil-works/pi-coding-agent";
//#region src/agent/embedded/session-runner.ts
init_logger();
const log = createLogger("EmbeddedSessionRunner");
const DEFAULT_IDLE_TTL_MS = 5 * 6e4;
function buildEmbeddedRunnerFingerprint(input) {
	const tools = [...input.toolNames].sort().join("\0");
	const promptMarker = `${input.systemPrompt.length}:${input.systemPrompt.slice(0, 128)}`;
	return [
		input.sessionFile,
		input.workspaceDir,
		input.modelRef,
		tools,
		promptMarker,
		input.thinkingLevel
	].join("");
}
function isEmbeddedSessionRunnerEnabled() {
	const raw = process.env.XOPC_SESSION_RUNNER?.trim().toLowerCase();
	if (raw === "0" || raw === "false" || raw === "off") return false;
	return true;
}
function getEmbeddedSessionRunnerIdleTtlMs() {
	const raw = process.env.XOPC_SESSION_RUNNER_TTL_MS?.trim();
	if (!raw) return DEFAULT_IDLE_TTL_MS;
	const parsed = Number.parseInt(raw, 10);
	return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_IDLE_TTL_MS;
}
function createEmbeddedSettingsManager(cwd) {
	const sm = SettingsManager.inMemory({ compaction: { enabled: false } });
	sm.setCompactionEnabled(false);
	return sm;
}
/**
* Owns the per-session pool of pi `AgentSession` runners. The class is the supported,
* injectable owner; {@link defaultEmbeddedSessionRunnerPool} keeps the historic
* module-level free functions working until every caller is migrated to DI.
*/
var EmbeddedSessionRunnerPool = class {
	pool = /* @__PURE__ */ new Map();
	cache;
	isEnabledFn;
	getIdleTtlMsFn;
	stats = {
		acquires: 0,
		reuses: 0,
		creates: 0,
		evictions: 0
	};
	constructor(opts = {}) {
		this.cache = opts.sessionManagerCache ?? defaultSessionManagerCache;
		this.isEnabledFn = opts.isEnabled ?? isEmbeddedSessionRunnerEnabled;
		this.getIdleTtlMsFn = opts.getIdleTtlMs ?? getEmbeddedSessionRunnerIdleTtlMs;
	}
	getStats() {
		return {
			...this.stats,
			pooled: this.pool.size
		};
	}
	resetForTest() {
		for (const entry of this.pool.values()) this.clearIdleTimer(entry);
		this.pool.clear();
		this.stats = {
			acquires: 0,
			reuses: 0,
			creates: 0,
			evictions: 0
		};
	}
	evict(sessionKey, reason = "explicit") {
		const entry = this.pool.get(sessionKey);
		if (!entry) return;
		this.disposePooledRunner(sessionKey, entry, reason);
	}
	evictAll(reason = "dispose_all") {
		for (const sessionKey of [...this.pool.keys()]) this.evict(sessionKey, reason);
	}
	async acquire(params) {
		this.stats.acquires += 1;
		const fingerprint = buildEmbeddedRunnerFingerprint({
			sessionFile: params.sessionFile,
			workspaceDir: params.workspaceDir,
			modelRef: params.modelRef,
			toolNames: params.tools.map((t) => t.name),
			systemPrompt: params.systemPrompt,
			thinkingLevel: params.thinkingLevel ?? "medium"
		});
		const reuseEnabled = this.isEnabledFn();
		const existing = this.pool.get(params.sessionKey);
		let entry;
		let reused = false;
		if (reuseEnabled && existing && existing.fingerprint === fingerprint) {
			this.clearIdleTimer(existing);
			entry = existing;
			entry.lastUsedAt = Date.now();
			reused = true;
			this.stats.reuses += 1;
			applySystemPromptOverrideToSession(entry.session, params.systemPrompt);
			entry.session.agent.streamFn = entry.baseStreamFn;
			log.debug({ sessionKey: params.sessionKey }, "Reusing pooled embedded session runner");
		} else {
			if (existing) this.disposePooledRunner(params.sessionKey, existing, "fingerprint_mismatch");
			entry = await this.createPooledRunner(params);
			this.pool.set(params.sessionKey, entry);
			this.stats.creates += 1;
			log.debug({ sessionKey: params.sessionKey }, "Created embedded session runner");
		}
		return {
			session: entry.session,
			piSm: entry.piSm,
			reused,
			release: () => {
				if (!this.isEnabledFn()) {
					this.disposePooledRunner(params.sessionKey, entry, "runner_disabled");
					return;
				}
				entry.lastUsedAt = Date.now();
				this.scheduleIdleEviction(params.sessionKey, entry);
			}
		};
	}
	clearIdleTimer(entry) {
		if (entry.idleTimer) {
			clearTimeout(entry.idleTimer);
			entry.idleTimer = null;
		}
	}
	scheduleIdleEviction(sessionKey, entry) {
		this.clearIdleTimer(entry);
		const ttlMs = this.getIdleTtlMsFn();
		entry.idleTimer = setTimeout(() => {
			if (this.pool.get(sessionKey) === entry) this.disposePooledRunner(sessionKey, entry, "idle_ttl");
		}, ttlMs);
		entry.idleTimer.unref?.();
	}
	disposePooledRunner(sessionKey, entry, reason) {
		this.clearIdleTimer(entry);
		this.pool.delete(sessionKey);
		this.stats.evictions += 1;
		try {
			entry.piSm.flushPendingToolResults?.();
		} catch {}
		log.debug({
			sessionKey,
			reason
		}, "Embedded session runner evicted");
	}
	async createPooledRunner(params) {
		const { sessionKey, sessionId, sessionFile, sessionsDir, hadSessionFile, workspaceDir, model, thinkingLevel, tools, systemPrompt } = params;
		await this.cache.prewarm(sessionFile);
		const settingsManager = createEmbeddedSettingsManager(workspaceDir);
		const piSm = guardSessionManager(SessionManager.open(sessionFile, sessionsDir, workspaceDir), {
			sessionKey,
			contextWindowTokens: model.contextWindow ?? 128e3
		});
		await prepareSessionManagerForRun({
			sessionManager: piSm,
			sessionFile,
			hadSessionFile,
			sessionId,
			cwd: workspaceDir
		});
		const toolDefs = xopcToolsToDefinitions(tools);
		const toolNames = tools.map((t) => t.name);
		const authStorage = createEmbeddedAuthStorage();
		applyXopcProviderApiKey(authStorage, model.provider);
		const resourceLoader = new DefaultResourceLoader({
			cwd: workspaceDir,
			agentDir: getAgentDir(),
			settingsManager,
			noContextFiles: true
		});
		await resourceLoader.reload();
		const { session } = await createAgentSession({
			cwd: workspaceDir,
			model,
			thinkingLevel: thinkingLevel ?? "medium",
			sessionManager: piSm,
			settingsManager,
			authStorage,
			resourceLoader,
			noTools: "builtin",
			customTools: toolDefs,
			tools: toolNames
		});
		applySystemPromptOverrideToSession(session, systemPrompt);
		const baseStreamFn = wrapStreamFnForXopcExtensions(session.agent.streamFn);
		session.agent.streamFn = baseStreamFn;
		return {
			sessionKey,
			fingerprint: buildEmbeddedRunnerFingerprint({
				sessionFile,
				workspaceDir,
				modelRef: params.modelRef,
				toolNames,
				systemPrompt,
				thinkingLevel: thinkingLevel ?? "medium"
			}),
			session,
			piSm,
			settingsManager,
			baseStreamFn,
			lastUsedAt: Date.now(),
			idleTimer: null
		};
	}
};
const defaultEmbeddedSessionRunnerPool = new EmbeddedSessionRunnerPool();
function getEmbeddedSessionRunnerStats() {
	return defaultEmbeddedSessionRunnerPool.getStats();
}
function resetEmbeddedSessionRunnerForTest() {
	defaultEmbeddedSessionRunnerPool.resetForTest();
}
function evictEmbeddedSessionRunner(sessionKey, reason = "explicit") {
	defaultEmbeddedSessionRunnerPool.evict(sessionKey, reason);
}
function evictAllEmbeddedSessionRunners(reason = "dispose_all") {
	defaultEmbeddedSessionRunnerPool.evictAll(reason);
}
function acquireEmbeddedSessionRunner(params) {
	return defaultEmbeddedSessionRunnerPool.acquire(params);
}
/** Resolve transcript path inputs used by both runner acquire and turn execution. */
async function resolveEmbeddedTranscriptInputs(sessionStore, sessionKey) {
	const { sessionId, absPath: sessionFile, sessionsDir } = await sessionStore.resolveTranscriptPath(sessionKey);
	return {
		sessionId,
		sessionFile,
		sessionsDir,
		hadSessionFile: existsSync(sessionFile)
	};
}
//#endregion
export { EmbeddedSessionRunnerPool, acquireEmbeddedSessionRunner, buildEmbeddedRunnerFingerprint, defaultEmbeddedSessionRunnerPool, evictAllEmbeddedSessionRunners, evictEmbeddedSessionRunner, getEmbeddedSessionRunnerIdleTtlMs, getEmbeddedSessionRunnerStats, isEmbeddedSessionRunnerEnabled, resetEmbeddedSessionRunnerForTest, resolveEmbeddedTranscriptInputs };

//# sourceMappingURL=session-runner.js.map