import { beforeEach, describe, expect, it, vi } from "vitest";
import type { AuthProfileStore } from "../../agents/auth-profiles.js";
import type { OpenClawConfig } from "../../config/config.js";

let mockStore: AuthProfileStore;
let mockAllowedProfiles: string[];

const resolveAuthProfileOrderMock = vi.fn(() => mockAllowedProfiles);
const resolveAuthProfileEligibilityMock = vi.fn(() => ({
  eligible: false,
  reasonCode: "invalid_expires" as const,
}));
const resolveSecretRefStringMock = vi.fn(async () => "resolved-secret");

vi.mock("../../agents/model-catalog.js", () => ({
  loadModelCatalog: vi.fn(async () => []),
}));
vi.mock("../../secrets/resolve.js", () => ({
  resolveSecretRefString: resolveSecretRefStringMock,
}));

vi.mock("../../agents/auth-profiles.js", async (importOriginal) => {
  const actual = await importOriginal<typeof import("../../agents/auth-profiles.js")>();
  return {
    ...actual,
    ensureAuthProfileStore: () => mockStore,
    listProfilesForProvider: (_store: AuthProfileStore, provider: string) =>
      Object.entries(mockStore.profiles)
        .filter(
          ([, profile]) =>
            typeof profile.provider === "string" && profile.provider.toLowerCase() === provider,
        )
        .map(([profileId]) => profileId),
    resolveAuthProfileDisplayLabel: ({ profileId }: { profileId: string }) => profileId,
    resolveAuthProfileOrder: resolveAuthProfileOrderMock,
    resolveAuthProfileEligibility: resolveAuthProfileEligibilityMock,
  };
});

const { buildProbeTargets } = await import("./list.probe.js");

describe("buildProbeTargets reason codes", () => {
  beforeEach(() => {
    mockStore = {
      version: 1,
      profiles: {
        "anthropic:default": {
          type: "token",
          provider: "anthropic",
          tokenRef: { source: "env", provider: "default", id: "ANTHROPIC_TOKEN" },
          expires: 0,
        },
      },
      order: {
        anthropic: ["anthropic:default"],
      },
    };
    mockAllowedProfiles = [];
    resolveAuthProfileOrderMock.mockClear();
    resolveAuthProfileEligibilityMock.mockClear();
    resolveSecretRefStringMock.mockReset();
    resolveSecretRefStringMock.mockResolvedValue("resolved-secret");
    resolveAuthProfileEligibilityMock.mockReturnValue({
      eligible: false,
      reasonCode: "invalid_expires",
    });
  });

  it("reports invalid_expires with a legacy-compatible first error line", async () => {
    const plan = await buildProbeTargets({
      cfg: {
        auth: {
          order: {
            anthropic: ["anthropic:default"],
          },
        },
      } as OpenClawConfig,
      providers: ["anthropic"],
      modelCandidates: ["anthropic/claude-sonnet-4-6"],
      options: {
        timeoutMs: 5_000,
        concurrency: 1,
        maxTokens: 16,
      },
    });

    expect(plan.targets).toHaveLength(0);
    expect(plan.results).toHaveLength(1);
    expect(plan.results[0]?.reasonCode).toBe("invalid_expires");
    expect(plan.results[0]?.error?.split("\n")[0]).toBe(
      "Auth profile credentials are missing or expired.",
    );
    expect(plan.results[0]?.error).toContain("[invalid_expires]");
  });

  it("reports excluded_by_auth_order when profile id is not present in explicit order", async () => {
    mockStore.order = {
      anthropic: ["anthropic:work"],
    };
    const plan = await buildProbeTargets({
      cfg: {
        auth: {
          order: {
            anthropic: ["anthropic:work"],
          },
        },
      } as OpenClawConfig,
      providers: ["anthropic"],
      modelCandidates: ["anthropic/claude-sonnet-4-6"],
      options: {
        timeoutMs: 5_000,
        concurrency: 1,
        maxTokens: 16,
      },
    });

    expect(plan.targets).toHaveLength(0);
    expect(plan.results).toHaveLength(1);
    expect(plan.results[0]?.reasonCode).toBe("excluded_by_auth_order");
    expect(plan.results[0]?.error).toBe("Excluded by auth.order for this provider.");
  });

  it("reports unresolved_ref when a ref-only profile cannot resolve its SecretRef", async () => {
    mockStore = {
      version: 1,
      profiles: {
        "anthropic:default": {
          type: "token",
          provider: "anthropic",
          tokenRef: { source: "env", provider: "default", id: "MISSING_ANTHROPIC_TOKEN" },
        },
      },
      order: {
        anthropic: ["anthropic:default"],
      },
    };
    mockAllowedProfiles = ["anthropic:default"];
    resolveSecretRefStringMock.mockRejectedValueOnce(new Error("missing secret"));

    const plan = await buildProbeTargets({
      cfg: {
        auth: {
          order: {
            anthropic: ["anthropic:default"],
          },
        },
      } as OpenClawConfig,
      providers: ["anthropic"],
      modelCandidates: ["anthropic/claude-sonnet-4-6"],
      options: {
        timeoutMs: 5_000,
        concurrency: 1,
        maxTokens: 16,
      },
    });

    expect(plan.targets).toHaveLength(0);
    expect(plan.results).toHaveLength(1);
    expect(plan.results[0]?.reasonCode).toBe("unresolved_ref");
    expect(plan.results[0]?.error?.split("\n")[0]).toBe(
      "Auth profile credentials are missing or expired.",
    );
    expect(plan.results[0]?.error).toContain("[unresolved_ref]");
    expect(plan.results[0]?.error).toContain("env:default:MISSING_ANTHROPIC_TOKEN");
  });
});
