import { t as pruneMapToMaxSize } from "./map-size-DAGm21RM.js";
import { i as resolveGlobalSingleton } from "./global-singleton-Dc_stLtU.js";
import { t as listSystemPresence } from "./system-presence-rX-9uWTd.js";
import { t as presenceUserKey } from "./presence-user-ulXqGuvR.js";
//#region src/gateway/server-methods/session-typing-state.ts
const TYPING_THROTTLE_MS = 1e3;
const TYPING_ACTIVE_TTL_MS = 2500;
const MAX_TYPING_THROTTLE_KEYS = 2048;
function clearSessionTypingStateValue(state) {
	for (const entry of state.broadcasts.values()) if (entry.timer) clearTimeout(entry.timer);
	state.broadcasts.clear();
	state.connections.clear();
}
const sessionTypingState = resolveGlobalSingleton(Symbol.for("openclaw.sessionTypingState"), () => ({
	broadcasts: /* @__PURE__ */ new Map(),
	connections: /* @__PURE__ */ new Map()
}), clearSessionTypingStateValue);
const typingBroadcastState = sessionTypingState.broadcasts;
const typingConnections = sessionTypingState.connections;
function clearSessionTypingState() {
	clearSessionTypingStateValue(sessionTypingState);
}
function liveViewerIdentities(sessionKeys) {
	return new Set(listSystemPresence().flatMap((entry) => entry.user?.id && entry.watchedSessions?.some((sessionKey) => sessionKeys.has(sessionKey)) ? [presenceUserKey(entry.user)] : []));
}
function rememberTypingBroadcast(key, state) {
	typingBroadcastState.delete(key);
	typingBroadcastState.set(key, state);
	if (typingBroadcastState.size <= MAX_TYPING_THROTTLE_KEYS) return;
	const oldestKey = typingBroadcastState.keys().next().value;
	if (!oldestKey) return;
	const oldest = typingBroadcastState.get(oldestKey);
	if (oldest?.timer) clearTimeout(oldest.timer);
	typingBroadcastState.delete(oldestKey);
}
function broadcastTypingThrottled(params) {
	const previous = typingBroadcastState.get(params.key);
	if (!previous || params.now - previous.at >= params.intervalMs) {
		if (previous?.timer) clearTimeout(previous.timer);
		const emitted = params.emit();
		if (emitted) rememberTypingBroadcast(params.key, {
			at: params.now,
			typing: params.typing,
			signature: params.signature
		});
		else typingBroadcastState.delete(params.key);
		return emitted;
	}
	if (params.signature === previous.signature && previous.pending?.signature !== params.signature) {
		if (previous.timer) clearTimeout(previous.timer);
		delete previous.pending;
		delete previous.timer;
		if (!params.typing) {
			rememberTypingBroadcast(params.key, previous);
			return false;
		}
	}
	if (previous.timer && previous.pending?.intervalMs !== params.intervalMs) {
		clearTimeout(previous.timer);
		delete previous.timer;
	}
	previous.pending = {
		typing: params.typing,
		signature: params.signature,
		intervalMs: params.intervalMs,
		emit: params.emit
	};
	if (!previous.timer) {
		const timer = setTimeout(() => {
			const current = typingBroadcastState.get(params.key);
			if (!current || current.timer !== timer || !current.pending) return;
			const pending = current.pending;
			const next = {
				at: Date.now(),
				typing: pending.typing,
				signature: pending.signature
			};
			if (pending.emit()) rememberTypingBroadcast(params.key, next);
			else typingBroadcastState.delete(params.key);
		}, params.intervalMs - (params.now - previous.at));
		timer.unref?.();
		previous.timer = timer;
	}
	rememberTypingBroadcast(params.key, previous);
	return false;
}
function updateTypingConnections(params) {
	for (const [typingKey, activeConnections] of typingConnections) {
		for (const [connectionId, connection] of activeConnections) if (params.now - connection.updatedAt >= TYPING_ACTIVE_TTL_MS) activeConnections.delete(connectionId);
		if (activeConnections.size === 0) typingConnections.delete(typingKey);
	}
	const connections = typingConnections.get(params.key) ?? /* @__PURE__ */ new Map();
	if (params.typing) connections.set(params.connectionId, {
		updatedAt: params.now,
		...params.preview ? { preview: params.preview } : {}
	});
	else connections.delete(params.connectionId);
	if (connections.size === 0) {
		typingConnections.delete(params.key);
		return { typing: false };
	}
	typingConnections.delete(params.key);
	typingConnections.set(params.key, connections);
	pruneMapToMaxSize(typingConnections, MAX_TYPING_THROTTLE_KEYS);
	let latestPreview;
	for (const connection of connections.values()) if (connection.preview && (!latestPreview || connection.updatedAt >= latestPreview.updatedAt)) latestPreview = connection;
	return {
		typing: true,
		...latestPreview?.preview ? { preview: latestPreview.preview } : {}
	};
}
//#endregion
export { updateTypingConnections as a, liveViewerIdentities as i, broadcastTypingThrottled as n, clearSessionTypingState as r, TYPING_THROTTLE_MS as t };
