"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.__tsfTypeAliases = exports.SentryLiftKeysToTagsFromLoggerContext = void 0;
exports.isError = isError;
exports.getErrorMessage = getErrorMessage;
exports.toError = toError;
exports.tryOrErrorSync = tryOrErrorSync;
exports.tryOrError = tryOrError;
exports.setGlobalErrorReporter = setGlobalErrorReporter;
exports.reportError = reportError;
const tslib_1 = require("tslib");
const _a = tslib_1.__importStar(require("@zyno-io/ts-server-foundation/type-metadata-runtime"));
const types_1 = require("node:util/types");
const node_1 = require("@sentry/node");
const const_1 = require("../../app/const");
const env_1 = require("../../env");
const helpers_1 = require("../../telemetry/otel/helpers");
const sentry_1 = require("../../telemetry/sentry");
exports.SentryLiftKeysToTagsFromLoggerContext = [];
const errorHandlerState = {};
function isError(value) {
    return value instanceof Error || (0, types_1.isNativeError)(value);
}
function getErrorMessage(value) {
    return isError(value) ? value.message : String(value);
}
function toError(value, cause) {
    const error = isError(value) ? value : new Error(String(value));
    if (cause !== undefined)
        error.cause = toError(cause);
    return error;
}
function tryOrErrorSync(fn) {
    try {
        return fn();
    }
    catch (error) {
        return toError(error);
    }
}
async function tryOrError(fn) {
    try {
        return await fn();
    }
    catch (error) {
        return toError(error);
    }
}
function setGlobalErrorReporter(reporter) {
    errorHandlerState.reporter = reporter;
}
function reportError(level, err, context) {
    try {
        errorHandlerState.reporter?.(level, err, context);
    }
    catch (reporterError) {
        console.error('Global error reporter failed', reporterError);
    }
    if ((0, sentry_1.isSentryInstalled)()) {
        const loggerContext = context.loggerContext ?? {};
        const tags = pickTagKeys(loggerContext, exports.SentryLiftKeysToTagsFromLoggerContext);
        const Details = {
            ...context,
            loggerContext: omitKeys(loggerContext, exports.SentryLiftKeysToTagsFromLoggerContext)
        };
        (0, node_1.captureException)(err, {
            tags,
            extra: { Details },
            level: level === 1 ? 'fatal' : level === 3 ? 'warning' : 'error'
        });
    }
    if (level === 1 && !(0, const_1.isTestEnvironment)()) {
        sendSlackAlertNotification(err, context);
    }
}
async function sendSlackAlertNotification(err, context) {
    try {
        const traceContext = (0, helpers_1.getTraceContext)();
        const url = getSlackWebhookUrl();
        if (!url)
            return;
        await fetch(url, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                text: compact([`:rotating_light: *${err.message}*`, getCauseMessage(err.cause) && `cause: ${getCauseMessage(err.cause)}`]).join('\n'),
                attachments: [
                    {
                        color: 'danger',
                        fields: compact([
                            context.scope && {
                                title: 'Scope',
                                value: context.scope,
                                short: true
                            },
                            traceContext && {
                                title: 'Trace ID',
                                value: traceContext.traceId,
                                short: true
                            },
                            context.data && {
                                title: 'Alert Data',
                                value: JSON.stringify(context.data, null, 2),
                                short: false
                            },
                            err.context && {
                                title: 'Error Context',
                                value: JSON.stringify(err.context, null, 2),
                                short: false
                            },
                            context.scopeData && {
                                title: 'Scope Data',
                                value: JSON.stringify(context.scopeData, null, 2),
                                short: false
                            },
                            context.loggerContext && {
                                title: 'Logger Context',
                                value: JSON.stringify(context.loggerContext, null, 2),
                                short: false
                            }
                        ])
                    }
                ]
            })
        });
    }
    catch (error) {
        console.error('Failed to send slack alert notification', error);
    }
}
function getSlackWebhookUrl() {
    try {
        // Lazy require avoids a load-time cycle through app -> services -> logger -> error.
        // eslint-disable-next-line @typescript-eslint/no-require-imports
        const { getCurrentApp } = require('../../app/base');
        return getCurrentApp().config?.ALERTS_SLACK_WEBHOOK_URL ?? env_1.Env.ALERTS_SLACK_WEBHOOK_URL;
    }
    catch {
        return env_1.Env.ALERTS_SLACK_WEBHOOK_URL;
    }
}
function getCauseMessage(cause) {
    if (!cause)
        return undefined;
    if (isError(cause))
        return cause.message;
    if (typeof cause === 'object' && 'message' in cause)
        return String(cause.message);
    return String(cause);
}
function compact(values) {
    return values.filter(Boolean);
}
function pickTagKeys(source, keys) {
    return Object.fromEntries(keys.filter(key => isPrimitive(source[key])).map(key => [key, source[key]]));
}
function omitKeys(source, keys) {
    const blocked = new Set(keys);
    return Object.fromEntries(Object.entries(source).filter(([key]) => !blocked.has(key)));
}
function isPrimitive(value) {
    return value === undefined || value === null || ['string', 'number', 'boolean', 'bigint', 'symbol'].includes(typeof value);
}
exports.__tsfTypeAliases = _a.decodeCompactMetadataV1("[1,{\"DecoratedError\":{\"kind\":18,\"typeName\":\"DecoratedError\",\"types\":[{\"kind\":20,\"name\":\"cause\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"context\",\"type\":{\"kind\":12,\"types\":[{\"kind\":18,\"typeName\":\"Record\",\"utilityType\":\"Record\",\"typeArguments\":[{\"kind\":6},{\"kind\":2}],\"index\":{\"kind\":2},\"types\":[]},{\"kind\":4}]},\"optional\":true}],\"implements\":[{\"kind\":16,\"typeName\":\"Error\",\"classType\":{\"$tsf\":0}}]},\"IErrorContext\":{\"kind\":18,\"typeName\":\"IErrorContext\",\"types\":[{\"kind\":20,\"name\":\"scope\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"scopeData\",\"type\":{\"kind\":12,\"types\":[{\"kind\":18,\"typeName\":\"Record\",\"utilityType\":\"Record\",\"typeArguments\":[{\"kind\":6},{\"kind\":2}],\"index\":{\"kind\":2},\"types\":[]},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"loggerContext\",\"type\":{\"kind\":12,\"types\":[{\"kind\":18,\"typeName\":\"Record\",\"utilityType\":\"Record\",\"typeArguments\":[{\"kind\":6},{\"kind\":2}],\"index\":{\"kind\":2},\"types\":[]},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"data\",\"type\":{\"kind\":12,\"types\":[{\"kind\":18,\"typeName\":\"Record\",\"utilityType\":\"Record\",\"typeArguments\":[{\"kind\":6},{\"kind\":2}],\"index\":{\"kind\":2},\"types\":[]},{\"kind\":4}]},\"optional\":true}],\"index\":{\"kind\":2}}}]", [() => (typeof Error !== "undefined" ? Error : (typeof exports !== "undefined" ? exports.Error : undefined))]);
//# sourceMappingURL=error.js.map