/**
 * Autonomous mode Supervisor — signal handling and working-tree activity detection.
 *
 * Pure functions — no module-level globals or AutoContext dependency.
 */
import { clearLock } from "./crash-recovery.js";
import { nativeHasChanges } from "./native-git-bridge.js";
import { releaseSessionLock } from "./session-lock.js";
import { logWarning } from "./workflow-logger.js";

// ─── Signal Handling ─────────────────────────────────────────────────────────
/** Signals that should trigger lock cleanup on process termination. */
const CLEANUP_SIGNALS = ["SIGTERM", "SIGHUP", "SIGINT"];
/** Module-level reference to the last registered handler, used as a safety net
 *  to prevent handler accumulation if the caller neglects to pass previousHandler. */
let _currentSigtermHandler = null;
/**
 * Register signal handlers that clear lock files and exit cleanly.
 * Installs handlers on SIGTERM, SIGHUP, and SIGINT so that lock files
 * are cleaned up regardless of how the process is terminated (normal kill,
 * parent process death, or Ctrl+C).
 *
 * Captures the active base path at registration time so the handler
 * always references the correct path even if the module variable changes.
 * Removes any previously registered handler before installing the new one.
 *
 * The optional `onSignal` callback is invoked before `process.exit(0)` so
 * callers can write diagnostics (e.g., UOK parity heartbeat) that would
 * otherwise be lost when the finally block is bypassed by the hard exit.
 *
 * Returns the new handler so the caller can store and deregister it later.
 */
export function registerSigtermHandler(
	currentBasePath,
	previousHandler,
	onSignal,
) {
	// Remove the explicitly-passed previous handler
	if (previousHandler) {
		for (const sig of CLEANUP_SIGNALS) process.off(sig, previousHandler);
	}
	// Safety net: also remove the module-tracked handler in case the caller
	// forgot to pass previousHandler (prevents handler accumulation)
	if (_currentSigtermHandler && _currentSigtermHandler !== previousHandler) {
		for (const sig of CLEANUP_SIGNALS) process.off(sig, _currentSigtermHandler);
	}
	const handler = () => {
		try {
			onSignal?.();
		} catch (err) {
			// Best-effort: signal handler must not throw — log and continue
			// to lock cleanup so the user can still exit cleanly.
			logWarning(
				"session",
				`auto-supervisor signal handler threw: ${err.message}`,
			);
		}
		clearLock(currentBasePath);
		releaseSessionLock(currentBasePath);
		process.exit(0);
	};
	for (const sig of CLEANUP_SIGNALS) process.on(sig, handler);
	_currentSigtermHandler = handler;
	return handler;
}
/** Deregister signal handlers from all cleanup signals (called on stop/pause). */
export function deregisterSigtermHandler(handler) {
	if (handler) {
		for (const sig of CLEANUP_SIGNALS) process.off(sig, handler);
	}
	if (_currentSigtermHandler === handler) {
		_currentSigtermHandler = null;
	}
}
// ─── Working Tree Activity Detection ──────────────────────────────────────────
/**
 * Detect whether the agent is producing work on disk by checking git for
 * any working-tree changes (staged, unstaged, or untracked). Returns true
 * if there are uncommitted changes — meaning the agent is actively working,
 * even though it hasn't signaled progress through runtime records.
 */
export function detectWorkingTreeActivity(cwd) {
	try {
		return nativeHasChanges(cwd);
	} catch {
		return false;
	}
}
