/**
 * Codex MCP Operations
 *
 * Transport-level operations for interacting with Codex MCP server management:
 * listing status, reading/writing config, and building server detail records.
 */

import type { JsonRpcTransport } from "./json-rpc-transport.js";
import type { McpServerDetail, McpServerConfig } from "./session-types.js";
import type { CodexMcpServerStatus, CodexMcpStatusListResponse } from "./codex-types.js";
import {
  toMcpServerConfig,
  fromMcpServerConfig,
  isMcpServerEnabled,
  mapMcpTools,
  asRecord,
} from "./codex-mcp-helpers.js";

// ─── Transport Operations ─────────────────────────────────────────────────────

/** Paginate through all MCP server statuses from the Codex runtime. */
export async function listAllMcpServerStatuses(
  transport: JsonRpcTransport,
): Promise<CodexMcpServerStatus[]> {
  const out: CodexMcpServerStatus[] = [];
  let cursor: string | null = null;
  let page = 0;

  while (page < 50) {
    const response = await transport.call("mcpServerStatus/list", {
      cursor,
      limit: 100,
    }) as CodexMcpStatusListResponse;
    if (Array.isArray(response.data)) {
      out.push(...response.data);
    }
    cursor = typeof response.nextCursor === "string" ? response.nextCursor : null;
    if (!cursor) break;
    page++;
  }

  return out;
}

/** Read the MCP servers config section from Codex config. */
export async function readMcpServersConfig(
  transport: JsonRpcTransport,
): Promise<Record<string, unknown>> {
  const response = await transport.call("config/read", {}) as {
    config?: Record<string, unknown>;
  };
  const config = asRecord(response?.config) || {};
  return asRecord(config.mcp_servers) || {};
}

/** Trigger a reload of all MCP servers in the Codex runtime. */
export async function reloadMcpServers(
  transport: JsonRpcTransport,
): Promise<void> {
  await transport.call("config/mcpServer/reload", {});
}

// ─── Pure Helpers ─────────────────────────────────────────────────────────────

/** Build McpServerDetail[] from status entries and config map. */
export function buildMcpServerDetails(
  statusEntries: CodexMcpServerStatus[],
  configMap: Record<string, unknown>,
): McpServerDetail[] {
  const names = new Set<string>([
    ...statusEntries.map((s) => s.name),
    ...Object.keys(configMap),
  ]);

  const statusByName = new Map(statusEntries.map((s) => [s.name, s]));

  return Array.from(names).sort().map((name) => {
    const status = statusByName.get(name);
    const config = toMcpServerConfig(configMap[name]);
    const isEnabled = isMcpServerEnabled(configMap[name]);
    const serverStatus: McpServerDetail["status"] =
      !isEnabled
        ? "disabled"
        : (status?.authStatus === "notLoggedIn" ? "failed" : "connected");

    return {
      name,
      status: serverStatus,
      error: status?.authStatus === "notLoggedIn" ? "MCP server requires login" : undefined,
      config,
      scope: "user",
      tools: mapMcpTools(status?.tools),
    };
  });
}

/**
 * Build config/batchWrite edit entries from a browser McpServerConfig map.
 * Validates that server names do not contain dots (required by Codex keyPath format).
 */
export function buildMcpConfigEdits(
  servers: Record<string, McpServerConfig>,
): Array<{ keyPath: string; value: Record<string, unknown>; mergeStrategy: "upsert" }> {
  const edits: Array<{ keyPath: string; value: Record<string, unknown>; mergeStrategy: "upsert" }> = [];
  for (const [name, config] of Object.entries(servers)) {
    if (name.includes(".")) {
      throw new Error(`Server names containing '.' are not supported: ${name}`);
    }
    edits.push({
      keyPath: `mcp_servers.${name}`,
      value: fromMcpServerConfig(config),
      mergeStrategy: "upsert",
    });
  }
  return edits;
}
