import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";

const ensureAuthProfileStoreMock = vi.hoisted(() => vi.fn());
const listProfilesForProviderMock = vi.hoisted(() => vi.fn());
const coerceSecretRefMock = vi.hoisted(() => vi.fn());
const resolveRequiredConfiguredSecretRefInputStringMock = vi.hoisted(() => vi.fn());

vi.mock("openclaw/plugin-sdk/provider-auth", () => ({
  coerceSecretRef: coerceSecretRefMock,
  ensureAuthProfileStore: ensureAuthProfileStoreMock,
  listProfilesForProvider: listProfilesForProviderMock,
}));

vi.mock("openclaw/plugin-sdk/config-runtime", () => ({
  resolveRequiredConfiguredSecretRefInputString: resolveRequiredConfiguredSecretRefInputStringMock,
}));

import { resolveFirstGithubToken } from "./auth.js";

describe("resolveFirstGithubToken", () => {
  beforeEach(() => {
    ensureAuthProfileStoreMock.mockReturnValue({
      profiles: {
        "github-copilot:github": {
          type: "token",
          tokenRef: { source: "file", provider: "default", id: "/providers/github-copilot/token" },
        },
      },
    });
    listProfilesForProviderMock.mockReturnValue(["github-copilot:github"]);
    coerceSecretRefMock.mockReturnValue({
      source: "file",
      provider: "default",
      id: "/providers/github-copilot/token",
    });
    resolveRequiredConfiguredSecretRefInputStringMock.mockResolvedValue("resolved-profile-token");
  });

  afterEach(() => {
    vi.restoreAllMocks();
    ensureAuthProfileStoreMock.mockReset();
    listProfilesForProviderMock.mockReset();
    coerceSecretRefMock.mockReset();
    resolveRequiredConfiguredSecretRefInputStringMock.mockReset();
  });

  it("prefers env tokens when available", async () => {
    const result = await resolveFirstGithubToken({
      env: { GH_TOKEN: "env-token" } as NodeJS.ProcessEnv,
    });

    expect(result).toEqual({
      githubToken: "env-token",
      hasProfile: true,
    });
    expect(resolveRequiredConfiguredSecretRefInputStringMock).not.toHaveBeenCalled();
  });

  it("returns direct profile tokens before resolving SecretRefs", async () => {
    ensureAuthProfileStoreMock.mockReturnValue({
      profiles: {
        "github-copilot:github": {
          type: "token",
          token: "profile-token",
        },
      },
    });
    coerceSecretRefMock.mockReturnValue(null);

    const result = await resolveFirstGithubToken({
      env: {} as NodeJS.ProcessEnv,
    });

    expect(result).toEqual({
      githubToken: "profile-token",
      hasProfile: true,
    });
  });

  it("resolves non-env SecretRefs when config is available", async () => {
    const result = await resolveFirstGithubToken({
      config: { secrets: { defaults: { provider: "default" } } } as never,
      env: {} as NodeJS.ProcessEnv,
    });

    expect(result).toEqual({
      githubToken: "resolved-profile-token",
      hasProfile: true,
    });
    expect(resolveRequiredConfiguredSecretRefInputStringMock).toHaveBeenCalledWith(
      expect.objectContaining({
        path: "providers.github-copilot.authProfiles.github-copilot:github.tokenRef",
      }),
    );
  });
});
