#!/usr/bin/env node

function loadWebSocketImplementation() {
  if (typeof globalThis.WebSocket === 'function') {
    return globalThis.WebSocket;
  }

  try {
    const { WebSocket } = require('undici');
    if (typeof WebSocket === 'function') {
      return WebSocket;
    }
  } catch {
    // Fall through to the legacy ws dependency when available.
  }

  try {
    const { WebSocket } = require('ws');
    if (typeof WebSocket === 'function') {
      return WebSocket;
    }
  } catch {
    // Surface a dedicated error below if no implementation is available.
  }

  throw new Error(
    'Browser MCP could not find a WebSocket implementation. Tried globalThis.WebSocket, undici, and ws.'
  );
}

const WebSocket = loadWebSocketImplementation();

const PROTOCOL_VERSION = '2024-11-05';
const SERVER_NAME = 'ccs-browser';
const SERVER_VERSION = '1.0.0';
const TOOL_SESSION_INFO = 'browser_get_session_info';
const TOOL_URL_TITLE = 'browser_get_url_and_title';
const TOOL_VISIBLE_TEXT = 'browser_get_visible_text';
const TOOL_DOM_SNAPSHOT = 'browser_get_dom_snapshot';
const TOOL_NAVIGATE = 'browser_navigate';
const TOOL_CLICK = 'browser_click';
const TOOL_TYPE = 'browser_type';
const TOOL_TAKE_SCREENSHOT = 'browser_take_screenshot';
const TOOL_NAMES = [
  TOOL_SESSION_INFO,
  TOOL_URL_TITLE,
  TOOL_VISIBLE_TEXT,
  TOOL_DOM_SNAPSHOT,
  TOOL_NAVIGATE,
  TOOL_CLICK,
  TOOL_TYPE,
  TOOL_TAKE_SCREENSHOT,
];
const CDP_TIMEOUT_MS = 5000;
const NAVIGATION_POLL_INTERVAL_MS = 100;

let inputBuffer = Buffer.alloc(0);
let requestCounter = 0;

function addSocketListener(socket, eventName, handler) {
  if (typeof socket.addEventListener === 'function') {
    socket.addEventListener(eventName, handler);
    return;
  }

  if (typeof socket.on === 'function') {
    socket.on(eventName, handler);
  }
}

async function getSocketMessageText(message) {
  const data = message && typeof message === 'object' && 'data' in message ? message.data : message;

  if (typeof data === 'string') {
    return data;
  }

  if (Buffer.isBuffer(data)) {
    return data.toString('utf8');
  }

  if (data instanceof ArrayBuffer) {
    return Buffer.from(data).toString('utf8');
  }

  if (ArrayBuffer.isView(data)) {
    return Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString('utf8');
  }

  if (data && typeof data.text === 'function') {
    return await data.text();
  }

  return String(data);
}

function closeSocket(socket) {
  if (typeof socket.close === 'function') {
    socket.close();
  }
}

function abortSocket(socket) {
  if (typeof socket.terminate === 'function') {
    socket.terminate();
    return;
  }

  closeSocket(socket);
}

function toSocketError(error) {
  if (error instanceof Error) {
    return error;
  }

  return new Error('Browser MCP lost the DevTools websocket connection.');
}

function shouldExposeTools() {
  return Boolean(process.env.CCS_BROWSER_DEVTOOLS_HTTP_URL);
}

function writeMessage(message) {
  process.stdout.write(`${JSON.stringify(message)}\n`);
}

function writeResponse(id, result) {
  writeMessage({ jsonrpc: '2.0', id, result });
}

function writeError(id, code, message) {
  writeMessage({ jsonrpc: '2.0', id, error: { code, message } });
}

