/**
 * Transport abstraction for MCP server.
 * Decouples the wire protocol (stdio, HTTP) from the MCP protocol logic.
 */

import { MCPMessageContext, MCPResponse } from '../types/mcp';

/**
 * Abstraction over the wire protocol (stdio or HTTP).
 * MCPServer delegates all I/O to the transport; it never reads stdin
 * or writes stdout directly.
 */
export interface MCPTransport {
  /**
   * Register the handler that processes incoming parsed JSON-RPC messages.
   * The handler returns a response for requests (those with an id),
   * or null for notifications (no id).
   */
  onMessage(handler: (msg: Record<string, unknown>, context?: MCPMessageContext) => Promise<MCPResponse | null>): void;

  /**
   * Send a JSON-RPC response or notification to the client.
   * For stdio this writes to stdout; for HTTP this is used only for
   * server-initiated notifications (request responses go through the
   * HTTP response object directly).
   */
  send(response: MCPResponse): void;

  /**
   * Register cleanup that runs when a stateful transport deletes an MCP session.
   * Stateless transports can omit this hook.
   */
  onSessionDelete?(handler: (sessionId: string) => void): void;

  /** Start listening for messages (bind port or attach readline). */
  start(): void | Promise<void>;

  /** Graceful shutdown. */
  close(): Promise<void>;
}

export type TransportMode = 'stdio' | 'http';

export interface TransportOptions {
  port?: number;
  host?: string;
  authToken?: string;
  insecure?: boolean;
  allowedOrigins?: string[];
}

/**
 * Factory: create the appropriate transport based on mode.
 */
export async function createTransport(mode: TransportMode, options?: TransportOptions): Promise<MCPTransport> {
  if (mode === 'http') {
    // Use dynamic import to avoid loading HTTP module when not needed
    const { HTTPTransport } = await import('./http');
    return new HTTPTransport(options?.port || 3100, options);
  }
  const { StdioTransport } = await import('./stdio');
  return new StdioTransport();
}
