import { webhookCallback } from "grammy";
import { createServer } from "node:http";
import { isDiagnosticsEnabled } from "../infra/diagnostic-events.js";
import { formatErrorMessage } from "../infra/errors.js";
import { installRequestBodyLimitGuard } from "../infra/http-body.js";
import { logWebhookError, logWebhookProcessed, logWebhookReceived, startDiagnosticHeartbeat, stopDiagnosticHeartbeat, } from "../logging/diagnostic.js";
import { defaultRuntime } from "../runtime.js";
import { resolveTelegramAllowedUpdates } from "./allowed-updates.js";
import { withTelegramApiErrorLogging } from "./api-logging.js";
import { createTelegramBot } from "./bot.js";
const TELEGRAM_WEBHOOK_MAX_BODY_BYTES = 1024 * 1024;
const TELEGRAM_WEBHOOK_BODY_TIMEOUT_MS = 30_000;
const TELEGRAM_WEBHOOK_CALLBACK_TIMEOUT_MS = 10_000;
export async function startTelegramWebhook(opts) {
    const path = opts.path ?? "/telegram-webhook";
    const healthPath = opts.healthPath ?? "/healthz";
    const port = opts.port ?? 8787;
    const host = opts.host ?? "127.0.0.1";
    const secret = typeof opts.secret === "string" ? opts.secret.trim() : "";
    if (!secret) {
        throw new Error("Telegram webhook mode requires a non-empty secret token. " +
            "Set channels.telegram.webhookSecret in your config.");
    }
    const runtime = opts.runtime ?? defaultRuntime;
    const diagnosticsEnabled = isDiagnosticsEnabled(opts.config);
    const bot = createTelegramBot({
        token: opts.token,
        runtime,
        proxyFetch: opts.fetch,
        config: opts.config,
        accountId: opts.accountId,
    });
    const handler = webhookCallback(bot, "http", {
        secretToken: secret,
        onTimeout: "return",
        timeoutMilliseconds: TELEGRAM_WEBHOOK_CALLBACK_TIMEOUT_MS,
    });
    if (diagnosticsEnabled) {
        startDiagnosticHeartbeat();
    }
    const server = createServer((req, res) => {
        if (req.url === healthPath) {
            res.writeHead(200);
            res.end("ok");
            return;
        }
        if (req.url !== path || req.method !== "POST") {
            res.writeHead(404);
            res.end();
            return;
        }
        const startTime = Date.now();
        if (diagnosticsEnabled) {
            logWebhookReceived({ channel: "telegram", updateType: "telegram-post" });
        }
        const guard = installRequestBodyLimitGuard(req, res, {
            maxBytes: TELEGRAM_WEBHOOK_MAX_BODY_BYTES,
            timeoutMs: TELEGRAM_WEBHOOK_BODY_TIMEOUT_MS,
            responseFormat: "text",
        });
        if (guard.isTripped()) {
            return;
        }
        const handled = handler(req, res);
        if (handled && typeof handled.catch === "function") {
            void handled
                .then(() => {
                if (diagnosticsEnabled) {
                    logWebhookProcessed({
                        channel: "telegram",
                        updateType: "telegram-post",
                        durationMs: Date.now() - startTime,
                    });
                }
            })
                .catch((err) => {
                if (guard.isTripped()) {
                    return;
                }
                const errMsg = formatErrorMessage(err);
                if (diagnosticsEnabled) {
                    logWebhookError({
                        channel: "telegram",
                        updateType: "telegram-post",
                        error: errMsg,
                    });
                }
                runtime.log?.(`webhook handler failed: ${errMsg}`);
                if (!res.headersSent) {
                    res.writeHead(500);
                }
                res.end();
            })
                .finally(() => {
                guard.dispose();
            });
            return;
        }
        guard.dispose();
    });
    const publicUrl = opts.publicUrl ?? `http://${host === "0.0.0.0" ? "localhost" : host}:${port}${path}`;
    await withTelegramApiErrorLogging({
        operation: "setWebhook",
        runtime,
        fn: () => bot.api.setWebhook(publicUrl, {
            secret_token: secret,
            allowed_updates: resolveTelegramAllowedUpdates(),
        }),
    });
    await new Promise((resolve) => server.listen(port, host, resolve));
    runtime.log?.(`webhook listening on ${publicUrl}`);
    const shutdown = () => {
        server.close();
        void bot.stop();
        if (diagnosticsEnabled) {
            stopDiagnosticHeartbeat();
        }
    };
    if (opts.abortSignal) {
        opts.abortSignal.addEventListener("abort", shutdown, { once: true });
    }
    return { server, bot, stop: shutdown };
}