function getTools() {
  if (!shouldExposeTools()) {
    return [];
  }

  return [
    {
      name: TOOL_SESSION_INFO,
      description:
        'List the current Chrome session pages available through the configured DevTools connection, including page ids, titles, URLs, and websocket endpoints.',
      inputSchema: {
        type: 'object',
        properties: {},
        additionalProperties: false,
      },
    },
    {
      name: TOOL_URL_TITLE,
      description:
        'Read the current page URL and title from the configured Chrome session. Optionally choose a page by index.',
      inputSchema: {
        type: 'object',
        properties: {
          pageIndex: {
            type: 'integer',
            minimum: 0,
            description: 'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
          },
        },
        additionalProperties: false,
      },
    },
    {
      name: TOOL_VISIBLE_TEXT,
      description:
        'Read visible text from the current page via DOM evaluation in the configured Chrome session. Optionally choose a page by index.',
      inputSchema: {
        type: 'object',
        properties: {
          pageIndex: {
            type: 'integer',
            minimum: 0,
            description: 'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
          },
        },
        additionalProperties: false,
      },
    },
    {
      name: TOOL_DOM_SNAPSHOT,
      description:
        'Read a DOM snapshot from the current page by returning the document outerHTML. Optionally choose a page by index.',
      inputSchema: {
        type: 'object',
        properties: {
          pageIndex: {
            type: 'integer',
            minimum: 0,
            description: 'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
          },
        },
        additionalProperties: false,
      },
    },
    {
      name: TOOL_NAVIGATE,
      description:
        'Navigate the selected page to an absolute http or https URL and wait until navigation is ready. Optionally choose a page by index.',
      inputSchema: {
        type: 'object',
        properties: {
          pageIndex: {
            type: 'integer',
            minimum: 0,
            description: 'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
          },
          url: {
            type: 'string',
            description: 'Required absolute http or https URL to navigate to.',
          },
        },
        required: ['url'],
        additionalProperties: false,
      },
    },
    {
      name: TOOL_CLICK,
      description:
        'Click the first element matching a CSS selector in the selected page using a minimal mouse event chain with click fallback. Optionally choose a page by index.',
      inputSchema: {
        type: 'object',
        properties: {
          pageIndex: {
            type: 'integer',
            minimum: 0,
            description: 'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
          },
          selector: {
            type: 'string',
            description: 'Required CSS selector for the element to click.',
          },
        },
        required: ['selector'],
        additionalProperties: false,
      },
    },
    {
      name: TOOL_TYPE,
      description:
        'Type text into the first element matching a CSS selector when it is a supported text-editable target. Optionally choose a page by index.',
      inputSchema: {
        type: 'object',
        properties: {
          pageIndex: {
            type: 'integer',
            minimum: 0,
            description: 'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
          },
          selector: {
            type: 'string',
            description: 'Required CSS selector for the target element.',
          },
          text: {
            type: 'string',
            description: 'Required text to assign. May be an empty string.',
          },
          clearFirst: {
            type: 'boolean',
            description: 'When true, clear the current value or content before assigning text.',
          },
        },
        required: ['selector', 'text'],
        additionalProperties: false,
      },
    },
    {
      name: TOOL_TAKE_SCREENSHOT,
      description:
        'Capture a PNG screenshot from the selected page. Optionally choose a page by index or request fullPage capture.',
      inputSchema: {
        type: 'object',
        properties: {
          pageIndex: {
            type: 'integer',
            minimum: 0,
            description: 'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
          },
          fullPage: {
            type: 'boolean',
            description: 'Optional full-page capture flag.',
          },
        },
        additionalProperties: false,
      },
    },
  ];
}

async function fetchJson(url) {
  const response = await fetch(url);
  if (!response.ok) {
    throw new Error(`HTTP ${response.status} for ${url}`);
  }
  return await response.json();
}

function getHttpUrl() {
  const value = process.env.CCS_BROWSER_DEVTOOLS_HTTP_URL;
  if (!value) {
    throw new Error('Browser MCP is unavailable because CCS_BROWSER_DEVTOOLS_HTTP_URL is missing.');
  }
  return value.replace(/\/+$/, '');
}

async function listPageTargets() {
  const targets = await fetchJson(`${getHttpUrl()}/json/list`);
  if (!Array.isArray(targets)) {
    throw new Error('Browser MCP received an invalid /json/list response.');
  }

  return targets
    .filter((target) => target && typeof target === 'object' && target.type === 'page')
    .map((target) => ({
      id: typeof target.id === 'string' ? target.id : '',
      title: typeof target.title === 'string' ? target.title : '',
      url: typeof target.url === 'string' ? target.url : '',
      type: typeof target.type === 'string' ? target.type : 'page',
      webSocketDebuggerUrl:
        typeof target.webSocketDebuggerUrl === 'string' ? target.webSocketDebuggerUrl : '',
    }));
}

function parsePageIndex(toolArgs) {
  if (!toolArgs || !Object.prototype.hasOwnProperty.call(toolArgs, 'pageIndex')) {
    return 0;
  }

  if (!Number.isInteger(toolArgs.pageIndex) || toolArgs.pageIndex < 0) {
    throw new Error('pageIndex must be a non-negative integer');
  }

  return toolArgs.pageIndex;
}

