import { afterEach, beforeEach, describe, expect, test } from "bun:test";
import { __resetMcpBearerWarnedForTest, loadVoiceAgentConfig } from "./config.ts";

const MCP_ENV_KEYS = [
  "MCP_BEARER_TOKEN",
  "MCP_BEARER_TOKEN_ADVANCEDMD",
  "MCP_BEARER_TOKEN_RINGCENTRAL",
  "MCP_BEARER_TOKEN_RINGCENTRAL_ADMIN",
  "ADVANCEDMD_MCP_URL",
  "RINGCENTRAL_MCP_URL",
  "RINGCENTRAL_ADMIN_MCP_URL",
  "CLAUDE_CLOUD_BASE",
  "OPENAI_REALTIME_VOICE",
] as const;

const snapshot: Partial<Record<(typeof MCP_ENV_KEYS)[number], string | undefined>> = {};

beforeEach(() => {
  for (const key of MCP_ENV_KEYS) {
    snapshot[key] = process.env[key];
    delete process.env[key];
  }
  process.env.CLAUDE_CLOUD_BASE = "https://example.internal";
  // Reset module-level dedupe flag so each test starts from a clean slate;
  // otherwise the deprecation-warning test below passes vacuously when a
  // prior test has already latched the flag to true.
  __resetMcpBearerWarnedForTest();
});

afterEach(() => {
  for (const key of MCP_ENV_KEYS) {
    if (snapshot[key] === undefined) delete process.env[key];
    else process.env[key] = snapshot[key];
  }
});

describe("loadVoiceAgentConfig", () => {
  test("defaults OPENAI_REALTIME_VOICE to marin (not alloy) for a warmer phone voice", () => {
    const config = loadVoiceAgentConfig();
    expect(config.openai.voice).toBe("marin");
  });

  test("honors an explicit OPENAI_REALTIME_VOICE override", () => {
    process.env.OPENAI_REALTIME_VOICE = "cedar";
    const config = loadVoiceAgentConfig();
    expect(config.openai.voice).toBe("cedar");
  });

  test("loads distinct per-endpoint MCP bearer tokens when all three are set", () => {
    process.env.MCP_BEARER_TOKEN_ADVANCEDMD = "amd-token";
    process.env.MCP_BEARER_TOKEN_RINGCENTRAL = "rc-token";
    process.env.MCP_BEARER_TOKEN_RINGCENTRAL_ADMIN = "rc-admin-token";

    const config = loadVoiceAgentConfig();
    expect(config.mcp.advancedmd.bearerToken).toBe("amd-token");
    expect(config.mcp.ringcentral.bearerToken).toBe("rc-token");
    expect(config.mcp.ringcentralAdmin.bearerToken).toBe("rc-admin-token");
  });

  test("falls back to legacy MCP_BEARER_TOKEN when a per-endpoint var is unset", () => {
    process.env.MCP_BEARER_TOKEN = "legacy-token";
    process.env.MCP_BEARER_TOKEN_RINGCENTRAL = "rc-specific";

    const config = loadVoiceAgentConfig();
    expect(config.mcp.advancedmd.bearerToken).toBe("legacy-token");
    expect(config.mcp.ringcentral.bearerToken).toBe("rc-specific");
    expect(config.mcp.ringcentralAdmin.bearerToken).toBe("legacy-token");
  });

  test("emits a single deprecation warning when MCP_BEARER_TOKEN is read", () => {
    process.env.MCP_BEARER_TOKEN = "legacy-token";

    const warnings: string[] = [];
    const originalWarn = console.warn;
    console.warn = (...args: unknown[]) => {
      warnings.push(args.map((a) => String(a)).join(" "));
    };
    try {
      loadVoiceAgentConfig();
      loadVoiceAgentConfig();
    } finally {
      console.warn = originalWarn;
    }

    const deprecationLines = warnings.filter((line) =>
      line.includes("MCP_BEARER_TOKEN is deprecated"),
    );
    // Module-level dedupe guard: warn exactly once per process.
    // With the per-test reset (beforeEach), this exercises the dedupe path
    // honestly — two loadVoiceAgentConfig() calls produce only one warning.
    expect(deprecationLines.length).toBe(1);
  });

  test("leaves bearer tokens undefined when no env vars are set", () => {
    const config = loadVoiceAgentConfig();
    expect(config.mcp.advancedmd.bearerToken).toBeUndefined();
    expect(config.mcp.ringcentral.bearerToken).toBeUndefined();
    expect(config.mcp.ringcentralAdmin.bearerToken).toBeUndefined();
  });
});
