import { describe, expect, it } from "vitest";
import { useProviderDialogs } from "../src/dimsdk/pages/utils/provider-dialogs.ts";

function createStore(
  input?: Partial<{
    activeId: string;
    connections: Record<string, any>;
    customProviders: any[];
    activeModelByProvider: Record<string, string>;
    env: Record<string, string>;
    cwd: string;
    model: string;
    contextWindow: number;
    sessionId: string;
  }>,
): any {
  const env = { ...input?.env };
  return {
    state: {
      ui: {
        onboarding: {
          lastSeenVersion: "",
        },
        providerFunnel: {
          counts: {},
          events: [],
        },
        workspaceSelectionByCwd: {},
      },
      provider: {
        activeId: input?.activeId ?? "openai",
        connections: input?.connections ?? {},
        customProviders: input?.customProviders ?? [],
        activeModelByProvider: input?.activeModelByProvider ?? {},
      },
      config: {
        model: input?.model ?? "",
        context_window: input?.contextWindow ?? 128000,
      },
      sessionId: input?.sessionId ?? "",
      context: { env, cwd: input?.cwd ?? "." },
    },
    setEnvVar: (key: string, value: string | undefined) => {
      if (value == null) {
        delete env[key];
      } else {
        env[key] = String(value);
      }
    },
  };
}

function findProviderOption(dialogs: ReturnType<typeof useProviderDialogs>, keyword: string) {
  return dialogs.providerOptions.value.find((option) => (option.keywords ?? []).includes(keyword));
}