async function getSelectedPage(toolArgs) {
  const pages = await listPageTargets();
  if (pages.length === 0) {
    throw new Error('Browser MCP did not find any page targets in the current Chrome session.');
  }

  const pageIndex = parsePageIndex(toolArgs);

  const page = pages[pageIndex];
  if (!page) {
    throw new Error(`Browser MCP page index ${pageIndex} is out of range (found ${pages.length} pages).`);
  }
  if (!page.webSocketDebuggerUrl) {
    throw new Error(`Browser MCP page ${pageIndex} does not expose a websocket debugger URL.`);
  }

  return { page, pageIndex, pages };
}

function formatSessionInfo(pages) {
  return [
    '[CCS Browser Session]',
    '',
    ...pages.map((page, index) => `${index}. ${page.title || '<untitled>'} | ${page.url || '<empty>'}`),
  ].join('\n');
}

function createEvaluateExpression(kind) {
  switch (kind) {
    case 'url-title':
      return `JSON.stringify({ title: document.title, url: location.href })`;
    case 'visible-text':
      return `document.body ? document.body.innerText : ''`;
    case 'dom-snapshot':
      return `document.documentElement ? document.documentElement.outerHTML : ''`;
    default:
      throw new Error(`Unknown browser evaluation kind: ${kind}`);
  }
}

async function sendCdpCommand(page, method, params = {}) {
  const ws = new WebSocket(page.webSocketDebuggerUrl);
  const requestId = ++requestCounter;

  return await new Promise((resolve, reject) => {
    let settled = false;
    const timer = setTimeout(() => {
      if (!settled) {
        settled = true;
        abortSocket(ws);
        reject(new Error('Browser MCP timed out waiting for a DevTools response.'));
      }
    }, CDP_TIMEOUT_MS);

    function settleError(error) {
      if (settled) {
        return;
      }
      clearTimeout(timer);
      settled = true;
      reject(toSocketError(error));
    }

    addSocketListener(ws, 'open', () => {
      ws.send(
        JSON.stringify({
          id: requestId,
          method,
          params,
        })
      );
    });

    addSocketListener(ws, 'message', (data) => {
      void (async () => {
        const raw = await getSocketMessageText(data);

        if (settled) {
          return;
        }

        let message;
        try {
          message = JSON.parse(raw);
        } catch {
          return;
        }

        if (message.id !== requestId) {
          return;
        }

        clearTimeout(timer);
        settled = true;
        closeSocket(ws);

        if (message.error) {
          reject(new Error(message.error.message || 'DevTools request failed.'));
          return;
        }

        resolve(message.result || null);
      })().catch(settleError);
    });

    addSocketListener(ws, 'error', (error) => {
      settleError(error);
    });

    addSocketListener(ws, 'close', () => {
      if (settled) {
        return;
      }
      settleError(new Error('Browser MCP lost the DevTools websocket connection.'));
    });
  });
}

async function evaluateInPage(page, kind) {
  const response = await sendCdpCommand(page, 'Runtime.evaluate', {
    expression: createEvaluateExpression(kind),
    returnByValue: true,
  });

  const result = response && response.result ? response.result : null;
  if (!result) {
    throw new Error('Browser MCP received an invalid DevTools evaluation response.');
  }

  if (result.subtype === 'error') {
    throw new Error(result.description || 'DevTools evaluation returned an error.');
  }

  return typeof result.value === 'string' ? result.value : result.value ?? '';
}

async function evaluateExpression(page, expression) {
  const response = await sendCdpCommand(page, 'Runtime.evaluate', {
    expression,
    returnByValue: true,
  });

  const result = response && response.result ? response.result : null;
  if (!result) {
    throw new Error('Browser MCP received an invalid DevTools evaluation response.');
  }

  if (result.subtype === 'error') {
    throw new Error(result.description || 'DevTools evaluation returned an error.');
  }

  return typeof result.value === 'string' ? result.value : result.value ?? '';
}

function requireNonEmptyString(value, label) {
  if (typeof value !== 'string' || value.trim() === '') {
    throw new Error(`${label} is required`);
  }
  return value.trim();
}

function requireString(value, label) {
  if (typeof value !== 'string') {
    throw new Error(`${label} is required`);
  }
  return value;
}

