import { describe, expect, it, vi } from "vitest";
import { createWizardPrompter } from "../../test/helpers/wizard-prompter.js";
import { createNonExitingRuntime } from "../runtime.js";
import { runSearchSetupFlow } from "./search-setup.js";

const mockGrokProvider = vi.hoisted(() => ({
  id: "grok",
  pluginId: "xai",
  label: "Grok",
  hint: "Search with xAI",
  docsUrl: "https://docs.openclaw.ai/tools/web",
  requiresCredential: true,
  credentialLabel: "xAI API key",
  placeholder: "xai-...",
  signupUrl: "https://x.ai/api",
  envVars: ["XAI_API_KEY"],
  onboardingScopes: ["text-inference"],
  credentialPath: "plugins.entries.xai.config.webSearch.apiKey",
  getCredentialValue: (search?: Record<string, unknown>) => search?.apiKey,
  setCredentialValue: (searchConfigTarget: Record<string, unknown>, value: unknown) => {
    searchConfigTarget.apiKey = value;
  },
  getConfiguredCredentialValue: (config?: Record<string, unknown>) =>
    (
      config?.plugins as
        | {
            entries?: Record<
              string,
              {
                config?: {
                  webSearch?: { apiKey?: unknown };
                };
              }
            >;
          }
        | undefined
    )?.entries?.xai?.config?.webSearch?.apiKey,
  setConfiguredCredentialValue: (configTarget: Record<string, unknown>, value: unknown) => {
    const plugins = (configTarget.plugins ??= {}) as Record<string, unknown>;
    const entries = (plugins.entries ??= {}) as Record<string, unknown>;
    const xaiEntry = (entries.xai ??= {}) as Record<string, unknown>;
    const xaiConfig = (xaiEntry.config ??= {}) as Record<string, unknown>;
    const webSearch = (xaiConfig.webSearch ??= {}) as Record<string, unknown>;
    webSearch.apiKey = value;
  },
  runSetup: async ({
    config,
    prompter,
  }: {
    config: Record<string, unknown>;
    prompter: { select: (params: Record<string, unknown>) => Promise<string> };
  }) => {
    const enableXSearch = await prompter.select({
      message: "Enable x_search",
      options: [
        { value: "yes", label: "Yes" },
        { value: "no", label: "No" },
      ],
    });
    if (enableXSearch !== "yes") {
      return config;
    }
    const model = await prompter.select({
      message: "Grok model",
      options: [{ value: "grok-4-1-fast", label: "grok-4-1-fast" }],
    });
    const pluginEntries = (config.plugins as { entries?: Record<string, unknown> } | undefined)
      ?.entries;
    const existingXaiEntry = pluginEntries?.xai as Record<string, unknown> | undefined;
    const existingXaiConfig = (
      pluginEntries?.xai as { config?: Record<string, unknown> } | undefined
    )?.config;
    return {
      ...config,
      plugins: {
        ...(config.plugins as Record<string, unknown> | undefined),
        entries: {
          ...pluginEntries,
          xai: {
            ...existingXaiEntry,
            config: {
              ...existingXaiConfig,
              xSearch: {
                enabled: true,
                model,
              },
            },
          },
        },
      },
    };
  },
}));

vi.mock("../plugins/web-search-providers.runtime.js", () => ({
  resolvePluginWebSearchProviders: () => [mockGrokProvider],
}));

describe("runSearchSetupFlow", () => {
  it("runs provider-owned setup after selecting Grok web search", async () => {
    const select = vi
      .fn()
      .mockResolvedValueOnce("grok")
      .mockResolvedValueOnce("yes")
      .mockResolvedValueOnce("grok-4-1-fast");
    const text = vi.fn().mockResolvedValue("xai-test-key");
    const prompter = createWizardPrompter({
      select: select as never,
      text: text as never,
    });

    const next = await runSearchSetupFlow(
      { plugins: { allow: ["xai"] } },
      createNonExitingRuntime(),
      prompter,
    );

    expect(next.plugins?.entries?.xai?.config?.webSearch).toMatchObject({
      apiKey: "xai-test-key",
    });
    expect(next.tools?.web?.search).toMatchObject({
      provider: "grok",
      enabled: true,
    });
    expect(next.plugins?.entries?.xai?.config?.xSearch).toMatchObject({
      enabled: true,
      model: "grok-4-1-fast",
    });
  });

  it("preserves disabled web_search state while still allowing provider-owned x_search setup", async () => {
    const select = vi
      .fn()
      .mockResolvedValueOnce("grok")
      .mockResolvedValueOnce("yes")
      .mockResolvedValueOnce("grok-4-1-fast");
    const prompter = createWizardPrompter({
      select: select as never,
    });

    const next = await runSearchSetupFlow(
      {
        plugins: {
          allow: ["xai"],
          entries: {
            xai: {
              enabled: true,
              config: {
                webSearch: {
                  apiKey: "xai-test-key",
                },
              },
            },
          },
        },
        tools: {
          web: {
            search: {
              provider: "grok",
              enabled: false,
            },
          },
        },
      },
      createNonExitingRuntime(),
      prompter,
    );

    expect(next.tools?.web?.search).toMatchObject({
      provider: "grok",
      enabled: false,
    });
    expect(next.plugins?.entries?.xai?.config?.xSearch).toMatchObject({
      enabled: true,
      model: "grok-4-1-fast",
    });
  });
});