describe("provider dialogs connect ux", () => {
  it("shows first-use 3-step guide once before regular connect reminder", () => {
    const prev = process.env.DIMCODE_TEST;
    delete process.env.DIMCODE_TEST;
    try {
      const toasts: string[] = [];
      const store = createStore({
        activeId: "openai",
        connections: {},
      });
      const dialogs = useProviderDialogs({
        store,
        nodeLike: false,
        showToast: (text: string) => toasts.push(text),
        openCustomSettings: () => {},
      });

      expect(dialogs.ensureActiveProviderReadyForChat()).toBe(false);
      expect(toasts[0]).toContain("1) /connect");
      expect(dialogs.ensureActiveProviderReadyForChat()).toBe(false);
      expect(
        toasts.some(
          (text) => text.includes("connect a provider first") || text.includes("先连接提供方"),
        ),
      ).toBe(true);
    } finally {
      if (prev == null) {
        delete process.env.DIMCODE_TEST;
      } else {
        process.env.DIMCODE_TEST = prev;
      }
    }
  });

  it("auto-fetches models after first custom provider connect when no models are set", () => {
    const toasts: string[] = [];
    const store = createStore({ activeId: "openai" });
    const dialogs = useProviderDialogs({
      store,
      nodeLike: false,
      showToast: (text: string) => toasts.push(text),
      openCustomSettings: () => {},
    });

    dialogs.openConnect();
    const addCustomOption = dialogs.providerOptions.value.find(
      (o) => o.detail === "add custom provider",
    );
    expect(addCustomOption).toBeTruthy();
    dialogs.onSelectProvider(addCustomOption?.label ?? null);
    expect(dialogs.showCustomType.value).toBe(true);

    const openAiOption = dialogs.customTypeOptions.value.find((o) => o.detail === "openai");
    expect(openAiOption).toBeTruthy();
    dialogs.onSelectCustomType(openAiOption?.label ?? null);
    expect(dialogs.showCustomConnectDialog.value).toBe(true);

    dialogs.customConnectBaseUrl.value = "https://example.com/chat/completions";
    dialogs.customConnectApiKeyDraft.value = "sk-test";
    dialogs.applyCustomConnect();

    expect(dialogs.showCustomConnectDialog.value).toBe(false);
    expect(dialogs.showCustomModelsDialog.value).toBe(true);
    expect(toasts.some((text) => text.includes("No models yet. Fetching model list"))).toBe(true);
  });

  it("keeps the custom connect dialog open and shows an API key toast when apply is pressed empty", () => {
    const toasts: string[] = [];
    const store = createStore({ activeId: "openai" });
    const dialogs = useProviderDialogs({
      store,
      nodeLike: false,
      showToast: (text: string) => toasts.push(text),
      openCustomSettings: () => {},
    });

    dialogs.openConnect();
    const addCustomOption = dialogs.providerOptions.value.find(
      (o) => o.detail === "add custom provider",
    );
    expect(addCustomOption).toBeTruthy();
    dialogs.onSelectProvider(addCustomOption?.label ?? null);
    expect(dialogs.showCustomType.value).toBe(true);

    const openAiOption = dialogs.customTypeOptions.value.find((o) => o.detail === "openai");
    expect(openAiOption).toBeTruthy();
    dialogs.onSelectCustomType(openAiOption?.label ?? null);
    expect(dialogs.showCustomConnectDialog.value).toBe(true);

    dialogs.customConnectBaseUrl.value = "https://example.com/v1";
    dialogs.customConnectApiKeyDraft.value = "";
    dialogs.applyCustomConnect();

    expect(dialogs.showCustomConnectDialog.value).toBe(true);
    expect(dialogs.showCustomModelsDialog.value).toBe(false);
    expect(toasts.some((text) => text.includes("API key is required."))).toBe(true);
  });

  it("returns to the provider picker when cancelling the add custom provider flow", () => {
    const store = createStore({ activeId: "openai" });
    const dialogs = useProviderDialogs({
      store,
      nodeLike: false,
      showToast: () => {},
      openCustomSettings: () => {},
    });

    dialogs.openConnect();
    const addCustomOption = dialogs.providerOptions.value.find(
      (o) => o.detail === "add custom provider",
    );
    expect(addCustomOption).toBeTruthy();
    dialogs.onSelectProvider(addCustomOption?.label ?? null);
    expect(dialogs.showConnect.value).toBe(false);
    expect(dialogs.showCustomType.value).toBe(true);

    dialogs.closeCustomType();
    expect(dialogs.showCustomType.value).toBe(false);
    expect(dialogs.showConnect.value).toBe(true);

    dialogs.onSelectProvider(addCustomOption?.label ?? null);
    const openAiOption = dialogs.customTypeOptions.value.find((o) => o.detail === "openai");
    expect(openAiOption).toBeTruthy();
    dialogs.onSelectCustomType(openAiOption?.label ?? null);
    expect(dialogs.showCustomConnectDialog.value).toBe(true);

    dialogs.cancelCustomConnectDialog();
    expect(dialogs.showCustomConnectDialog.value).toBe(false);
    expect(dialogs.showConnect.value).toBe(true);
  });

  it("does not auto-append /v1 when editing OpenAI-compatible base URLs", () => {
    const store = createStore({ activeId: "openai" });
    const dialogs = useProviderDialogs({
      store,
      nodeLike: false,
      showToast: () => {},
      openCustomSettings: () => {},
    });

    dialogs.openConnect();
    const openaiOption = findProviderOption(dialogs, "openai");
    expect(openaiOption).toBeTruthy();
    dialogs.onSelectProvider(openaiOption?.label ?? null);
    dialogs.updateConnectBaseUrlDraft("https://proxy.example.com");
    expect(dialogs.connectBaseUrl.value).toBe("https://proxy.example.com");

    dialogs.openConnect();
    const addCustomOption = dialogs.providerOptions.value.find(
      (o) => o.detail === "add custom provider",
    );
    expect(addCustomOption).toBeTruthy();
    dialogs.onSelectProvider(addCustomOption?.label ?? null);
    expect(dialogs.showCustomType.value).toBe(true);
    const customOpenAiOption = dialogs.customTypeOptions.value.find((o) => o.detail === "openai");
    expect(customOpenAiOption).toBeTruthy();
    dialogs.onSelectCustomType(customOpenAiOption?.label ?? null);
    dialogs.updateCustomConnectBaseUrlDraft("https://proxy.example.com");
    expect(dialogs.customConnectBaseUrl.value).toBe("https://proxy.example.com");
  });
});