function requireValidHttpUrl(value) {
  const raw = requireNonEmptyString(value, 'url');
  let parsed;
  try {
    parsed = new URL(raw);
  } catch {
    throw new Error('url must be an absolute http or https URL');
  }

  if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
    throw new Error('url must be an absolute http or https URL');
  }

  return parsed.toString();
}

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function getNavigationState(page) {
  const raw = await evaluateExpression(page, `JSON.stringify({ href: location.href, readyState: document.readyState })`);
  const parsed = JSON.parse(raw);
  return {
    href: typeof parsed.href === 'string' ? parsed.href : '',
    readyState: typeof parsed.readyState === 'string' ? parsed.readyState : '',
  };
}

function isSameDocumentHashNavigation(beforeHref, requestedUrl) {
  try {
    const before = new URL(beforeHref);
    const requested = new URL(requestedUrl);
    return (
      before.origin === requested.origin &&
      before.pathname === requested.pathname &&
      before.search === requested.search &&
      before.hash !== requested.hash
    );
  } catch {
    return false;
  }
}

function isNavigationReady(state, beforeHref, requestedUrl) {
  if (state.readyState !== 'interactive' && state.readyState !== 'complete') {
    return false;
  }

  if (state.href === requestedUrl) {
    return true;
  }

  if (state.href && state.href !== beforeHref) {
    return true;
  }

  if (isSameDocumentHashNavigation(beforeHref, requestedUrl) && state.href === requestedUrl) {
    return true;
  }

  return false;
}

async function waitForNavigationReady(page, beforeHref, requestedUrl) {
  const deadline = Date.now() + CDP_TIMEOUT_MS;

  while (Date.now() <= deadline) {
    const state = await getNavigationState(page);
    if (isNavigationReady(state, beforeHref, requestedUrl)) {
      return state.href;
    }
    if (Date.now() + NAVIGATION_POLL_INTERVAL_MS > deadline) {
      break;
    }
    await sleep(NAVIGATION_POLL_INTERVAL_MS);
  }

  throw new Error(`navigation did not complete for URL: ${requestedUrl}`);
}

async function handleNavigate(toolArgs) {
  const { page, pageIndex } = await getSelectedPage(toolArgs);
  const url = requireValidHttpUrl(toolArgs.url);
  const before = await getNavigationState(page);
  const navigateResult = await sendCdpCommand(page, 'Page.navigate', { url });
  if (navigateResult && typeof navigateResult.errorText === 'string' && navigateResult.errorText) {
    throw new Error(`navigation failed for URL: ${url}: ${navigateResult.errorText}`);
  }
  const finalUrl = await waitForNavigationReady(page, before.href, url);
  return `pageIndex: ${pageIndex}\nurl: ${finalUrl}\nstatus: navigated`;
}

async function handleClick(toolArgs) {
  const { page, pageIndex } = await getSelectedPage(toolArgs);
  const selector = requireNonEmptyString(toolArgs.selector, 'selector');

  const expression = `(() => {
    const selector = JSON.parse(${JSON.stringify(JSON.stringify(selector))});
    const element = document.querySelector(selector);
    if (!element) {
      throw new Error('element not found for selector: ' + selector);
    }
    if (!element.isConnected) {
      throw new Error('element is detached for selector: ' + selector);
    }
    if ('disabled' in element && element.disabled) {
      throw new Error('element is disabled for selector: ' + selector);
    }
    const style = window.getComputedStyle(element);
    const rect = element.getBoundingClientRect();
    if (
      style.display === 'none' ||
      style.visibility === 'hidden' ||
      rect.width <= 0 ||
      rect.height <= 0
    ) {
      throw new Error('element is hidden or not interactable for selector: ' + selector);
    }
    element.scrollIntoView({ block: 'center', inline: 'center' });

    const dispatchMouseEvent = (type, init) => {
      const event = new MouseEvent(type, {
        bubbles: true,
        cancelable: true,
        composed: true,
        view: window,
        detail: 1,
        ...init,
      });
      return element.dispatchEvent(event);
    };

    try {
      const dispatchResult = {
        shouldActivate:
          dispatchMouseEvent('mousedown', { button: 0, buttons: 1 }) &&
          dispatchMouseEvent('mouseup', { button: 0, buttons: 0 }),
      };
      if (!dispatchResult.shouldActivate) {
        return 'ok';
      }
      if (!element.isConnected) {
        return 'ok';
      }
    } catch (mouseError) {
      // Fall through to the native activation path below.
    }

    element.click();

    return 'ok';
  })()`;

  await evaluateExpression(page, expression);
  return `pageIndex: ${pageIndex}\nselector: ${selector}\nstatus: clicked`;
}

