"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.__tsfTypeAliases = exports.DEFAULT_AVAILABILITY_ALERT_AFTER_MS = void 0;
exports.createAvailabilityMonitor = createAvailabilityMonitor;
const tslib_1 = require("tslib");
const _a = tslib_1.__importStar(require("@zyno-io/ts-server-foundation/type-metadata-runtime"));
exports.DEFAULT_AVAILABILITY_ALERT_AFTER_MS = 60000;
function createAvailabilityMonitor(logger, options = {}) {
    const alertAfterMs = Number(options.alertAfterMs ?? exports.DEFAULT_AVAILABILITY_ALERT_AFTER_MS);
    if (!Number.isFinite(alertAfterMs) || alertAfterMs < 0) {
        throw new Error('Availability alert delay must be a non-negative number');
    }
    const name = options.name ?? 'Dependency';
    let unavailableAt;
    let lastError;
    let alertTimer;
    let alerted = false;
    let stopped = false;
    const clearAlertTimer = () => {
        if (alertTimer)
            clearTimeout(alertTimer);
        alertTimer = undefined;
    };
    const reportUnavailable = () => {
        alertTimer = undefined;
        if (stopped || unavailableAt === undefined || alerted)
            return;
        alerted = true;
        const unavailableForMs = Date.now() - unavailableAt;
        if (lastError === undefined) {
            logger.error(`${name} remains unavailable`, { unavailableForMs });
        }
        else {
            logger.error(`${name} remains unavailable`, lastError, { unavailableForMs });
        }
    };
    const unavailable = (error) => {
        if (stopped)
            return;
        if (error !== undefined)
            lastError = error;
        if (unavailableAt !== undefined)
            return;
        unavailableAt = Date.now();
        logger.warning(`${name} is temporarily unavailable`, {
            alertAfterMs,
            errorMessage: getErrorMessage(error)
        });
        if (alertAfterMs === 0) {
            reportUnavailable();
            return;
        }
        alertTimer = setTimeout(reportUnavailable, alertAfterMs);
        alertTimer.unref?.();
    };
    const available = () => {
        if (stopped || unavailableAt === undefined)
            return;
        const unavailableForMs = Date.now() - unavailableAt;
        const reported = alerted;
        clearAlertTimer();
        unavailableAt = undefined;
        lastError = undefined;
        alerted = false;
        logger.info(`${name} recovered`, { unavailableForMs, alerted: reported });
    };
    return {
        unavailable,
        available,
        stop() {
            if (stopped)
                return;
            stopped = true;
            clearAlertTimer();
        }
    };
}
function getErrorMessage(error) {
    if (error === undefined)
        return undefined;
    return error instanceof Error ? error.message : String(error);
}
exports.__tsfTypeAliases = _a.decodeCompactMetadataV1("[1,{\"AvailabilityLogger\":{\"kind\":18,\"typeName\":\"AvailabilityLogger\",\"types\":[]},\"AvailabilityMonitor\":{\"kind\":18,\"typeName\":\"AvailabilityMonitor\",\"types\":[]},\"AvailabilityMonitorOptions\":{\"kind\":18,\"typeName\":\"AvailabilityMonitorOptions\",\"types\":[{\"kind\":20,\"name\":\"alertAfterMs\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"name\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true}]}}]", []);
//# sourceMappingURL=availability.js.map