module Clacky::Channel::Adapters::Feishu::WSClient::ProtoFrame

def self.decode(buf)

def self.decode(buf)
  buf = buf.b
  pos = 0
  result = { headers: {}, payload: "".b }
  while pos < buf.bytesize
    tag_byte, pos = read_varint(buf, pos)
    field_number = tag_byte >> 3
    wire_type = tag_byte & 0x7
    case wire_type
    when 0 # varint
      val, pos = read_varint(buf, pos)
      case field_number
      when 1 then result[:seq_id] = val
      when 2 then result[:log_id] = val
      when 3 then result[:service] = val
      when 4 then result[:method] = val
      end
    when 2 # length-delimited
      len, pos = read_varint(buf, pos)
      bytes = buf.byteslice(pos, len)
      pos += len
      case field_number
      when 5 # header entry
        k, v = decode_header(bytes)
        result[:headers][k] = v if k
      when 7 then result[:payload_type] = bytes.force_encoding("UTF-8")
      when 8 then result[:payload] = bytes
      end
    else
      break # unknown wire type, stop parsing
    end
  end
  result
end

def self.decode_header(buf)

def self.decode_header(buf)
  buf = buf.b
  pos = 0
  key = nil
  val = nil
  while pos < buf.bytesize
    tag_byte, pos = read_varint(buf, pos)
    field_number = tag_byte >> 3
    wire_type = tag_byte & 0x7
    if wire_type == 2
      len, pos = read_varint(buf, pos)
      bytes = buf.byteslice(pos, len)
      pos += len
      case field_number
      when 1 then key = bytes.force_encoding("UTF-8")
      when 2 then val = bytes.force_encoding("UTF-8")
      end
    else
      break
    end
  end
  [key, val]
end

def self.encode(frame)

def self.encode(frame)
  buf = "".b
  buf << encode_varint(1, frame[:seq_id] || 0)
  buf << encode_varint(2, frame[:log_id] || 0)
  buf << encode_varint(3, frame[:service] || 0)
  buf << encode_varint(4, frame[:method] || 0)
  (frame[:headers] || {}).each do |k, v|
    header_bytes = encode_string(1, k.to_s) + encode_string(2, v.to_s)
    buf << encode_length_delimited(5, header_bytes)
  end
  if frame[:payload]
    payload_bytes = frame[:payload].respond_to?(:b) ? frame[:payload].b : frame[:payload].to_s.b
    buf << encode_length_delimited(8, payload_bytes)
  end
  buf
end

def self.encode_length_delimited(field_number, bytes)

def self.encode_length_delimited(field_number, bytes)
  tag = (field_number << 3) | 2  # wire type 2
  encode_raw_varint(tag) + encode_raw_varint(bytes.bytesize) + bytes
end

def self.encode_raw_varint(value)

def self.encode_raw_varint(value)
  bytes = "".b
  loop do
    byte = value & 0x7F
    value >>= 7
    byte |= 0x80 if value > 0
    bytes << byte
    break if value == 0
  end
  bytes
end

def self.encode_string(field_number, str)

def self.encode_string(field_number, str)
  bytes = str.encode("UTF-8").b
  encode_length_delimited(field_number, bytes)
end

def self.encode_varint(field_number, value)

def self.encode_varint(field_number, value)
  tag = (field_number << 3) | 0  # wire type 0
  encode_raw_varint(tag) + encode_raw_varint(value)
end

def self.read_varint(buf, pos)

def self.read_varint(buf, pos)
  result = 0
  shift = 0
  loop do
    byte = buf.getbyte(pos)
    raise "unexpected end of buffer at pos #{pos}" if byte.nil?
    pos += 1
    result |= (byte & 0x7F) << shift
    break unless byte & 0x80 != 0
    shift += 7
  end
  [result, pos]
end