"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.webhookCallback = void 0;
const platform_node_js_1 = require("../platform.node.js");
const frameworks_node_js_1 = require("./frameworks.node.js");
const debugErr = (0, platform_node_js_1.debug)("grammy:error");
const callbackAdapter = (update, callback, header, unauthorized = () => callback('"unauthorized"')) => ({
    update: Promise.resolve(update),
    respond: callback,
    header,
    unauthorized,
});
const adapters = { ...frameworks_node_js_1.adapters, callback: callbackAdapter };
function webhookCallback(bot, adapter = frameworks_node_js_1.defaultAdapter, onTimeout = "throw", timeoutMilliseconds = 10000, secretToken) {
    const { onTimeout: timeout = "throw", timeoutMilliseconds: ms = 10000, secretToken: token, } = typeof onTimeout === "object"
        ? onTimeout
        : { onTimeout, timeoutMilliseconds, secretToken };
    let initialized = false;
    const server = typeof adapter === "string"
        ? adapters[adapter]
        : adapter;
    return async (...args) => {
        if (!initialized) {
            // Will dedupe concurrently incoming calls from several updates
            await bot.init();
            initialized = true;
        }
        const { update, respond, unauthorized, end, handlerReturn, header } = server(...args);
        if (header !== token) {
            await unauthorized();
            // TODO: investigate deno bug that happens when this console logging is removed
            console.log(handlerReturn);
            return handlerReturn;
        }
        let usedWebhookReply = false;
        const webhookReplyEnvelope = {
            async send(json) {
                usedWebhookReply = true;
                await respond(json);
            },
        };
        await timeoutIfNecessary(bot.handleUpdate(await update, webhookReplyEnvelope), typeof timeout === "function" ? () => timeout(...args) : timeout, ms);
        if (!usedWebhookReply)
            end === null || end === void 0 ? void 0 : end();
        return handlerReturn;
    };
}
exports.webhookCallback = webhookCallback;
function timeoutIfNecessary(task, onTimeout, timeout) {
    if (timeout === Infinity)
        return task;
    return new Promise((resolve, reject) => {
        const handle = setTimeout(() => {
            if (onTimeout === "throw") {
                reject(new Error(`Request timed out after ${timeout} ms`));
            }
            else {
                if (typeof onTimeout === "function")
                    onTimeout();
                resolve();
            }
            const now = Date.now();
            task.finally(() => {
                const diff = Date.now() - now;
                debugErr(`Request completed ${diff} ms after timeout!`);
            });
        }, timeout);
        task.then(resolve)
            .catch(reject)
            .finally(() => clearTimeout(handle));
    });
}
