import { compile, analyze } from "./compile.js";
import { pathToFileURL } from "node:url";
const API_VERSION = "0.3.0";
const SCHEMA_VERSION = "1.0.0";

const SERVER_INFO = {
  name: "schemeta-mcp",
  version: "0.2.0"
};

let stdinBuffer = Buffer.alloc(0);

function writeMessage(message) {
  const json = JSON.stringify(message);
  const body = Buffer.from(json, "utf8");
  const header = Buffer.from(`Content-Length: ${body.length}\r\n\r\n`, "utf8");
  process.stdout.write(Buffer.concat([header, body]));
}

function sendResult(id, result) {
  writeMessage({ jsonrpc: "2.0", id, result });
}

function sendError(id, code, message, data = undefined) {
  writeMessage({
    jsonrpc: "2.0",
    id,
    error: { code, message, data }
  });
}

function decodePayload(value) {
  if (typeof value === "string") {
    return JSON.parse(value);
  }
  if (value && typeof value === "object") {
    return value;
  }
  throw new Error("payload must be a JSON object or JSON string");
}

export function toolListResult() {
  return {
    tools: [
      {
        name: "schemeta_compile",
        description: "Compile Schemeta JSON into SVG with ERC, metrics, and topology results.",
        inputSchema: {
          type: "object",
          properties: {
            payload: {
              description: "Schemeta model object or JSON string",
              anyOf: [{ type: "object" }, { type: "string" }]
            },
            options: {
              description: "Compile options (render_mode, show_labels, generic_symbols)",
              type: "object"
            }
          },
          required: ["payload"]
        }
      },
      {
        name: "schemeta_analyze",
        description: "Analyze Schemeta JSON for ERC and topology without rendering SVG.",
        inputSchema: {
          type: "object",
          properties: {
            payload: {
              description: "Schemeta model object or JSON string",
              anyOf: [{ type: "object" }, { type: "string" }]
            },
            options: {
              description: "Analyze options (generic_symbols)",
              type: "object"
            }
          },
          required: ["payload"]
        }
      },
      {
        name: "schemeta_ui_bundle",
        description: "Return Schemeta UI bundle metadata for iframe embedding.",
        inputSchema: {
          type: "object",
          properties: {}
        }
      }
    ]
  };
}

export function withEnvelopeMeta(payload) {
  return {
    api_version: API_VERSION,
    schema_version: SCHEMA_VERSION,
    ...payload
  };
}

export function uiBundleDescriptor() {
  return {
    name: "schemeta-workspace",
    version: "0.2.0",
    api_version: API_VERSION,
    schema_version: SCHEMA_VERSION,
    entry: "/",
    title: "Schemeta Workspace",
    transport: "iframe"
  };
}

export function handleToolCall(name, args) {
  if (!args || typeof args !== "object") {
    args = {};
  }

  if (name === "schemeta_compile") {
    const payload = decodePayload(args.payload);
    const result = withEnvelopeMeta(compile(payload, args.options ?? {}));
    return {
      content: [{ type: "text", text: JSON.stringify(result) }],
      structuredContent: result,
      isError: false
    };
  }

  if (name === "schemeta_analyze") {
    const payload = decodePayload(args.payload);
    const result = withEnvelopeMeta(analyze(payload, args.options ?? {}));
    return {
      content: [{ type: "text", text: JSON.stringify(result) }],
      structuredContent: result,
      isError: false
    };
  }

  if (name === "schemeta_ui_bundle") {
    const result = uiBundleDescriptor();
    return {
      content: [{ type: "text", text: JSON.stringify(result) }],
      structuredContent: result,
      isError: false
    };
  }

  throw new Error(`Unknown tool '${name}'`);
}

export function handleRequest(message) {
  const { id, method, params } = message;

  if (method === "initialize") {
    return sendResult(id, {
      protocolVersion: "2024-11-05",
      capabilities: { tools: {} },
      serverInfo: SERVER_INFO
    });
  }

  if (method === "notifications/initialized") {
    return;
  }

  if (method === "ping") {
    return sendResult(id, {});
  }

  if (method === "tools/list") {
    return sendResult(id, toolListResult());
  }

  if (method === "tools/call") {
    try {
      const name = params?.name;
      const args = params?.arguments ?? {};
      const result = handleToolCall(name, args);
      return sendResult(id, result);
    } catch (err) {
      return sendError(id, -32602, err.message);
    }
  }

  if (id !== undefined) {
    return sendError(id, -32601, `Method not found: ${method}`);
  }
}

function tryParseBuffer() {
  while (true) {
    const headerEnd = stdinBuffer.indexOf("\r\n\r\n");
    if (headerEnd === -1) {
      return;
    }

    const headerText = stdinBuffer.slice(0, headerEnd).toString("utf8");
    const headers = headerText.split("\r\n");
    const lengthLine = headers.find((h) => h.toLowerCase().startsWith("content-length:"));
    if (!lengthLine) {
      stdinBuffer = Buffer.alloc(0);
      return;
    }

    const contentLength = Number(lengthLine.split(":")[1].trim());
    const totalLength = headerEnd + 4 + contentLength;
    if (stdinBuffer.length < totalLength) {
      return;
    }

    const body = stdinBuffer.slice(headerEnd + 4, totalLength).toString("utf8");
    stdinBuffer = stdinBuffer.slice(totalLength);

    let message;
    try {
      message = JSON.parse(body);
    } catch {
      continue;
    }

    try {
      handleRequest(message);
    } catch (err) {
      if (message?.id !== undefined) {
        sendError(message.id, -32603, "Internal error", err.message);
      }
    }
  }
}

const isMain = process.argv[1] ? import.meta.url === pathToFileURL(process.argv[1]).href : false;
if (isMain) {
  process.stdin.on("data", (chunk) => {
    stdinBuffer = Buffer.concat([stdinBuffer, Buffer.from(chunk)]);
    tryParseBuffer();
  });

  process.stdin.on("error", (err) => {
    process.stderr.write(`stdin error: ${String(err)}\n`);
  });

  process.stdin.resume();
}