async function handleType(toolArgs) {
  const { page, pageIndex } = await getSelectedPage(toolArgs);
  const selector = requireNonEmptyString(toolArgs.selector, 'selector');
  const text = requireString(toolArgs.text, 'text');
  const clearFirst = toolArgs.clearFirst === true;

  const expression = `(() => {
    const selector = JSON.parse(${JSON.stringify(JSON.stringify(selector))});
    const text = JSON.parse(${JSON.stringify(JSON.stringify(text))});
    const clearFirst = ${clearFirst ? 'true' : 'false'};
    const element = document.querySelector(selector);
    if (!element) {
      throw new Error('element not found for selector: ' + selector);
    }

    const dispatchEvents = (target) => {
      target.dispatchEvent(new Event('input', { bubbles: true }));
      target.dispatchEvent(new Event('change', { bubbles: true }));
    };

    const focusTarget = (target) => {
      if (typeof target.focus === 'function') {
        target.focus();
      }
    };

    let readback = '';
    let expectedValue = '';

    if (element instanceof HTMLTextAreaElement) {
      focusTarget(element);
      const setter = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value')?.set;
      expectedValue = (clearFirst ? '' : element.value) + text;
      if (setter) {
        setter.call(element, expectedValue);
      } else {
        element.value = expectedValue;
      }
      dispatchEvents(element);
      readback = element.value;
    } else if (element instanceof HTMLInputElement) {
      const supportedTypes = new Set(['', 'text', 'search', 'email', 'url', 'tel', 'password']);
      const normalizedType = (element.getAttribute('type') || '').toLowerCase();
      if (!supportedTypes.has(normalizedType)) {
        throw new Error('element is not text-editable for selector: ' + selector);
      }
      focusTarget(element);
      const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set;
      expectedValue = (clearFirst ? '' : element.value) + text;
      if (setter) {
        setter.call(element, expectedValue);
      } else {
        element.value = expectedValue;
      }
      dispatchEvents(element);
      readback = element.value;
    } else if (element.isContentEditable === true) {
      focusTarget(element);
      expectedValue = (clearFirst ? '' : (element.textContent || '')) + text;
      element.textContent = expectedValue;
      dispatchEvents(element);
      readback = element.textContent || '';
    } else {
      throw new Error('element is not text-editable for selector: ' + selector);
    }

    if (readback !== expectedValue) {
      throw new Error('typed text verification failed for selector: ' + selector);
    }

    return JSON.stringify({ value: readback, typedLength: readback.length });
  })()`;

  const raw = await evaluateExpression(page, expression);
  const parsed = JSON.parse(raw);
  const typedLength = typeof parsed.typedLength === 'number' ? parsed.typedLength : String(parsed.value || '').length;
  return `pageIndex: ${pageIndex}\nselector: ${selector}\ntypedLength: ${typedLength}\nstatus: typed`;
}

async function handleScreenshot(toolArgs) {
  const { page, pageIndex } = await getSelectedPage(toolArgs);
  const fullPage = toolArgs.fullPage === true;
  const response = await sendCdpCommand(page, 'Page.captureScreenshot', {
    format: 'png',
    captureBeyondViewport: fullPage,
  });

  const data = response && typeof response.data === 'string' ? response.data : '';
  if (!data) {
    throw new Error('screenshot capture failed');
  }

  return `pageIndex: ${pageIndex}\nformat: png\nfullPage: ${fullPage ? 'true' : 'false'}\ndata: ${data}`;
}

