import http from 'node:http';
import type { UpstreamConnection, JsonRpcRequest, JsonRpcResponse, UpstreamConfig } from '../types.js';

/**
 * Connects to an MCP server over HTTP (SSE or Streamable HTTP transport).
 * Sends JSON-RPC requests via HTTP POST.
 */
export class HttpUpstream implements UpstreamConnection {
  readonly name: string;
  private url: string;
  private alive = true;

  constructor(config: UpstreamConfig) {
    this.name = config.name;
    if (!config.url) {
      throw new Error(`HTTP upstream '${config.name}' has no URL configured`);
    }
    this.url = config.url;
  }

  async send(request: JsonRpcRequest): Promise<JsonRpcResponse> {
    if (!this.alive) {
      throw new Error(`Upstream '${this.name}' is closed`);
    }

    const body = JSON.stringify(request);
    const parsed = new URL(this.url);

    return new Promise((resolve, reject) => {
      const opts: http.RequestOptions = {
        hostname: parsed.hostname,
        port: parsed.port,
        path: parsed.pathname,
        method: 'POST',
        timeout: 120_000,
        headers: {
          'Content-Type': 'application/json',
          'Content-Length': Buffer.byteLength(body),
        },
      };

      const req = http.request(opts, (res) => {
        const chunks: Buffer[] = [];
        res.on('data', (chunk: Buffer) => chunks.push(chunk));
        res.on('end', () => {
          try {
            const raw = Buffer.concat(chunks).toString('utf-8');
            resolve(JSON.parse(raw) as JsonRpcResponse);
          } catch (err) {
            reject(new Error(`Invalid response from '${this.name}': ${err}`));
          }
        });
      });
      req.on('error', reject);
      req.on('timeout', () => {
        req.destroy();
        reject(new Error(`Request to '${this.name}' timed out`));
      });
      req.write(body);
      req.end();
    });
  }

  async close(): Promise<void> {
    this.alive = false;
  }

  isAlive(): boolean {
    return this.alive;
  }
}
