import { afterEach, describe, expect, it, vi } from "vitest";
import { resolveAgentModelPrimaryValue } from "../config/model-input.js";
import type { WizardPrompter } from "../wizard/prompts.js";
import { applyAuthChoiceMiniMax } from "./auth-choice.apply.minimax.js";
import {
  createAuthTestLifecycle,
  createExitThrowingRuntime,
  createWizardPrompter,
  readAuthProfilesForAgent,
  setupAuthTestEnv,
} from "./test-wizard-helpers.js";

function createMinimaxPrompter(
  params: {
    text?: WizardPrompter["text"];
    confirm?: WizardPrompter["confirm"];
    select?: WizardPrompter["select"];
  } = {},
): WizardPrompter {
  return createWizardPrompter(
    {
      text: params.text,
      confirm: params.confirm,
      select: params.select,
    },
    { defaultSelect: "oauth" },
  );
}

describe("applyAuthChoiceMiniMax", () => {
  const lifecycle = createAuthTestLifecycle([
    "OPENCLAW_STATE_DIR",
    "OPENCLAW_AGENT_DIR",
    "PI_CODING_AGENT_DIR",
    "MINIMAX_API_KEY",
    "MINIMAX_OAUTH_TOKEN",
  ]);

  async function setupTempState() {
    const env = await setupAuthTestEnv("openclaw-minimax-");
    lifecycle.setStateDir(env.stateDir);
    return env.agentDir;
  }

  async function readAuthProfiles(agentDir: string) {
    return await readAuthProfilesForAgent<{
      profiles?: Record<string, { key?: string; keyRef?: { source: string; id: string } }>;
    }>(agentDir);
  }

  function resetMiniMaxEnv(): void {
    delete process.env.MINIMAX_API_KEY;
    delete process.env.MINIMAX_OAUTH_TOKEN;
  }

  async function runMiniMaxChoice(params: {
    authChoice: Parameters<typeof applyAuthChoiceMiniMax>[0]["authChoice"];
    opts?: Parameters<typeof applyAuthChoiceMiniMax>[0]["opts"];
    env?: { apiKey?: string; oauthToken?: string };
    prompter?: Parameters<typeof createMinimaxPrompter>[0];
  }) {
    const agentDir = await setupTempState();
    resetMiniMaxEnv();
    if (params.env?.apiKey !== undefined) {
      process.env.MINIMAX_API_KEY = params.env.apiKey;
    }
    if (params.env?.oauthToken !== undefined) {
      process.env.MINIMAX_OAUTH_TOKEN = params.env.oauthToken;
    }

    const text = vi.fn(async () => "should-not-be-used");
    const confirm = vi.fn(async () => true);
    const result = await applyAuthChoiceMiniMax({
      authChoice: params.authChoice,
      config: {},
      prompter: createMinimaxPrompter({
        text,
        confirm,
        ...params.prompter,
      }),
      runtime: createExitThrowingRuntime(),
      setDefaultModel: true,
      ...(params.opts ? { opts: params.opts } : {}),
    });

    return { agentDir, result, text, confirm };
  }

  afterEach(async () => {
    await lifecycle.cleanup();
  });

  it("returns null for unrelated authChoice", async () => {
    const result = await applyAuthChoiceMiniMax({
      authChoice: "openrouter-api-key",
      config: {},
      prompter: createMinimaxPrompter(),
      runtime: createExitThrowingRuntime(),
      setDefaultModel: true,
    });

    expect(result).toBeNull();
  });

  it.each([
    {
      caseName: "uses opts token for minimax-api without prompt",
      authChoice: "minimax-api" as const,
      tokenProvider: "minimax",
      token: "mm-opts-token",
      profileId: "minimax:default",
      provider: "minimax",
      expectedModel: "minimax/MiniMax-M2.5",
    },
    {
      caseName:
        "uses opts token for minimax-api-key-cn with trimmed/case-insensitive tokenProvider",
      authChoice: "minimax-api-key-cn" as const,
      tokenProvider: "  MINIMAX-CN  ",
      token: "mm-cn-opts-token",
      profileId: "minimax-cn:default",
      provider: "minimax-cn",
      expectedModel: "minimax-cn/MiniMax-M2.5",
    },
  ])(
    "$caseName",
    async ({ authChoice, tokenProvider, token, profileId, provider, expectedModel }) => {
      const { agentDir, result, text, confirm } = await runMiniMaxChoice({
        authChoice,
        opts: {
          tokenProvider,
          token,
        },
      });

      expect(result).not.toBeNull();
      expect(result?.config.auth?.profiles?.[profileId]).toMatchObject({
        provider,
        mode: "api_key",
      });
      expect(resolveAgentModelPrimaryValue(result?.config.agents?.defaults?.model)).toBe(
        expectedModel,
      );
      expect(text).not.toHaveBeenCalled();
      expect(confirm).not.toHaveBeenCalled();

      const parsed = await readAuthProfiles(agentDir);
      expect(parsed.profiles?.[profileId]?.key).toBe(token);
    },
  );

  it.each([
    {
      name: "uses env token for minimax-api-key-cn as plaintext by default",
      opts: undefined,
      expectKey: "mm-env-token",
      expectKeyRef: undefined,
      expectConfirmCalls: 1,
    },
    {
      name: "uses env token for minimax-api-key-cn as keyRef in ref mode",
      opts: { secretInputMode: "ref" as const },
      expectKey: undefined,
      expectKeyRef: {
        source: "env",
        provider: "default",
        id: "MINIMAX_API_KEY",
      },
      expectConfirmCalls: 0,
    },
  ])("$name", async ({ opts, expectKey, expectKeyRef, expectConfirmCalls }) => {
    const { agentDir, result, text, confirm } = await runMiniMaxChoice({
      authChoice: "minimax-api-key-cn",
      opts,
      env: { apiKey: "mm-env-token" },
    });

    expect(result).not.toBeNull();
    if (!opts) {
      expect(result?.config.auth?.profiles?.["minimax-cn:default"]).toMatchObject({
        provider: "minimax-cn",
        mode: "api_key",
      });
      expect(resolveAgentModelPrimaryValue(result?.config.agents?.defaults?.model)).toBe(
        "minimax-cn/MiniMax-M2.5",
      );
    }
    expect(text).not.toHaveBeenCalled();
    expect(confirm).toHaveBeenCalledTimes(expectConfirmCalls);

    const parsed = await readAuthProfiles(agentDir);
    expect(parsed.profiles?.["minimax-cn:default"]?.key).toBe(expectKey);
    if (expectKeyRef) {
      expect(parsed.profiles?.["minimax-cn:default"]?.keyRef).toEqual(expectKeyRef);
    } else {
      expect(parsed.profiles?.["minimax-cn:default"]?.keyRef).toBeUndefined();
    }
  });

  it("uses minimax-api-lightning default model", async () => {
    const { agentDir, result, text, confirm } = await runMiniMaxChoice({
      authChoice: "minimax-api-lightning",
      opts: {
        tokenProvider: "minimax",
        token: "mm-lightning-token",
      },
    });

    expect(result).not.toBeNull();
    expect(result?.config.auth?.profiles?.["minimax:default"]).toMatchObject({
      provider: "minimax",
      mode: "api_key",
    });
    expect(resolveAgentModelPrimaryValue(result?.config.agents?.defaults?.model)).toBe(
      "minimax/MiniMax-M2.5-highspeed",
    );
    expect(text).not.toHaveBeenCalled();
    expect(confirm).not.toHaveBeenCalled();

    const parsed = await readAuthProfiles(agentDir);
    expect(parsed.profiles?.["minimax:default"]?.key).toBe("mm-lightning-token");
  });
});
