import type { AppConfig } from "../../shared/types";

export interface McpToolDescriptor {
  name: string;
  title?: string;
  description?: string;
  inputSchema?: unknown;
}

export interface McpToolResult {
  content?: Array<{ type: string; text?: string }>;
  structuredContent?: unknown;
}

interface McpRpcResponse<T> {
  jsonrpc: "2.0";
  id: number | string | null;
  result?: T;
  error?: {
    code: number;
    message: string;
  };
}

export class McpClient {
  private requestId = 1;

  constructor(private readonly getConfig: () => AppConfig) {}

  async listTools(): Promise<McpToolDescriptor[]> {
    const response = await this.rpc<{ tools?: McpToolDescriptor[] }>("tools/list", {});
    return Array.isArray(response.tools) ? response.tools : [];
  }

  async callTool(name: string, args: Record<string, unknown>): Promise<McpToolResult> {
    return this.rpc<McpToolResult>("tools/call", {
      name,
      arguments: args
    });
  }

  private async rpc<T>(method: string, params: Record<string, unknown>): Promise<T> {
    const config = this.getConfig();
    if (!config.mcp.enabled) {
      throw new Error("MCP 未启用");
    }

    const response = await fetch(this.endpoint(config), {
      method: "POST",
      headers: this.headers(config),
      body: JSON.stringify({
        jsonrpc: "2.0",
        id: this.requestId++,
        method,
        params
      })
    });

    const payload = (await response.json()) as McpRpcResponse<T>;
    if (!response.ok) {
      throw new Error(payload.error?.message || `MCP HTTP ${response.status}`);
    }
    if (payload.error) {
      throw new Error(payload.error.message || "MCP 调用失败");
    }
    if (payload.result === undefined) {
      throw new Error("MCP 未返回结果");
    }
    return payload.result;
  }

  private endpoint(config: AppConfig): string {
    const host = config.mcp.allowExternal ? config.mcp.host : "127.0.0.1";
    const path = config.mcp.path.startsWith("/") ? config.mcp.path : `/${config.mcp.path}`;
    return `http://${host}:${config.mcp.port}${path}`;
  }

  private headers(config: AppConfig): Record<string, string> {
    const headers: Record<string, string> = {
      "Content-Type": "application/json"
    };
    const token = config.mcp.authToken.trim();
    if (token) {
      headers.Authorization = `Bearer ${token}`;
      headers["X-MCP-Token"] = token;
    }
    return headers;
  }
}
