/**
 * Periodic health check for the OpenCode server.
 *
 * Monitors OpenCode server health by polling GET /global/health every 30s.
 * After 3 consecutive failures, triggers an auto-restart via the supervisor.
 */
import { logger } from "../utils/logger.js";
import { proxyToOpenCode } from "./proxy.js";
const HEALTH_CHECK_INTERVAL_MS = 30_000;
const MAX_CONSECUTIVE_FAILURES = 3;
const HEALTH_REQUEST_TIMEOUT_MS = 5_000;
let intervalTimer = null;
let consecutiveFailures = 0;
let lastHealthCheck = null;
let onRestartNeeded = null;
/**
 * Start the periodic health check loop.
 *
 * @param restartFn Called when health check determines a restart is needed
 *   (after MAX_CONSECUTIVE_FAILURES consecutive failures).
 */
export function startHealthCheck(restartFn) {
    if (intervalTimer) {
        return; // Already running
    }
    onRestartNeeded = restartFn;
    consecutiveFailures = 0;
    lastHealthCheck = null;
    intervalTimer = setInterval(() => {
        void checkHealth();
    }, HEALTH_CHECK_INTERVAL_MS);
    intervalTimer.unref();
    logger.info("OpenCode health check started (every 30s)");
}
/**
 * Stop the periodic health check loop.
 */
export function stopHealthCheck() {
    if (intervalTimer) {
        clearInterval(intervalTimer);
        intervalTimer = null;
    }
    onRestartNeeded = null;
    logger.info("OpenCode health check stopped");
}
/**
 * Get the current health status for reporting (e.g., /healthz endpoint).
 */
export function getHealthStatus() {
    return {
        healthy: consecutiveFailures === 0 && lastHealthCheck !== null,
        lastHealthCheck,
        consecutiveFailures,
    };
}
/**
 * Reset health check state (for testing).
 */
export function resetHealthCheck() {
    stopHealthCheck();
    consecutiveFailures = 0;
    lastHealthCheck = null;
    onRestartNeeded = null;
}
/**
 * Perform a single health check against the OpenCode server.
 */
async function checkHealth() {
    try {
        const response = await proxyToOpenCode({ method: "GET", path: "/global/health" }, HEALTH_REQUEST_TIMEOUT_MS);
        if (response.status >= 200 && response.status < 300) {
            consecutiveFailures = 0;
            lastHealthCheck = Date.now();
            logger.debug("OpenCode health check passed");
        }
        else {
            handleFailure(`HTTP ${response.status}`);
        }
    }
    catch (err) {
        const message = err instanceof Error ? err.message : String(err);
        handleFailure(message);
    }
}
/**
 * Handle a health check failure. Triggers restart after MAX_CONSECUTIVE_FAILURES.
 */
function handleFailure(reason) {
    consecutiveFailures++;
    logger.warn(`OpenCode health check failed (${consecutiveFailures}/${MAX_CONSECUTIVE_FAILURES}): ${reason}`);
    if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES && onRestartNeeded) {
        logger.error(`OpenCode health check failed ${MAX_CONSECUTIVE_FAILURES} times consecutively, triggering restart`);
        consecutiveFailures = 0;
        void onRestartNeeded();
    }
}
//# sourceMappingURL=health-check.js.map