const tagInteger = 0x02
const tagSequence = 0x30

/** The end justifies the means. */
export default class Asn1SequenceDecoder {
  buffer: Buffer

  offset: number

  constructor(buffer: Buffer) {
    if (buffer[0] !== tagSequence) {
      throw new TypeError()
    }

    this.buffer = buffer
    this.offset = 1

    const len = this.decodeLength()
    if (len !== buffer.length - this.offset) {
      throw new TypeError()
    }
  }

  decodeLength() {
    let length = this.buffer[this.offset++]
    if (length & 0x80) {
      // Long form.
      const nBytes = length & ~0x80
      length = 0
      for (let i = 0; i < nBytes; i++) length = (length << 8) | this.buffer[this.offset + i]
      this.offset += nBytes
    }
    return length
  }

  unsignedInteger() {
    if (this.buffer[this.offset++] !== tagInteger) {
      throw new TypeError()
    }

    let length = this.decodeLength()

    // There may be exactly one leading zero (if the next byte's MSB is set).
    if (this.buffer[this.offset] === 0) {
      this.offset++
      length--
    }

    const result = this.buffer.slice(this.offset, this.offset + length)
    this.offset += length
    return result
  }

  end() {
    if (this.offset !== this.buffer.length) {
      throw new TypeError()
    }
  }
}
