///|
priv struct Av1IvfStreamState {
  limits : DecodeLimits
  mut track : Av1DemuxedTrack?
  mut scale : Int64
  mut declared : Int64
  mut count : Int
}

///|
fn Av1IvfStreamState::new(limits : DecodeLimits) -> Av1IvfStreamState {
  { limits, track: None, scale: 0L, declared: 0L, count: 0, }
}

///|
fn Av1IvfStreamState::retained_bytes(_self : Av1IvfStreamState) -> Int {
  0
}

///|
fn Av1IvfStreamState::step(
  self : Av1IvfStreamState,
  input : ContainerStreamInput,
  eof : Bool,
) -> Result[ContainerStreamStep, DecodeError] {
  let p = input.start
  let data = input.bytes
  let available = input.available()
  if self.track is None {
    if available < 32 {
      return Ok(Wait)
    }
    let size = ivf_u16(data, p + 6)
    if size < 32 {
      return Err(decode_error(InvalidData, "ivf.header", "Invalid header size"))
    }
    if size > self.limits.max_input_bytes {
      return Err(
        decode_error(
          LimitExceeded,
          "ivf.header",
          "Header exceeds retained-input budget",
        ),
      )
    }
    if available < size {
      return Ok(Wait)
    }
    let header = Array::makei(size, i => data[p + i])
    self.declared = ivf_u32(header, 24)
    if self.declared > self.limits.max_frames.to_int64() {
      return Err(
        decode_error(LimitExceeded, "ivf.header", "Track exceeds max_frames"),
      )
    }
    // Reuse the complete parser's exact header checks, with unspecified count.
    for i in 24..<28 {
      header[i] = 0
    }
    self.track = Some(
      match av1_demux_ivf(header, limits=self.limits) {
        Err(error) => return Err(error)
        Ok(value) => value
      },
    )
    self.scale = ivf_u32(data, p + 20)
    input.consume(size)
    return Ok(Progress)
  }
  if available == 0 && eof {
    if self.declared != 0L && self.declared != self.count.to_int64() {
      return Err(
        decode_error(
          TruncatedInput,
          "ivf.count",
          "Declared record count exceeds available packets",
        ),
      )
    }
    return Ok(End)
  }
  if available < 12 {
    return Ok(Wait)
  }
  if self.count == self.limits.max_frames ||
    (self.declared != 0L && self.count.to_int64() == self.declared) {
    let kind = if self.count == self.limits.max_frames {
      LimitExceeded
    } else {
      InvalidData
    }
    return Err(decode_error(kind, "ivf.count", "Too many IVF records"))
  }
  let length = ivf_u32(data, p)
  if length == 0L {
    return Err(decode_error(InvalidData, "ivf.packet", "Empty AV1 record"))
  }
  if self.limits.max_input_bytes < 12 ||
    length > (self.limits.max_input_bytes - 12).to_int64() {
    return Err(
      decode_error(
        LimitExceeded,
        "ivf.packet",
        "Record exceeds retained-input budget",
      ),
    )
  }
  if length > (available - 12).to_int64() {
    return Ok(Wait)
  }
  let timestamp = ivf_timestamp(data, p + 4)
  if timestamp > 9223372036854775807L / self.scale ||
    timestamp < (-9223372036854775807L - 1L) / self.scale {
    return Err(
      decode_error(
        Unsupported,
        "ivf.timestamp",
        "Scaled timestamp does not fit Int64",
      ),
    )
  }
  let packet : Av1Packet = {
    data: Array::makei(length.to_int(), i => data[p + 12 + i]),
    presentation_timestamp: Some(timestamp * self.scale),
    decode_timestamp: None,
    duration: None,
    sync_sample: None,
  }
  input.consume(12 + length.to_int())
  self.count += 1
  Ok(Packet(packet))
}