import type { McpEndpointConfig } from "./config.ts";

export interface McpReadinessResult {
  name: string;
  ok: boolean;
  healthUrl: string;
  transportOk: boolean;
  bearerConfigured: boolean;
  status?: number;
  error?: string;
}

export interface McpReadinessOptions {
  fetchImpl?: typeof fetch;
  timeoutMs?: number;
}

export function healthUrlForMcpUrl(mcpUrl: string): string {
  const url = new URL(mcpUrl);
  if (url.pathname.endsWith("/mcp")) {
    url.pathname = url.pathname.slice(0, -"/mcp".length) + "/health";
  } else {
    url.pathname = url.pathname.replace(/\/?$/, "/health");
  }
  return url.toString();
}

export function isSecureMcpTransport(endpoint: McpEndpointConfig): boolean {
  const url = new URL(endpoint.mcpUrl);
  if (url.protocol !== "https:") return false;
  return Boolean(endpoint.bearerToken);
}

export async function checkMcpEndpoint(
  endpoint: McpEndpointConfig,
  opts: McpReadinessOptions = {},
): Promise<McpReadinessResult> {
  const fetchImpl = opts.fetchImpl ?? fetch;
  const timeoutMs = opts.timeoutMs ?? 5000;
  const healthUrl = healthUrlForMcpUrl(endpoint.mcpUrl);
  const controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), timeoutMs);
  const transportOk = isSecureMcpTransport(endpoint);

  try {
    const response = await fetchImpl(healthUrl, { signal: controller.signal });
    const ok = transportOk && response.ok;
    return {
      name: endpoint.name,
      ok,
      healthUrl,
      transportOk,
      bearerConfigured: Boolean(endpoint.bearerToken),
      status: response.status,
      ...(ok
        ? {}
        : {
            error: !transportOk
              ? "MCP endpoint must use HTTPS and a configured bearer token"
              : `health check returned ${response.status}`,
          }),
    };
  } catch (err) {
    const message = err instanceof Error ? err.message : String(err);
    return {
      name: endpoint.name,
      ok: false,
      healthUrl,
      transportOk,
      bearerConfigured: Boolean(endpoint.bearerToken),
      error: message,
    };
  } finally {
    clearTimeout(timeout);
  }
}

export async function checkAllMcpEndpoints(
  endpoints: McpEndpointConfig[],
  opts: McpReadinessOptions = {},
): Promise<McpReadinessResult[]> {
  return Promise.all(endpoints.map((endpoint) => checkMcpEndpoint(endpoint, opts)));
}
