import { danger } from "../globals.js";
import { DEFAULT_GMAIL_LABEL, DEFAULT_GMAIL_MAX_BYTES, DEFAULT_GMAIL_RENEW_MINUTES, DEFAULT_GMAIL_SERVE_BIND, DEFAULT_GMAIL_SERVE_PATH, DEFAULT_GMAIL_SERVE_PORT, DEFAULT_GMAIL_SUBSCRIPTION, DEFAULT_GMAIL_TOPIC, } from "../hooks/gmail.js";
import { runGmailService, runGmailSetup, } from "../hooks/gmail-ops.js";
import { defaultRuntime } from "../runtime.js";
import { formatDocsLink } from "../terminal/links.js";
import { theme } from "../terminal/theme.js";
export function registerWebhooksCli(program) {
    const webhooks = program
        .command("webhooks")
        .description("Webhook helpers and integrations")
        .addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/webhooks", "docs.clawd.bot/cli/webhooks")}\n`);
    const gmail = webhooks.command("gmail").description("Gmail Pub/Sub 钩子（通过 gogcli）");
    gmail
        .command("setup")
        .description("Configure Gmail watch + Pub/Sub + Clawdbot hooks")
        .requiredOption("--account <email>", "Gmail account to watch")
        .option("--project <id>", "GCP project id (OAuth client owner)")
        .option("--topic <name>", "Pub/Sub topic name", DEFAULT_GMAIL_TOPIC)
        .option("--subscription <name>", "Pub/Sub subscription name", DEFAULT_GMAIL_SUBSCRIPTION)
        .option("--label <label>", "Gmail label to watch", DEFAULT_GMAIL_LABEL)
        .option("--hook-url <url>", "Clawdbot hook URL")
        .option("--hook-token <token>", "Clawdbot hook token")
        .option("--push-token <token>", "Push token for gog watch serve")
        .option("--bind <host>", "gog watch serve bind host", DEFAULT_GMAIL_SERVE_BIND)
        .option("--port <port>", "gog watch serve port", String(DEFAULT_GMAIL_SERVE_PORT))
        .option("--path <path>", "gog watch serve path", DEFAULT_GMAIL_SERVE_PATH)
        .option("--include-body", "Include email body snippets", true)
        .option("--max-bytes <n>", "Max bytes for body snippets", String(DEFAULT_GMAIL_MAX_BYTES))
        .option("--renew-minutes <n>", "Renew watch every N minutes", String(DEFAULT_GMAIL_RENEW_MINUTES))
        .option("--tailscale <mode>", "Expose push endpoint via tailscale (funnel|serve|off)", "funnel")
        .option("--tailscale-path <path>", "Path for tailscale serve/funnel")
        .option("--tailscale-target <target>", "Tailscale serve/funnel target (port, host:port, or URL)")
        .option("--push-endpoint <url>", "Explicit Pub/Sub push endpoint")
        .option("--json", "Output JSON summary", false)
        .action(async (opts) => {
        try {
            const parsed = parseGmailSetupOptions(opts);
            await runGmailSetup(parsed);
        }
        catch (err) {
            defaultRuntime.error(danger(String(err)));
            defaultRuntime.exit(1);
        }
    });
    gmail
        .command("run")
        .description("Run gog watch serve + auto-renew loop")
        .option("--account <email>", "Gmail account to watch")
        .option("--topic <topic>", "Pub/Sub topic path (projects/.../topics/..)")
        .option("--subscription <name>", "Pub/Sub subscription name")
        .option("--label <label>", "Gmail label to watch")
        .option("--hook-url <url>", "Clawdbot hook URL")
        .option("--hook-token <token>", "Clawdbot hook token")
        .option("--push-token <token>", "Push token for gog watch serve")
        .option("--bind <host>", "gog watch serve bind host")
        .option("--port <port>", "gog watch serve port")
        .option("--path <path>", "gog watch serve path")
        .option("--include-body", "Include email body snippets")
        .option("--max-bytes <n>", "Max bytes for body snippets")
        .option("--renew-minutes <n>", "Renew watch every N minutes")
        .option("--tailscale <mode>", "Expose push endpoint via tailscale (funnel|serve|off)")
        .option("--tailscale-path <path>", "Path for tailscale serve/funnel")
        .option("--tailscale-target <target>", "Tailscale serve/funnel target (port, host:port, or URL)")
        .action(async (opts) => {
        try {
            const parsed = parseGmailRunOptions(opts);
            await runGmailService(parsed);
        }
        catch (err) {
            defaultRuntime.error(danger(String(err)));
            defaultRuntime.exit(1);
        }
    });
}
function parseGmailSetupOptions(raw) {
    const accountRaw = raw.account;
    const account = typeof accountRaw === "string" ? accountRaw.trim() : "";
    if (!account)
        throw new Error("--account is required");
    return {
        account,
        project: stringOption(raw.project),
        topic: stringOption(raw.topic),
        subscription: stringOption(raw.subscription),
        label: stringOption(raw.label),
        hookUrl: stringOption(raw.hookUrl),
        hookToken: stringOption(raw.hookToken),
        pushToken: stringOption(raw.pushToken),
        bind: stringOption(raw.bind),
        port: numberOption(raw.port),
        path: stringOption(raw.path),
        includeBody: booleanOption(raw.includeBody),
        maxBytes: numberOption(raw.maxBytes),
        renewEveryMinutes: numberOption(raw.renewMinutes),
        tailscale: stringOption(raw.tailscale),
        tailscalePath: stringOption(raw.tailscalePath),
        tailscaleTarget: stringOption(raw.tailscaleTarget),
        pushEndpoint: stringOption(raw.pushEndpoint),
        json: Boolean(raw.json),
    };
}
function parseGmailRunOptions(raw) {
    return {
        account: stringOption(raw.account),
        topic: stringOption(raw.topic),
        subscription: stringOption(raw.subscription),
        label: stringOption(raw.label),
        hookUrl: stringOption(raw.hookUrl),
        hookToken: stringOption(raw.hookToken),
        pushToken: stringOption(raw.pushToken),
        bind: stringOption(raw.bind),
        port: numberOption(raw.port),
        path: stringOption(raw.path),
        includeBody: booleanOption(raw.includeBody),
        maxBytes: numberOption(raw.maxBytes),
        renewEveryMinutes: numberOption(raw.renewMinutes),
        tailscale: stringOption(raw.tailscale),
        tailscalePath: stringOption(raw.tailscalePath),
        tailscaleTarget: stringOption(raw.tailscaleTarget),
    };
}
function stringOption(value) {
    if (typeof value !== "string")
        return undefined;
    const trimmed = value.trim();
    return trimmed ? trimmed : undefined;
}
function numberOption(value) {
    if (value === undefined || value === null)
        return undefined;
    const n = typeof value === "number" ? value : Number(value);
    if (!Number.isFinite(n) || n <= 0)
        return undefined;
    return Math.floor(n);
}
function booleanOption(value) {
    if (value === undefined || value === null)
        return undefined;
    return Boolean(value);
}
