import "./fs-safe-gVoExnQ2.js";
import { r as withTimeout } from "./timing-8WD1In27.js";
import { c as interruptSessionWorkAdmissions, l as isCompetingSessionWorkAdmissionActive, t as SESSION_WORK_ADMISSION_DRAIN_TIMEOUT_MS } from "./session-lifecycle-admission-DPRIiIqj.js";
import { b as waitForReplyRunEndBySessionId, l as isReplyRunActiveForSessionId, m as replyRunRegistry, n as abortReplyRunBySessionId } from "./reply-run-registry.registry-W2x6KG50.js";
import "./reply-run-registry-DzGHXS4H.js";
import { A as waitForEmbeddedAgentRunEnd, f as isEmbeddedAgentRunInProgress, n as abortEmbeddedAgentRun } from "./runs-DkiZS9mO.js";
import { a as getCommandLaneSnapshot } from "./command-queue-CrKnQVag.js";
import { o as hasPendingFollowupQueueWork } from "./state-ShHnWzdd.js";
import { t as resolveEmbeddedSessionLane } from "./lanes-CVttd5qX.js";
import { t as clearSessionQueues } from "./cleanup-CBdLrNVP.js";
import { i as prepareSessionWorkerPlacementStop, n as prepareSessionWorkerPlacementMutationCheck } from "./session-placement-lifecycle-7DQHpaT9.js";
import { m as waitForChatAbortControllerRemoval } from "./chat-abort-BUtCwiyk.js";
import { i as hasGatewaySessionAbortOwner, r as createChatAbortOps, t as abortChatRunsForSessionKeyWithPartials } from "./chat-abort-runtime-B-JjtK50.js";
import { t as asWorkerInferenceControl } from "./inference-control-CDvM08Nt.js";
import { t as beginWorkerInferenceSessionDrain } from "./inference-control-internal-CQh2JfZC.js";
//#region src/gateway/server-methods/sessions-lifecycle-drain.ts
function hasAuthoritativeSessionWork(params, workerDrain, terminalDrain, workIdentities) {
	const sessionId = params.sessionId;
	return isCompetingSessionWorkAdmissionActive(params.storePath, params.lifecycleIdentities) || params.sessionKeys.some((key) => replyRunRegistry.isActive(key)) || Boolean(sessionId && isReplyRunActiveForSessionId(sessionId)) || Boolean(sessionId && isEmbeddedAgentRunInProgress(sessionId)) || hasPendingFollowupQueueWork(workIdentities) || workIdentities.some((key) => getCommandLaneSnapshot(resolveEmbeddedSessionLane(key)).queuedCount > 0) || hasGatewaySessionAbortOwner({
		context: params.context,
		sessionKeys: params.sessionKeys,
		sessionId,
		agentId: params.agentId,
		defaultAgentId: params.defaultAgentId
	}) || Boolean(sessionId && params.context.workerSessionPlacementService?.getMany([sessionId]).get(sessionId)?.turnClaim) || workerDrain?.hasWork() === true || terminalDrain?.hasWork() === true;
}
/** Fence is already active when this starts; retain the returned runtime fence through commit. */
async function prepareSessionLifecycleDrain(params) {
	params.authorize?.();
	const reclaim = prepareSessionWorkerPlacementStop(params);
	const timeoutMs = SESSION_WORK_ADMISSION_DRAIN_TIMEOUT_MS;
	const workIdentities = Array.from(/* @__PURE__ */ new Set([...params.sessionKeys, ...params.sessionId ? [params.sessionId] : []]));
	const workerService = params.context.workerEnvironmentService;
	const workerControl = asWorkerInferenceControl(workerService);
	let workerDrain;
	let terminalDrain;
	const release = () => {
		try {
			terminalDrain?.release();
		} finally {
			workerDrain?.release();
		}
	};
	try {
		if (params.sessionId) {
			workerDrain = beginWorkerInferenceSessionDrain(workerService, params.sessionId);
			if (!workerDrain && workerControl?.hasInferenceForSession(params.sessionId) === true) throw new Error("Worker inference drain is unavailable");
			terminalDrain = params.context.terminalSessions?.beginAgentSessionDrain({
				kind: "agent",
				agentSessionKey: params.sessionKey,
				agentSessionId: params.sessionId,
				agentId: params.agentId
			});
		}
		let controllerDrain = Promise.resolve(true);
		if ((await abortChatRunsForSessionKeyWithPartials({
			context: params.context,
			ops: createChatAbortOps(params.context),
			sessionKey: params.sessionKeys[0],
			sessionKeyAliases: params.sessionKeys.slice(1),
			sessionId: params.sessionId,
			agentId: params.agentId,
			defaultAgentId: params.defaultAgentId,
			abortOrigin: "rpc",
			stopReason: params.action,
			requester: { isAdmin: true },
			includeProtectedRuns: true,
			onControllerTargets: (targets) => {
				controllerDrain = waitForChatAbortControllerRemoval({
					entries: params.context.chatAbortControllers,
					targets,
					timeoutMs
				});
			},
			onAuthorizedAfterQueuedAbort: () => {
				const cleared = clearSessionQueues(workIdentities);
				let aborted = cleared.followupCleared > 0 || cleared.laneCleared > 0;
				for (const key of params.sessionKeys) aborted = replyRunRegistry.abort(key) || aborted;
				if (params.sessionId) {
					aborted = abortReplyRunBySessionId(params.sessionId) || aborted;
					aborted = abortEmbeddedAgentRun(params.sessionId) || aborted;
				}
				return aborted;
			}
		})).unauthorized) throw new Error("Session cancellation lost ownership");
		params.authorize?.();
		const admittedWork = interruptSessionWorkAdmissions({
			scope: params.storePath,
			identities: params.lifecycleIdentities,
			timeoutMs
		});
		const replyWork = Promise.all([...params.sessionKeys.map((key) => replyRunRegistry.waitForIdle(key, timeoutMs)), ...params.sessionId ? [waitForReplyRunEndBySessionId(params.sessionId, timeoutMs)] : []]).then((results) => results.every(Boolean));
		const embeddedWork = params.sessionId ? waitForEmbeddedAgentRunEnd(params.sessionId, timeoutMs) : Promise.resolve(true);
		const placementService = params.context.workerSessionPlacementService;
		const placementWork = (params.sessionId ? placementService?.getMany([params.sessionId]).get(params.sessionId) : void 0)?.turnClaim ? placementService?.waitForTurnClaimRelease ? placementService.waitForTurnClaimRelease(params.sessionId, { timeoutMs }).then(() => true) : Promise.resolve(false) : Promise.resolve(true);
		const workerWork = workerDrain ? withTimeout(workerDrain.drained, timeoutMs, "worker inference lifecycle drain").then(() => true) : Promise.resolve(true);
		const terminalWork = terminalDrain ? withTimeout(terminalDrain.drained, timeoutMs, "agent terminal lifecycle drain").then(() => true) : Promise.resolve(true);
		if (!(await Promise.all([
			controllerDrain,
			admittedWork,
			replyWork,
			embeddedWork,
			placementWork,
			workerWork,
			terminalWork
		])).every(Boolean)) throw new Error("Session work is still active after the lifecycle drain");
		await reclaim();
		const assertPlacementCurrent = prepareSessionWorkerPlacementMutationCheck({
			context: params.context,
			sessionId: params.sessionId
		});
		return {
			release,
			hasAuthoritativeWork: () => {
				try {
					assertPlacementCurrent();
				} catch {
					return true;
				}
				return hasAuthoritativeSessionWork(params, workerDrain, terminalDrain, workIdentities);
			}
		};
	} catch (error) {
		release();
		throw error;
	}
}
//#endregion
export { prepareSessionLifecycleDrain as t };
