import { resolveOxcConfigForFile, runOxcOnSource } from "./runtime-Ci2oTJlY.js";
function createContentLengthMessage(payload) {
  const body = JSON.stringify(payload);
  return `Content-Length: ${new TextEncoder().encode(body).length}\r
\r
${body}`;
}
function fileUriToPath(uri) {
  if (uri.startsWith("file://")) {
    return decodeURIComponent(uri.slice("file://".length));
  }
  return uri;
}
function diagnosticSeverityToLspSeverity(severity) {
  switch (severity) {
    case "error":
      return 1;
    case "warning":
      return 2;
    default:
      return 3;
  }
}
function createLineStarts(sourceText) {
  const lineStarts = [0];
  for (let index = 0; index < sourceText.length; index += 1) {
    if (sourceText[index] === "\n") {
      lineStarts.push(index + 1);
    }
  }
  return lineStarts;
}
function offsetToLspPosition(lineStarts, sourceTextLength, offset) {
  const safeOffset = Math.max(0, Math.min(offset, sourceTextLength));
  let lineIndex = 0;
  while (lineIndex + 1 < lineStarts.length && lineStarts[lineIndex + 1] <= safeOffset) {
    lineIndex += 1;
  }
  return {
    line: lineIndex,
    character: safeOffset - lineStarts[lineIndex]
  };
}
function applyTextDocumentChanges(previousText, contentChanges) {
  if (contentChanges.length === 0) {
    return previousText;
  }
  return contentChanges[contentChanges.length - 1].text;
}
async function runOxcLspSession(options) {
  var _a, _b;
  const { execution, accessor } = options;
  const documents = /* @__PURE__ */ new Map();
  let inputBuffer = "";
  let finished = false;
  let shutdownRequested = false;
  let exitCode = 0;
  let inputQueue = Promise.resolve();
  const sendMessage = (payload) => {
    var _a2;
    execution.outputStreamed = true;
    (_a2 = execution.onStdout) == null ? void 0 : _a2.call(execution, createContentLengthMessage(payload));
  };
  const publishDiagnostics = async (document) => {
    const filePath = fileUriToPath(document.uri);
    const config = resolveOxcConfigForFile(accessor, filePath);
    const result = await runOxcOnSource({
      filePath,
      sourceText: document.text,
      format: false,
      lint: true,
      formatterConfigText: config.formatterConfigText,
      linterConfigText: config.linterConfigText
    });
    const lineStarts = createLineStarts(document.text);
    sendMessage({
      jsonrpc: "2.0",
      method: "textDocument/publishDiagnostics",
      params: {
        uri: document.uri,
        diagnostics: result.diagnostics.map((diagnostic) => ({
          severity: diagnosticSeverityToLspSeverity(diagnostic.severity),
          message: diagnostic.message,
          source: "oxlint",
          range: {
            start: offsetToLspPosition(lineStarts, document.text.length, diagnostic.start),
            end: offsetToLspPosition(lineStarts, document.text.length, diagnostic.end)
          }
        }))
      }
    });
  };
  const handleRequest = async (message) => {
    switch (message.method) {
      case "initialize":
        sendMessage({
          jsonrpc: "2.0",
          id: message.id ?? null,
          result: {
            capabilities: {
              textDocumentSync: 1
            },
            serverInfo: {
              name: "almostnode-oxlint",
              version: "0.1.0"
            }
          }
        });
        return;
      case "initialized":
      case "$/setTrace":
      case "workspace/didChangeConfiguration":
        return;
      case "shutdown":
        shutdownRequested = true;
        sendMessage({
          jsonrpc: "2.0",
          id: message.id ?? null,
          result: null
        });
        return;
      case "exit":
        exitCode = shutdownRequested ? 0 : 1;
        finished = true;
        return;
      case "textDocument/didOpen": {
        const params = message.params;
        const document = {
          uri: params.textDocument.uri,
          version: params.textDocument.version,
          text: params.textDocument.text
        };
        documents.set(document.uri, document);
        await publishDiagnostics(document);
        return;
      }
      case "textDocument/didChange": {
        const params = message.params;
        const previous = documents.get(params.textDocument.uri);
        const nextDocument = {
          uri: params.textDocument.uri,
          version: params.textDocument.version,
          text: applyTextDocumentChanges((previous == null ? void 0 : previous.text) ?? "", params.contentChanges)
        };
        documents.set(nextDocument.uri, nextDocument);
        await publishDiagnostics(nextDocument);
        return;
      }
      case "textDocument/didSave": {
        const params = message.params;
        const existing = documents.get(params.textDocument.uri);
        if (existing) {
          await publishDiagnostics(existing);
        }
        return;
      }
      case "textDocument/didClose": {
        const params = message.params;
        documents.delete(params.textDocument.uri);
        sendMessage({
          jsonrpc: "2.0",
          method: "textDocument/publishDiagnostics",
          params: {
            uri: params.textDocument.uri,
            diagnostics: []
          }
        });
        return;
      }
      default:
        if (message.id !== void 0) {
          sendMessage({
            jsonrpc: "2.0",
            id: message.id,
            result: null
          });
        }
    }
  };
  const processInput = async (chunk) => {
    var _a2;
    inputBuffer += chunk;
    while (true) {
      const headerEnd = inputBuffer.indexOf("\r\n\r\n");
      if (headerEnd < 0) {
        return;
      }
      const headerText = inputBuffer.slice(0, headerEnd);
      const contentLengthMatch = /Content-Length:\s*(\d+)/i.exec(headerText);
      if (!contentLengthMatch) {
        inputBuffer = "";
        return;
      }
      const contentLength = Number(contentLengthMatch[1]);
      const bodyStart = headerEnd + 4;
      if (inputBuffer.length < bodyStart + contentLength) {
        return;
      }
      const body = inputBuffer.slice(bodyStart, bodyStart + contentLength);
      inputBuffer = inputBuffer.slice(bodyStart + contentLength);
      try {
        await handleRequest(JSON.parse(body));
      } catch (error) {
        execution.outputStreamed = true;
        (_a2 = execution.onStderr) == null ? void 0 : _a2.call(
          execution,
          `[almostnode-oxlint-lsp] ${error instanceof Error ? error.message : String(error)}
`
        );
      }
    }
  };
  const stdinTarget = {
    emit() {
    },
    listenerCount() {
      return 0;
    },
    __almostnodePushInput(data) {
      inputQueue = inputQueue.then(() => processInput(data)).catch((error) => {
        var _a2;
        execution.outputStreamed = true;
        (_a2 = execution.onStderr) == null ? void 0 : _a2.call(
          execution,
          `[almostnode-oxlint-lsp] ${error instanceof Error ? error.message : String(error)}
`
        );
      });
    }
  };
  execution.activeProcessStdin = stdinTarget;
  execution.outputStreamed = true;
  while (!((_a = execution.signal) == null ? void 0 : _a.aborted) && !finished) {
    await new Promise((resolve) => setTimeout(resolve, 25));
  }
  await inputQueue;
  execution.activeProcessStdin = null;
  return {
    stdout: "",
    stderr: "",
    exitCode: ((_b = execution.signal) == null ? void 0 : _b.aborted) ? 130 : exitCode
  };
}
export {
  runOxcLspSession
};
//# sourceMappingURL=lsp-BXNfKWOV.js.map
