"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TelegramBotWebHook = void 0;
const debug_js_1 = __importDefault(require("./internal/debug.cjs"));
const node_fs_1 = require("node:fs");
const node_http_1 = __importDefault(require("node:http"));
const node_https_1 = __importDefault(require("node:https"));
const node_buffer_1 = require("node:buffer");
const errors_js_1 = require("./errors.cjs");
const debug = (0, debug_js_1.default)("node-telegram-bot-api:webhook");
const MAX_PAYLOAD_BYTES = 50 * 1024 * 1024; // 50MB
async function readBody(req) {
    return new Promise((resolve, reject) => {
        let total = 0;
        const chunks = [];
        req.on("data", (chunk) => {
            total += chunk.length;
            if (total > MAX_PAYLOAD_BYTES) {
                reject(new Error("Webhook payload exceeds 50MB safety cap"));
                req.destroy();
                return;
            }
            chunks.push(chunk);
        });
        req.on("end", () => resolve(node_buffer_1.Buffer.concat(chunks)));
        req.on("error", reject);
    });
}
class TelegramBotWebHook {
    bot;
    host;
    port;
    healthEndpoint;
    _secretToken;
    _server;
    _open = false;
    constructor(bot, options = {}) {
        this.bot = bot;
        this.host = options.host ?? "0.0.0.0";
        this.port = options.port ?? 8443;
        this.healthEndpoint = options.healthEndpoint ?? "/healthz";
        this._secretToken = options.secretToken;
        const httpsOptions = { ...(options.https ?? {}) };
        if (options.key && options.cert) {
            debug("HTTPS WebHook enabled (by key/cert)");
            httpsOptions.key = (0, node_fs_1.readFileSync)(options.key);
            httpsOptions.cert = (0, node_fs_1.readFileSync)(options.cert);
            this._server = node_https_1.default.createServer(httpsOptions, this._handleRequest);
        }
        else if (options.pfx) {
            debug("HTTPS WebHook enabled (by pfx)");
            httpsOptions.pfx = (0, node_fs_1.readFileSync)(options.pfx);
            this._server = node_https_1.default.createServer(httpsOptions, this._handleRequest);
        }
        else if (Object.keys(httpsOptions).length) {
            debug("HTTPS WebHook enabled (by https options)");
            this._server = node_https_1.default.createServer(httpsOptions, this._handleRequest);
        }
        else {
            debug("HTTP WebHook enabled");
            this._server = node_http_1.default.createServer(this._handleRequest);
        }
    }
    /** Begin listening for incoming Telegram webhook requests. */
    async open() {
        if (this.isOpen())
            return;
        await new Promise((resolve, reject) => {
            const onError = (err) => reject(err);
            this._server.once("error", onError);
            this._server.listen(this.port, this.host, () => {
                this._server.off("error", onError);
                debug("WebHook listening on %s:%s", this.host, this.port);
                this._open = true;
                resolve();
            });
        });
    }
    /** Stop accepting requests. Resolves once existing connections drain. */
    async close() {
        if (!this.isOpen())
            return;
        await new Promise((resolve, reject) => {
            this._server.close((err) => {
                if (err) {
                    reject(err);
                    return;
                }
                this._open = false;
                resolve();
            });
        });
    }
    isOpen() {
        return this._open;
    }
    _emitError(err) {
        if (!this.bot.listeners("webhook_error").length) {
            // eslint-disable-next-line no-console
            console.error(`${new Date().toISOString()} error: [webhook_error] %j`, err);
            return;
        }
        this.bot.emit("webhook_error", err);
    }
    _handleRequest = async (req, res) => {
        debug("WebHook request URL: %s", req.url ?? "");
        const url = req.url ?? "";
        const pathname = url.split("?")[0];
        if (pathname === this.healthEndpoint) {
            debug("WebHook health check passed");
            res.statusCode = 200;
            res.end("OK");
            return;
        }
        if (!pathname.includes(this.bot.token)) {
            debug("WebHook request unauthorized");
            res.statusCode = 401;
            res.end();
            return;
        }
        if (req.method !== "POST") {
            debug("WebHook request isn't a POST");
            res.statusCode = 418; // I'm a teabot!
            res.end();
            return;
        }
        if (this._secretToken) {
            const provided = req.headers["x-telegram-bot-api-secret-token"];
            if (provided !== this._secretToken) {
                debug("WebHook secret-token mismatch");
                res.statusCode = 401;
                res.end();
                return;
            }
        }
        try {
            const buffer = await readBody(req);
            let update;
            try {
                update = JSON.parse(buffer.toString("utf8"));
            }
            catch (parseError) {
                this._emitError(new errors_js_1.ParseError(parseError.message));
                res.statusCode = 400;
                res.end("Bad Request");
                return;
            }
            this.bot.processUpdate(update);
            res.end("OK");
        }
        catch (err) {
            this._emitError(err instanceof errors_js_1.BaseError ? err : new errors_js_1.FatalError(err));
            res.statusCode = 500;
            res.end("Server Error");
        }
    };
}
exports.TelegramBotWebHook = TelegramBotWebHook;
//# sourceMappingURL=webhook.cjs.map