/**
 * auto/resolve.ts — Per-unit one-shot promise state and resolution.
 *
 * Module-level mutable state: `_currentResolve` and `_sessionSwitchInFlight`.
 * Setter functions are exported because ES modules can't mutate `let` vars
 * across module boundaries.
 *
 * Imports from: auto/types
 */
import { debugLog } from "../debug-logger.js";

// ─── Per-unit one-shot promise state ────────────────────────────────────────
//
// A single module-level resolve function scoped to the current unit execution.
// No queue — if an agent_end arrives with no pending resolver, it is dropped
// (logged as warning). This is simpler and safer than the previous session-
// scoped pendingResolve + pendingAgentEndQueue pattern. Late duplicate
// agent_end events are ignored because the first event already resolved the
// unit and a stale duplicate must not trip the idle watchdog.
let _currentResolve = null;
let _sessionSwitchInFlight = false;
// ─── Setters (needed for cross-module mutation) ─────────────────────────────
export function _setCurrentResolve(fn) {
	_currentResolve = fn;
}
export function _setSessionSwitchInFlight(v) {
	_sessionSwitchInFlight = v;
}
export function _clearCurrentResolve() {
	_currentResolve = null;
}
// ─── resolveAgentEnd ─────────────────────────────────────────────────────────
/**
 * Called from the agent_end event handler in index.ts to resolve the
 * in-flight unit promise. One-shot: the resolver is nulled before calling
 * to prevent double-resolution from model fallback retries.
 *
 * If called when no resolver is registered, the event is stale relative to the
 * current unit lifecycle and is ignored. runUnit registers the resolver before
 * dispatching the turn, so a no-pending event is either a duplicate or a late
 * event from a previous session.
 */
export function resolveAgentEnd(event) {
	if (_sessionSwitchInFlight) {
		debugLog("resolveAgentEnd", { status: "ignored-during-switch" });
		return;
	}
	if (_currentResolve) {
		debugLog("resolveAgentEnd", { status: "resolving", hasEvent: true });
		const r = _currentResolve;
		_currentResolve = null;
		r({ status: "completed", event });
	} else {
		debugLog("resolveAgentEnd", { status: "ignored-no-pending-resolve" });
	}
}
export function isSessionSwitchInFlight() {
	return _sessionSwitchInFlight;
}
/** Return whether a unit is currently awaiting an agent_end event. Test-only. */
export function _hasPendingResolve() {
	return _currentResolve !== null;
}
// ─── resolveAgentEndCancelled ─────────────────────────────────────────────────
/**
 * Force-resolve the pending unit promise with { status: "cancelled" }.
 *
 * Used by pauseAuto, handleAgentEnd early-return, and supervision catch
 * blocks to ensure the autoLoop is never stuck awaiting a promise that
 * will never resolve. Safe to call when no resolver is pending (no-op).
 */
export function resolveAgentEndCancelled(errorContext) {
	if (_currentResolve) {
		debugLog("resolveAgentEndCancelled", { status: "resolving-cancelled" });
		const r = _currentResolve;
		_currentResolve = null;
		r({ status: "cancelled", ...(errorContext ? { errorContext } : {}) });
	}
}
// ─── resetPendingResolve (test helper) ───────────────────────────────────────
/**
 * Reset module-level promise state. Only exported for test cleanup —
 * production code should never call this.
 */
export function _resetPendingResolve() {
	_currentResolve = null;
	_sessionSwitchInFlight = false;
}
/**
 * No-op for backward compatibility with tests that previously set the
 * active session. The module no longer holds a session reference.
 */
export function _setActiveSession(_session) {
	// No-op — kept for test backward compatibility
}
