import { createLogger } from "../../utils/logger/index.js";
import { init_logger } from "../../utils/logger.js";
//#region src/agent/session/session-state-bag.ts
init_logger();
const log = createLogger("SessionStateBag");
const DEFAULT_TTL_MS = 3600 * 1e3;
const DEFAULT_SWEEP_INTERVAL_MS = 600 * 1e3;
const DEFAULT_MAX_ENTRIES = 5e3;
var SessionStateBag = class {
	/** Webchat SSE publisher (register/unregister + TTL fallback). */
	webchatPublishers = /* @__PURE__ */ new Map();
	/** Last assistant plain text (TTL + LRU). */
	lastAssistantText = /* @__PURE__ */ new Map();
	/** Stream text for the in-flight embedded turn (managed by turn). */
	embeddedStreamText = /* @__PURE__ */ new Map();
	/** Persistent-goal stream outcome (take-and-delete). */
	directStreamOutcome = /* @__PURE__ */ new Map();
	/** Concurrent inbound turn depth (counter). */
	inboundTurnDepth = /* @__PURE__ */ new Map();
	/** Agent-event subscription tear-downs (run on dispose). */
	sessionEventUnsubscribers = /* @__PURE__ */ new Map();
	ttlMs;
	maxEntries;
	now;
	sweepTimer;
	constructor(opts = {}) {
		this.ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;
		this.maxEntries = opts.maxEntries ?? DEFAULT_MAX_ENTRIES;
		this.now = opts.now ?? Date.now;
		const sweepIntervalMs = opts.sweepIntervalMs ?? DEFAULT_SWEEP_INTERVAL_MS;
		if (this.ttlMs > 0 && sweepIntervalMs > 0) {
			this.sweepTimer = setInterval(() => this.sweepStaleEntries(), sweepIntervalMs);
			this.sweepTimer.unref?.();
		} else this.sweepTimer = null;
	}
	registerWebchatPublisher(sessionKey, publisher) {
		this.webchatPublishers.set(sessionKey, {
			value: publisher,
			touchedAt: this.now()
		});
		this.enforceCap(this.webchatPublishers, "webchatPublishers");
	}
	unregisterWebchatPublisher(sessionKey) {
		this.webchatPublishers.delete(sessionKey);
	}
	getWebchatPublisher(sessionKey) {
		const entry = this.webchatPublishers.get(sessionKey);
		if (!entry) return void 0;
		entry.touchedAt = this.now();
		return entry.value;
	}
	setLastAssistantText(sessionKey, text) {
		const trimmed = text.trim();
		if (!trimmed) return;
		this.lastAssistantText.set(sessionKey, {
			value: trimmed,
			touchedAt: this.now()
		});
		this.enforceCap(this.lastAssistantText, "lastAssistantText");
	}
	getLastAssistantText(sessionKey) {
		const entry = this.lastAssistantText.get(sessionKey);
		if (!entry) return void 0;
		entry.touchedAt = this.now();
		return entry.value;
	}
	appendEmbeddedStreamText(sessionKey, chunk) {
		const next = (this.embeddedStreamText.get(sessionKey) ?? "") + chunk;
		this.embeddedStreamText.set(sessionKey, next);
		return next;
	}
	clearEmbeddedStreamText(sessionKey) {
		this.embeddedStreamText.delete(sessionKey);
	}
	recordPersistentGoalStreamOutcome(sessionKey, outcome) {
		this.directStreamOutcome.set(sessionKey, outcome);
	}
	takePersistentGoalStreamOutcome(sessionKey) {
		const v = this.directStreamOutcome.get(sessionKey);
		this.directStreamOutcome.delete(sessionKey);
		return v;
	}
	beginInboundTurn(sessionKey) {
		this.inboundTurnDepth.set(sessionKey, (this.inboundTurnDepth.get(sessionKey) ?? 0) + 1);
	}
	endInboundTurn(sessionKey) {
		const next = (this.inboundTurnDepth.get(sessionKey) ?? 1) - 1;
		if (next <= 0) this.inboundTurnDepth.delete(sessionKey);
		else this.inboundTurnDepth.set(sessionKey, next);
	}
	getInboundTurnDepth(sessionKey) {
		return this.inboundTurnDepth.get(sessionKey) ?? 0;
	}
	setSessionEventUnsubscriber(sessionKey, unsubscribe) {
		const previous = this.sessionEventUnsubscribers.get(sessionKey);
		if (previous) try {
			previous();
		} catch (err) {
			log.warn({
				err,
				sessionKey
			}, "Previous session-event unsubscribe threw");
		}
		this.sessionEventUnsubscribers.set(sessionKey, unsubscribe);
	}
	hasSessionEventUnsubscriber(sessionKey) {
		return this.sessionEventUnsubscribers.has(sessionKey);
	}
	/** Clear every slot for `sessionKey`, invoking the unsubscriber if registered. */
	disposeSession(sessionKey) {
		const unsub = this.sessionEventUnsubscribers.get(sessionKey);
		if (unsub) {
			try {
				unsub();
			} catch (err) {
				log.warn({
					err,
					sessionKey
				}, "Session event unsubscribe threw during dispose");
			}
			this.sessionEventUnsubscribers.delete(sessionKey);
		}
		this.webchatPublishers.delete(sessionKey);
		this.lastAssistantText.delete(sessionKey);
		this.embeddedStreamText.delete(sessionKey);
		this.directStreamOutcome.delete(sessionKey);
		this.inboundTurnDepth.delete(sessionKey);
	}
	/** Tear down every session (process stop / hot reload). */
	disposeAll() {
		for (const [sessionKey, unsub] of this.sessionEventUnsubscribers) try {
			unsub();
		} catch (err) {
			log.warn({
				err,
				sessionKey
			}, "Session event unsubscribe threw during disposeAll");
		}
		this.sessionEventUnsubscribers.clear();
		this.webchatPublishers.clear();
		this.lastAssistantText.clear();
		this.embeddedStreamText.clear();
		this.directStreamOutcome.clear();
		this.inboundTurnDepth.clear();
		if (this.sweepTimer) clearInterval(this.sweepTimer);
	}
	/** Test helper. */
	size() {
		return {
			webchatPublishers: this.webchatPublishers.size,
			lastAssistantText: this.lastAssistantText.size,
			embeddedStreamText: this.embeddedStreamText.size,
			directStreamOutcome: this.directStreamOutcome.size,
			inboundTurnDepth: this.inboundTurnDepth.size,
			sessionEventUnsubscribers: this.sessionEventUnsubscribers.size
		};
	}
	sweepStaleEntries() {
		const cutoff = this.now() - this.ttlMs;
		let removed = 0;
		for (const [k, entry] of this.webchatPublishers) if (entry.touchedAt < cutoff) {
			this.webchatPublishers.delete(k);
			removed += 1;
		}
		for (const [k, entry] of this.lastAssistantText) if (entry.touchedAt < cutoff) {
			this.lastAssistantText.delete(k);
			removed += 1;
		}
		if (removed > 0) log.debug({
			removed,
			ttlMs: this.ttlMs
		}, "SessionStateBag TTL sweep");
	}
	enforceCap(map, slotName) {
		if (map.size <= this.maxEntries) return;
		const sorted = [...map.entries()].sort((a, b) => a[1].touchedAt - b[1].touchedAt);
		let evict = map.size - this.maxEntries;
		while (evict > 0 && sorted.length > 0) {
			const oldest = sorted.shift();
			map.delete(oldest[0]);
			evict -= 1;
		}
		log.warn({
			slot: slotName,
			maxEntries: this.maxEntries
		}, `SessionStateBag slot exceeded cap; evicted oldest entries`);
	}
};
//#endregion
export { SessionStateBag };

//# sourceMappingURL=session-state-bag.js.map