async function handleToolCall(message) {
  const id = message.id;
  const params = message.params || {};
  const toolName = params.name || '<missing>';
  const toolArgs = params.arguments || {};

  if (!TOOL_NAMES.includes(toolName)) {
    writeError(id, -32602, `Unknown tool: ${toolName}`);
    return;
  }

  if (!shouldExposeTools()) {
    writeResponse(id, {
      content: [
        {
          type: 'text',
          text: 'Browser MCP is unavailable because browser reuse is not configured for this Claude session.',
        },
      ],
      isError: true,
    });
    return;
  }

  try {
    if (toolName === TOOL_SESSION_INFO) {
      const pages = await listPageTargets();
      writeResponse(id, {
        content: [{ type: 'text', text: formatSessionInfo(pages) }],
      });
      return;
    }

    if (toolName === TOOL_NAVIGATE) {
      const text = await handleNavigate(toolArgs);
      writeResponse(id, {
        content: [{ type: 'text', text }],
      });
      return;
    }

    if (toolName === TOOL_CLICK) {
      const text = await handleClick(toolArgs);
      writeResponse(id, {
        content: [{ type: 'text', text }],
      });
      return;
    }

    if (toolName === TOOL_TYPE) {
      const text = await handleType(toolArgs);
      writeResponse(id, {
        content: [{ type: 'text', text }],
      });
      return;
    }

    if (toolName === TOOL_TAKE_SCREENSHOT) {
      const text = await handleScreenshot(toolArgs);
      writeResponse(id, {
        content: [{ type: 'text', text }],
      });
      return;
    }

    const { page, pageIndex } = await getSelectedPage(toolArgs);

    if (toolName === TOOL_URL_TITLE) {
      const raw = await evaluateInPage(page, 'url-title');
      const parsed = JSON.parse(raw);
      writeResponse(id, {
        content: [
          {
            type: 'text',
            text: `pageIndex: ${pageIndex}\ntitle: ${parsed.title || ''}\nurl: ${parsed.url || ''}`,
          },
        ],
      });
      return;
    }

    if (toolName === TOOL_VISIBLE_TEXT) {
      const text = await evaluateInPage(page, 'visible-text');
      writeResponse(id, {
        content: [{ type: 'text', text: text || '' }],
      });
      return;
    }

    const html = await evaluateInPage(page, 'dom-snapshot');
    writeResponse(id, {
      content: [{ type: 'text', text: html || '' }],
    });
  } catch (error) {
    writeResponse(id, {
      content: [
        {
          type: 'text',
          text: `Browser MCP failed: ${(error && error.message) || String(error)}`,
        },
      ],
      isError: true,
    });
  }
}

async function handleMessage(message) {
  if (!message || message.jsonrpc !== '2.0' || typeof message.method !== 'string') {
    return;
  }

  switch (message.method) {
    case 'initialize':
      writeResponse(message.id, {
        protocolVersion: PROTOCOL_VERSION,
        capabilities: { tools: {} },
        serverInfo: { name: SERVER_NAME, version: SERVER_VERSION },
      });
      return;
    case 'notifications/initialized':
      return;
    case 'ping':
      writeResponse(message.id, {});
      return;
    case 'tools/list':
      writeResponse(message.id, { tools: getTools() });
      return;
    case 'tools/call':
      await handleToolCall(message);
      return;
    default:
      if (message.id !== undefined) {
        writeError(message.id, -32601, `Method not found: ${message.method}`);
      }
  }
}

function parseMessages() {
  while (true) {
    let body;
    const startsWithLegacyHeaders = inputBuffer
      .subarray(0, Math.min(inputBuffer.length, 32))
      .toString('utf8')
      .toLowerCase()
      .startsWith('content-length:');

    if (startsWithLegacyHeaders) {
      const headerEnd = inputBuffer.indexOf('\r\n\r\n');
      if (headerEnd === -1) {
        return;
      }

      const headerText = inputBuffer.subarray(0, headerEnd).toString('utf8');
      const match = headerText.match(/content-length:\s*(\d+)/i);
      if (!match) {
        inputBuffer = Buffer.alloc(0);
        return;
      }

      const contentLength = Number.parseInt(match[1], 10);
      const messageEnd = headerEnd + 4 + contentLength;
      if (inputBuffer.length < messageEnd) {
        return;
      }

      body = inputBuffer.subarray(headerEnd + 4, messageEnd).toString('utf8');
      inputBuffer = inputBuffer.subarray(messageEnd);
    } else {
      const newlineIndex = inputBuffer.indexOf('\n');
      if (newlineIndex === -1) {
        return;
      }

      body = inputBuffer.subarray(0, newlineIndex).toString('utf8').replace(/\r$/, '').trim();
      inputBuffer = inputBuffer.subarray(newlineIndex + 1);
      if (!body) {
        continue;
      }
    }

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

    Promise.resolve(handleMessage(message)).catch((error) => {
      if (message && message.id !== undefined) {
        writeError(message.id, -32603, (error && error.message) || 'Internal error');
      }
    });
  }
}

process.stdin.on('data', (chunk) => {
  inputBuffer = Buffer.concat([inputBuffer, chunk]);
  parseMessages();
});

process.stdin.on('error', () => {
  process.exit(0);
});

['SIGINT', 'SIGTERM', 'SIGHUP'].forEach((signal) => {
  process.on(signal, () => process.exit(0));
});

process.stdin.resume();
