import { ensureAuthProfileStore } from "../agents/auth-profiles.js";
import { listChannelPlugins } from "../channels/plugins/index.js";
import { applyAuthChoice, resolvePreferredProviderForAuthChoice, warnIfModelConfigLooksOff, } from "../commands/auth-choice.js";
import { promptAuthChoiceGrouped } from "../commands/auth-choice-prompt.js";
import { applyPrimaryModel, promptDefaultModel } from "../commands/model-picker.js";
import { setupChannels } from "../commands/onboard-channels.js";
import { applyWizardMetadata, DEFAULT_WORKSPACE, ensureWorkspaceAndSessions, handleReset, printWizardHeader, probeGatewayReachable, summarizeExistingConfig, } from "../commands/onboard-helpers.js";
import { promptRemoteGatewayConfig } from "../commands/onboard-remote.js";
import { setupSkills } from "../commands/onboard-skills.js";
import { setupInternalHooks } from "../commands/onboard-hooks.js";
import { formatCliCommand } from "../cli/command-format.js";
import { DEFAULT_GATEWAY_PORT, readConfigFileSnapshot, resolveGatewayPort, writeConfigFile, } from "../config/config.js";
import { logConfigUpdated } from "../config/logging.js";
import { defaultRuntime } from "../runtime.js";
import { resolveUserPath } from "../utils.js";
import { finalizeOnboardingWizard } from "./onboarding.finalize.js";
import { configureGatewayForOnboarding } from "./onboarding.gateway-config.js";
import { WizardCancelledError } from "./prompts.js";
async function requireRiskAcknowledgement(params) {
    if (params.opts.acceptRisk === true)
        return;
    await params.prompter.note([
        "安全警告 — 请阅读。",
        "",
        "OpenClaw 是一个业余项目，仍处于测试阶段。可能会有粗糙之处。",
        "如果启用了工具，此机器人可以读取文件并执行操作。",
        "不良提示可能会诱使其执行不安全的操作。",
        "",
        "如果您不熟悉基本的安全和访问控制，请不要运行 OpenClaw。",
        "在启用工具或将系统暴露给互联网之前，请寻求有经验的人士帮助。",
        "",
        "推荐的基础设置：",
        "- 配对/白名单 + @提及门控。",
        "- 沙箱 + 最低权限工具。",
        "- 将机密信息保留在智能体可访问的文件系统之外。",
        "- 对于使用工具或不受信任收件箱的机器人，请使用最强大的可用模型。",
        "",
        "定期运行：",
        "openclaw-cn security audit --deep",
        "openclaw-cn security audit --fix",
        "",
        "必读：https://clawd.org.cn/gateway/security.html",
    ].join("\n"), "安全");
    const ok = await params.prompter.confirm({
        message: "我理解这很强大且本质上存在风险。继续吗？",
        initialValue: false,
    });
    if (!ok) {
        throw new WizardCancelledError("risk not accepted");
    }
}
export async function runOnboardingWizard(opts, runtime = defaultRuntime, prompter) {
    printWizardHeader(runtime);
    await prompter.intro("OpenClaw 安装引导");
    await requireRiskAcknowledgement({ opts, prompter });
    const snapshot = await readConfigFileSnapshot();
    let baseConfig = snapshot.valid ? snapshot.config : {};
    if (snapshot.exists && !snapshot.valid) {
        await prompter.note(summarizeExistingConfig(baseConfig), "配置无效");
        if (snapshot.issues.length > 0) {
            await prompter.note([
                ...snapshot.issues.map((iss) => `- ${iss.path}: ${iss.message}`),
                "",
                "文档：https://clawd.org.cn/gateway/configuration-examples.html",
            ].join("\n"), "配置问题");
        }
        await prompter.outro(`配置无效。运行 \${formatCliCommand("openclaw-cn doctor")} 修复它，然后重新运行安装引导。`);
        runtime.exit(1);
        return;
    }
    const quickstartHint = `稍后通过 ${formatCliCommand("openclaw-cn configure")} 配置详细信息。`;
    const manualHint = "配置端口、网络、Tailscale 和认证选项。";
    const explicitFlowRaw = opts.flow?.trim();
    const normalizedExplicitFlow = explicitFlowRaw === "manual" ? "advanced" : explicitFlowRaw;
    if (normalizedExplicitFlow &&
        normalizedExplicitFlow !== "quickstart" &&
        normalizedExplicitFlow !== "advanced") {
        runtime.error("无效的 --flow（使用 quickstart、manual 或 advanced）。");
        runtime.exit(1);
        return;
    }
    const explicitFlow = normalizedExplicitFlow === "quickstart" || normalizedExplicitFlow === "advanced"
        ? normalizedExplicitFlow
        : undefined;
    let flow = explicitFlow ??
        (await prompter.select({
            message: "安装引导模式",
            options: [
                { value: "quickstart", label: "快速开始", hint: quickstartHint },
                { value: "advanced", label: "手动", hint: manualHint },
            ],
            initialValue: "quickstart",
        }));
    if (opts.mode === "remote" && flow === "quickstart") {
        await prompter.note("快速开始仅支持本地网关。切换到手动模式。", "快速开始");
        flow = "advanced";
    }
    if (snapshot.exists) {
        await prompter.note(summarizeExistingConfig(baseConfig), "检测到现有配置");
        const action = (await prompter.select({
            message: "配置处理",
            options: [
                { value: "keep", label: "使用现有值" },
                { value: "modify", label: "更新值" },
                { value: "reset", label: "重置" },
            ],
        }));
        if (action === "reset") {
            const workspaceDefault = baseConfig.agents?.defaults?.workspace ?? DEFAULT_WORKSPACE;
            const resetScope = (await prompter.select({
                message: "重置范围",
                options: [
                    { value: "config", label: "仅配置" },
                    {
                        value: "config+creds+sessions",
                        label: "配置 + 凭据 + 会话",
                    },
                    {
                        value: "full",
                        label: "完全重置（配置 + 凭据 + 会话 + 工作区）",
                    },
                ],
            }));
            await handleReset(resetScope, resolveUserPath(workspaceDefault), runtime);
            baseConfig = {};
        }
    }
    const quickstartGateway = (() => {
        const hasExisting = typeof baseConfig.gateway?.port === "number" ||
            baseConfig.gateway?.bind !== undefined ||
            baseConfig.gateway?.auth?.mode !== undefined ||
            baseConfig.gateway?.auth?.token !== undefined ||
            baseConfig.gateway?.auth?.password !== undefined ||
            baseConfig.gateway?.customBindHost !== undefined ||
            baseConfig.gateway?.tailscale?.mode !== undefined;
        const bindRaw = baseConfig.gateway?.bind;
        const bind = bindRaw === "loopback" ||
            bindRaw === "lan" ||
            bindRaw === "auto" ||
            bindRaw === "custom" ||
            bindRaw === "tailnet"
            ? bindRaw
            : "loopback";
        let authMode = "token";
        if (baseConfig.gateway?.auth?.mode === "token" ||
            baseConfig.gateway?.auth?.mode === "password") {
            authMode = baseConfig.gateway.auth.mode;
        }
        else if (baseConfig.gateway?.auth?.token) {
            authMode = "token";
        }
        else if (baseConfig.gateway?.auth?.password) {
            authMode = "password";
        }
        const tailscaleRaw = baseConfig.gateway?.tailscale?.mode;
        const tailscaleMode = tailscaleRaw === "off" || tailscaleRaw === "serve" || tailscaleRaw === "funnel"
            ? tailscaleRaw
            : "off";
        return {
            hasExisting,
            port: resolveGatewayPort(baseConfig),
            bind,
            authMode,
            tailscaleMode,
            token: baseConfig.gateway?.auth?.token,
            password: baseConfig.gateway?.auth?.password,
            customBindHost: baseConfig.gateway?.customBindHost,
            tailscaleResetOnExit: baseConfig.gateway?.tailscale?.resetOnExit ?? false,
        };
    })();
    if (flow === "quickstart") {
        const formatBind = (value) => {
            if (value === "loopback")
                return "环回（127.0.0.1）";
            if (value === "lan")
                return "局域网";
            if (value === "custom")
                return "自定义 IP";
            if (value === "tailnet")
                return "Tailnet（Tailscale IP）";
            return "自动";
        };
        const formatAuth = (value) => {
            if (value === "off")
                return "关闭（仅环回）";
            if (value === "token")
                return "令牌（默认）";
            return "密码";
        };
        const formatTailscale = (value) => {
            if (value === "off")
                return "关闭";
            if (value === "serve")
                return "服务";
            return "隧道";
        };
        const quickstartLines = quickstartGateway.hasExisting
            ? [
                "保留您当前的网关设置：",
                `网关端口：${quickstartGateway.port}`,
                `网关绑定：${formatBind(quickstartGateway.bind)}`,
                ...(quickstartGateway.bind === "custom" && quickstartGateway.customBindHost
                    ? [`网关自定义 IP：${quickstartGateway.customBindHost}`]
                    : []),
                `网关认证：${formatAuth(quickstartGateway.authMode)}`,
                `Tailscale 暴露：${formatTailscale(quickstartGateway.tailscaleMode)}`,
                "直接到聊天频道。",
            ]
            : [
                `网关端口：${DEFAULT_GATEWAY_PORT}`,
                "网关绑定：环回（127.0.0.1）",
                "网关认证：令牌（默认）",
                "Tailscale 暴露：关闭",
                "直接到聊天频道。",
            ];
        await prompter.note(quickstartLines.join("\n"), "快速开始");
    }
    const localPort = resolveGatewayPort(baseConfig);
    const localUrl = `ws://127.0.0.1:${localPort}`;
    const localProbe = await probeGatewayReachable({
        url: localUrl,
        token: baseConfig.gateway?.auth?.token ?? process.env.OPENCLAW_GATEWAY_TOKEN,
        password: baseConfig.gateway?.auth?.password ?? process.env.OPENCLAW_GATEWAY_PASSWORD,
    });
    const remoteUrl = baseConfig.gateway?.remote?.url?.trim() ?? "";
    const remoteProbe = remoteUrl
        ? await probeGatewayReachable({
            url: remoteUrl,
            token: baseConfig.gateway?.remote?.token,
        })
        : null;
    const mode = opts.mode ??
        (flow === "quickstart"
            ? "local"
            : (await prompter.select({
                message: "您想要设置什么？",
                options: [
                    {
                        value: "local",
                        label: "本地网关（此机器）",
                        hint: localProbe.ok ? `网关可达（${localUrl}）` : `未检测到网关（${localUrl}）`,
                    },
                    {
                        value: "remote",
                        label: "远程网关（仅信息）",
                        hint: !remoteUrl
                            ? "尚未配置远程 URL"
                            : remoteProbe?.ok
                                ? `网关可达（${remoteUrl}）`
                                : `已配置但不可达（${remoteUrl}）`,
                    },
                ],
            })));
    if (mode === "remote") {
        let nextConfig = await promptRemoteGatewayConfig(baseConfig, prompter);
        nextConfig = applyWizardMetadata(nextConfig, { command: "onboard", mode });
        await writeConfigFile(nextConfig);
        logConfigUpdated(runtime);
        await prompter.outro("远程网关已配置。");
        return;
    }
    const workspaceInput = opts.workspace ??
        (flow === "quickstart"
            ? (baseConfig.agents?.defaults?.workspace ?? DEFAULT_WORKSPACE)
            : await prompter.text({
                message: "工作区目录",
                initialValue: baseConfig.agents?.defaults?.workspace ?? DEFAULT_WORKSPACE,
            }));
    const workspaceDir = resolveUserPath(workspaceInput.trim() || DEFAULT_WORKSPACE);
    let nextConfig = {
        ...baseConfig,
        agents: {
            ...baseConfig.agents,
            defaults: {
                ...baseConfig.agents?.defaults,
                workspace: workspaceDir,
            },
        },
        gateway: {
            ...baseConfig.gateway,
            mode: "local",
        },
    };
    const authStore = ensureAuthProfileStore(undefined, {
        allowKeychainPrompt: false,
    });
    const authChoiceFromPrompt = opts.authChoice === undefined;
    const authChoice = opts.authChoice ??
        (await promptAuthChoiceGrouped({
            prompter,
            store: authStore,
            includeSkip: true,
            includeClaudeCliIfMissing: true,
        }));
    const authResult = await applyAuthChoice({
        authChoice,
        config: nextConfig,
        prompter,
        runtime,
        setDefaultModel: true,
        opts: {
            tokenProvider: opts.tokenProvider,
            token: opts.authChoice === "apiKey" && opts.token ? opts.token : undefined,
            volcengineApiKey: opts.volcengineApiKey,
            xiaomiApiKey: opts.xiaomiApiKey,
        },
    });
    nextConfig = authResult.config;
    if (authChoiceFromPrompt && !authResult.agentModelOverride) {
        const modelSelection = await promptDefaultModel({
            config: nextConfig,
            prompter,
            allowKeep: true,
            ignoreAllowlist: true,
            preferredProvider: resolvePreferredProviderForAuthChoice(authChoice),
        });
        if (modelSelection.model) {
            nextConfig = applyPrimaryModel(nextConfig, modelSelection.model);
        }
    }
    await warnIfModelConfigLooksOff(nextConfig, prompter);
    const gateway = await configureGatewayForOnboarding({
        flow,
        baseConfig,
        nextConfig,
        localPort,
        quickstartGateway,
        prompter,
        runtime,
    });
    nextConfig = gateway.nextConfig;
    const settings = gateway.settings;
    if (opts.skipChannels ?? opts.skipProviders) {
        await prompter.note("跳过频道设置。", "频道");
    }
    else {
        const quickstartAllowFromChannels = flow === "quickstart"
            ? listChannelPlugins()
                .filter((plugin) => plugin.meta.quickstartAllowFrom)
                .map((plugin) => plugin.id)
            : [];
        nextConfig = await setupChannels(nextConfig, runtime, prompter, {
            allowSignalInstall: true,
            forceAllowFromChannels: quickstartAllowFromChannels,
            skipDmPolicyPrompt: flow === "quickstart",
            skipConfirm: flow === "quickstart",
            quickstartDefaults: flow === "quickstart",
        });
    }
    await writeConfigFile(nextConfig);
    logConfigUpdated(runtime);
    await ensureWorkspaceAndSessions(workspaceDir, runtime, {
        skipBootstrap: Boolean(nextConfig.agents?.defaults?.skipBootstrap),
    });
    if (opts.skipSkills) {
        await prompter.note("跳过技能设置。", "技能");
    }
    else {
        nextConfig = await setupSkills(nextConfig, workspaceDir, runtime, prompter);
    }
    // Setup hooks (session memory on /new)
    nextConfig = await setupInternalHooks(nextConfig, runtime, prompter);
    nextConfig = applyWizardMetadata(nextConfig, { command: "onboard", mode });
    await writeConfigFile(nextConfig);
    await finalizeOnboardingWizard({
        flow,
        opts,
        baseConfig,
        nextConfig,
        workspaceDir,
        settings,
        prompter,
        runtime,
    });
}
