// JSON-RPC protocol helpers for LSP communication over stdin/stdout.
// Reads Content-Length framed messages from stdin, writes to stdout.

var fd = use('fd')
var json = use('json')

// Read a single JSON-RPC message from stdin.
// Protocol: "Content-Length: N\r\n\r\n" followed by N bytes of JSON.
var read_message = function() {
  var header = ""
  var ch = null
  var content_length = null
  var body = null
  var total = 0
  var chunk = null

  // Read header byte by byte until we hit \r\n\r\n
  while (true) {
    ch = fd.read(0, 1)
    if (ch == null) {
      return null
    }
    header = header + text(ch)
    if (ends_with(header, "\r\n\r\n")) {
      break
    }
  }

  // Parse Content-Length from header
  var lines = array(header, "\r\n")
  var _i = 0
  while (_i < length(lines)) {
    if (starts_with(lines[_i], "Content-Length:")) {
      content_length = number(trim(text(lines[_i], 16)))
    }
    _i = _i + 1
  }

  if (content_length == null) {
    return null
  }

  // Read exactly content_length bytes
  body = ""
  total = 0
  while (total < content_length) {
    chunk = fd.read(0, content_length - total)
    if (chunk == null) {
      return null
    }
    chunk = text(chunk)
    body = body + chunk
    total = total + length(chunk)
  }

  return json.decode(body)
}

// Send a JSON-RPC message to stdout.
var send_message = function(msg) {
  var body = json.encode(msg)
  var header = `Content-Length: ${text(length(body))}\r\n\r\n`
  fd.write(1, header + body)
}

// Send a JSON-RPC response for a request.
var respond = function(id, result) {
  send_message({
    jsonrpc: "2.0",
    id: id,
    result: result
  })
}

// Send a JSON-RPC error response.
var respond_error = function(id, code, message) {
  send_message({
    jsonrpc: "2.0",
    id: id,
    error: {
      code: code,
      message: message
    }
  })
}

// Send a JSON-RPC notification (no id).
var notify = function(method, params) {
  send_message({
    jsonrpc: "2.0",
    method: method,
    params: params
  })
}

return {
  read_message: read_message,
  send_message: send_message,
  respond: respond,
  respond_error: respond_error,
  notify: notify
}
