// RFC 9639 section 9. Sample arithmetic stays in Int64 through decorrelation.

///|
priv struct FrameBits {
  data : Bytes
  mut pos : Int32
  mut bit : Int32
  base : Int64
}

///|
fn FrameBits::bad(self : FrameBits, message : String) -> Unit raise FlacError {
  raise Invalid(self.base + self.pos.to_int64(), message)
}

///|
fn FrameBits::read(self : FrameBits, width : Int32) -> Int64 raise FlacError {
  let mut result = 0L
  let mut left = width
  while left > 0 {
    if self.pos >= self.data.length() {
      raise NeedMore
    }
    let take = if left < 8 - self.bit { left } else { 8 - self.bit }
    let part = (self.data[self.pos].to_int() >> (8 - self.bit - take)) &
      ((1 << take) - 1)
    result = (result << take) | part.to_int64()
    self.bit += take
    if self.bit == 8 {
      self.bit = 0
      self.pos += 1
    }
    left -= take
  }
  result
}

///|
fn FrameBits::signed(self : FrameBits, width : Int32) -> Int64 raise FlacError {
  if width == 0 {
    return 0L
  }
  let n = self.read(width)
  if (n & (1L << (width - 1))) != 0L {
    n - (1L << width)
  } else {
    n
  }
}

///|
fn FrameBits::unary(self : FrameBits, maximum : Int64) -> Int64 raise FlacError {
  let mut n = 0L
  while self.pos < self.data.length() {
    let available = 8 - self.bit
    let tail = self.data[self.pos].to_int() & ((1 << available) - 1)
    if tail == 0 {
      // Long Rice quotients are legal. Skip each all-zero byte in one step,
      // including the unused tail when the code starts mid-byte.
      n += available.to_int64()
      self.pos += 1
      self.bit = 0
    } else {
      let mut zeros = 0
      let mut mask = 1 << (available - 1)
      while (tail & mask) == 0 {
        zeros += 1
        mask = mask >> 1
      }
      n += zeros.to_int64()
      self.bit += zeros + 1
      if self.bit == 8 {
        self.bit = 0
        self.pos += 1
      }
      if n > maximum {
        self.bad("unary value exceeds legal range")
      }
      return n
    }
    if n > maximum {
      self.bad("unary value exceeds legal range")
    }
  }
  raise NeedMore
}

///|
// Generated MSB-first polynomial 0x0007, initial zero.
// Private process-lifetime table; no writes or references escape this module.
let frame_crc8_table : FixedArray[Int32] = [
  0, 7, 14, 9, 28, 27, 18, 21, 56, 63, 54, 49, 36, 35, 42, 45, 112, 119, 126, 121,
  108, 107, 98, 101, 72, 79, 70, 65, 84, 83, 90, 93, 224, 231, 238, 233, 252, 251,
  242, 245, 216, 223, 214, 209, 196, 195, 202, 205, 144, 151, 158, 153, 140, 139,
  130, 133, 168, 175, 166, 161, 180, 179, 186, 189, 199, 192, 201, 206, 219, 220,
  213, 210, 255, 248, 241, 246, 227, 228, 237, 234, 183, 176, 185, 190, 171, 172,
  165, 162, 143, 136, 129, 134, 147, 148, 157, 154, 39, 32, 41, 46, 59, 60, 53, 50,
  31, 24, 17, 22, 3, 4, 13, 10, 87, 80, 89, 94, 75, 76, 69, 66, 111, 104, 97, 102,
  115, 116, 125, 122, 137, 142, 135, 128, 149, 146, 155, 156, 177, 182, 191, 184,
  173, 170, 163, 164, 249, 254, 247, 240, 229, 226, 235, 236, 193, 198, 207, 200,
  221, 218, 211, 212, 105, 110, 103, 96, 117, 114, 123, 124, 81, 86, 95, 88, 77,
  74, 67, 68, 25, 30, 23, 16, 5, 2, 11, 12, 33, 38, 47, 40, 61, 58, 51, 52, 78, 73,
  64, 71, 82, 85, 92, 91, 118, 113, 120, 127, 106, 109, 100, 99, 62, 57, 48, 55,
  34, 37, 44, 43, 6, 1, 8, 15, 26, 29, 20, 19, 174, 169, 160, 167, 178, 181, 188,
  187, 150, 145, 152, 159, 138, 141, 132, 131, 222, 217, 208, 215, 194, 197, 204,
  203, 230, 225, 232, 239, 250, 253, 244, 243,
]

///|
// Generated MSB-first polynomial 0x8005, initial zero.
// Private process-lifetime table; no writes or references escape this module.
let frame_crc16_table : FixedArray[Int32] = [
  0, 32773, 32783, 10, 32795, 30, 20, 32785, 32819, 54, 60, 32825, 40, 32813, 32807,
  34, 32867, 102, 108, 32873, 120, 32893, 32887, 114, 80, 32853, 32863, 90, 32843,
  78, 68, 32833, 32963, 198, 204, 32969, 216, 32989, 32983, 210, 240, 33013, 33023,
  250, 33003, 238, 228, 32993, 160, 32933, 32943, 170, 32955, 190, 180, 32945, 32915,
  150, 156, 32921, 136, 32909, 32903, 130, 33155, 390, 396, 33161, 408, 33181, 33175,
  402, 432, 33205, 33215, 442, 33195, 430, 420, 33185, 480, 33253, 33263, 490, 33275,
  510, 500, 33265, 33235, 470, 476, 33241, 456, 33229, 33223, 450, 320, 33093, 33103,
  330, 33115, 350, 340, 33105, 33139, 374, 380, 33145, 360, 33133, 33127, 354, 33059,
  294, 300, 33065, 312, 33085, 33079, 306, 272, 33045, 33055, 282, 33035, 270, 260,
  33025, 33539, 774, 780, 33545, 792, 33565, 33559, 786, 816, 33589, 33599, 826,
  33579, 814, 804, 33569, 864, 33637, 33647, 874, 33659, 894, 884, 33649, 33619,
  854, 860, 33625, 840, 33613, 33607, 834, 960, 33733, 33743, 970, 33755, 990, 980,
  33745, 33779, 1014, 1020, 33785, 1000, 33773, 33767, 994, 33699, 934, 940, 33705,
  952, 33725, 33719, 946, 912, 33685, 33695, 922, 33675, 910, 900, 33665, 640, 33413,
  33423, 650, 33435, 670, 660, 33425, 33459, 694, 700, 33465, 680, 33453, 33447,
  674, 33507, 742, 748, 33513, 760, 33533, 33527, 754, 720, 33493, 33503, 730, 33483,
  718, 708, 33473, 33347, 582, 588, 33353, 600, 33373, 33367, 594, 624, 33397, 33407,
  634, 33387, 622, 612, 33377, 544, 33317, 33327, 554, 33339, 574, 564, 33329, 33299,
  534, 540, 33305, 520, 33293, 33287, 514,
]

///|
// Width is 8 or 16 at all private callers. Checked data indexing retains
// the original slice-bound failure behavior; an empty/reversed range is 0.
fn frame_crc(data : Bytes, start : Int32, end : Int32, width : Int32) -> Int32 {
  let mut crc = 0
  if width == 8 {
    for i = start; i < end; i = i + 1 {
      crc = frame_crc8_table.unsafe_get(crc ^ data[i].to_int())
    }
  } else {
    for i = start; i < end; i = i + 1 {
      let index = (crc >> 8) ^ data[i].to_int()
      crc = ((crc << 8) & 65535) ^ frame_crc16_table.unsafe_get(index)
    }
  }
  crc
}

///|
fn frame_number(r : FrameBits, variable : Bool) -> Int64 raise FlacError {
  let first = r.read(8).to_int()
  if first < 128 {
    return first.to_int64()
  }
  let mut count = 0
  let mut mask = 128
  while (first & mask) != 0 && mask > 0 {
    count += 1
    mask = mask >> 1
  }
  if count < 2 || count > (if variable { 7 } else { 6 }) {
    r.bad("invalid coded frame/sample number")
  }
  let mut n = (first & (mask - 1)).to_int64()
  for i = 1; i < count; i = i + 1 {
    let b = r.read(8)
    if (b & 0xC0L) != 0x80L {
      r.bad("invalid coded-number continuation")
    }
    n = (n << 6) | (b & 63L)
  }
  let minima : Array[Int64] = [
    0L, 0L, 128L, 2048L, 65536L, 2097152L, 67108864L, 2147483648L,
  ]
  if n < minima[count] {
    r.bad("overlong coded frame/sample number")
  }
  n
}

///|
fn frame_residual(
  r : FrameBits,
  samples : Array[Int64],
  order : Int32,
) -> Unit raise FlacError {
  let coding = r.read(2).to_int()
  if coding > 1 {
    r.bad("reserved residual coding method")
  }
  let partition_order = r.read(4).to_int()
  let partitions = 1 << partition_order
  let size = samples.length() / partitions
  if samples.length() % partitions != 0 || size <= order {
    r.bad("invalid residual partition order")
  }
  let parameter_bits = coding + 4
  let mut index = order
  for p = 0; p < partitions; p = p + 1 {
    let count = if p == 0 { size - order } else { size }
    let parameter = r.read(parameter_bits).to_int()
    if parameter == (1 << parameter_bits) - 1 {
      let width = r.read(5).to_int()
      for i = 0; i < count; i = i + 1 {
        samples[index] = r.signed(width)
        index += 1
      }
    } else {
      for i = 0; i < count; i = i + 1 {
        let quotient = r.unary(4294967294L >> parameter)
        let folded = (quotient << parameter) | r.read(parameter)
        if folded > 4294967294L {
          r.bad("residual outside signed 31-bit magnitude")
        }
        samples[index] = if (folded & 1L) == 0L {
          folded >> 1
        } else {
          -(folded >> 1) - 1L
        }
        index += 1
      }
    }
  }
}

///|
fn frame_range(
  r : FrameBits,
  sample : Int64,
  width : Int32,
) -> Unit raise FlacError {
  let bound = 1L << (width - 1)
  if sample < -bound || sample >= bound {
    r.bad("decoded sample exceeds declared bit depth")
  }
}

///|
fn frame_subframe(
  r : FrameBits,
  size : Int32,
  width : Int32,
) -> Array[Int64] raise FlacError {
  if r.read(1) != 0L {
    r.bad("nonzero subframe padding bit")
  }
  let kind = r.read(6).to_int()
  let wasted = if r.read(1) == 0L {
    0
  } else {
    r.unary((width - 2).to_int64()).to_int() + 1
  }
  let depth = width - wasted
  let samples = Array::make(size, 0L)
  if kind == 0 {
    let value = r.signed(depth)
    samples.fill(value)
  } else if kind == 1 {
    for i = 0; i < size; i = i + 1 {
      samples[i] = r.signed(depth)
    }
  } else if (kind >= 8 && kind <= 12) || kind >= 32 {
    let order = if kind >= 32 { kind - 31 } else { kind - 8 }
    if order >= size {
      r.bad("predictor order is not smaller than block size")
    }
    for i = 0; i < order; i = i + 1 {
      samples[i] = r.signed(depth)
    }
    let coefficients : Array[Int64] = []
    let mut shift = 0
    if kind >= 32 {
      let precision = r.read(4).to_int() + 1
      if precision == 16 {
        r.bad("forbidden LPC coefficient precision")
      }
      shift = r.signed(5).to_int()
      if shift < 0 {
        r.bad("negative LPC shift is forbidden")
      }
      for i = 0; i < order; i = i + 1 {
        coefficients.push(r.signed(precision))
      }
    }
    frame_residual(r, samples, order)
    for i = order; i < size; i = i + 1 {
      let prediction = if kind >= 32 {
        let mut sum = 0L
        for j = 0; j < order; j = j + 1 {
          sum += coefficients[j] * samples[i - j - 1]
        }
        sum >> shift
      } else {
        match order {
          0 => 0L
          1 => samples[i - 1]
          2 => 2L * samples[i - 1] - samples[i - 2]
          3 => 3L * samples[i - 1] - 3L * samples[i - 2] + samples[i - 3]
          _ =>
            4L * samples[i - 1] -
            6L * samples[i - 2] +
            4L * samples[i - 3] -
            samples[i - 4]
        }
      }
      samples[i] += prediction
      // Validate before feeding a sample into another prediction: malformed
      // streams cannot grow coefficients into an Int64 overflow.
      frame_range(r, samples[i], depth)
    }
  } else {
    r.bad("reserved subframe type")
  }
  for i = 0; i < size; i = i + 1 {
    samples[i] = samples[i] << wasted
  }
  samples
}

///|
fn parse_frame(
  data : Bytes,
  start : Int32,
  info : StreamInfo,
  absolute_offset : Int64,
) -> (Frame, Int32) raise FlacError {
  if start < 0 || start > data.length() {
    raise Invalid(absolute_offset, "invalid frame offset")
  }
  let r : FrameBits = {
    data,
    pos: start,
    bit: 0,
    base: absolute_offset - start.to_int64(),
  }
  if r.read(15) != 0x7FFCL {
    r.bad("invalid frame sync")
  }
  let explicit_variable = r.read(1) != 0L
  let block_code = r.read(4).to_int()
  // Appendix B.1: pre-2007 encoders signaled variable blocking through
  // STREAMINFO and used only explicit block-size codes for these streams.
  let variable_block = explicit_variable ||
    (
      info.min_block_size != info.max_block_size &&
      (block_code == 6 || block_code == 7)
    )
  let rate_code = r.read(4).to_int()
  let assignment = r.read(4).to_int()
  let depth_code = r.read(3).to_int()
  if r.read(1) != 0L {
    r.bad("nonzero reserved frame header bit")
  }
  if block_code == 0 || rate_code == 15 || assignment > 10 || depth_code == 3 {
    r.bad("reserved frame header value")
  }
  let number = frame_number(r, variable_block)
  let block_size = match block_code {
    1 => 192
    2 | 3 | 4 | 5 => 144 << block_code
    6 => r.read(8).to_int() + 1
    7 => r.read(16).to_int() + 1
    _ => 1 << block_code
  }
  if block_size > 65535 {
    r.bad("forbidden block size 65536")
  }
  let sample_rate = match rate_code {
    0 => info.sample_rate
    1 => 88200
    2 => 176400
    3 => 192000
    4 => 8000
    5 => 16000
    6 => 22050
    7 => 24000
    8 => 32000
    9 => 44100
    10 => 48000
    11 => 96000
    12 => r.read(8).to_int() * 1000
    13 => r.read(16).to_int()
    _ => r.read(16).to_int() * 10
  }
  let bits_per_sample = match depth_code {
    0 => info.bits_per_sample
    1 => 8
    2 => 12
    4 => 16
    5 => 20
    6 => 24
    _ => 32
  }
  if bits_per_sample < 4 || bits_per_sample > 32 {
    r.bad("invalid sample bit depth")
  }
  let header_crc = frame_crc(data, start, r.pos, 8)
  if r.read(8).to_int() != header_crc {
    r.bad("frame header CRC8 mismatch")
  }
  let channel_count = if assignment < 8 { assignment + 1 } else { 2 }
  let decoded : Array[Array[Int64]] = []
  for channel = 0; channel < channel_count; channel = channel + 1 {
    let side = (assignment == 8 && channel == 1) ||
      (assignment == 9 && channel == 0) ||
      (assignment == 10 && channel == 1)
    decoded.push(
      frame_subframe(
        r,
        block_size,
        bits_per_sample + (if side { 1 } else { 0 }),
      ),
    )
  }
  if r.bit != 0 && r.read(8 - r.bit) != 0L {
    r.bad("nonzero frame alignment padding")
  }
  let crc = frame_crc(data, start, r.pos, 16)
  if r.read(16).to_int() != crc {
    r.bad("frame CRC16 mismatch")
  }
  if assignment >= 8 {
    for i = 0; i < block_size; i = i + 1 {
      let a = decoded[0][i]
      let b = decoded[1][i]
      if assignment == 8 {
        decoded[1][i] = a - b
      } else if assignment == 9 {
        decoded[0][i] = a + b
      } else {
        let mid = (a << 1) | (b & 1L)
        decoded[0][i] = (mid + b) >> 1
        decoded[1][i] = (mid - b) >> 1
      }
    }
  }
  let channels : Array[Array[Int32]] = []
  for channel in decoded {
    let output = Array::make(block_size, 0)
    for i = 0; i < block_size; i = i + 1 {
      frame_range(r, channel[i], bits_per_sample)
      output[i] = channel[i].to_int()
    }
    channels.push(output)
  }
  let sample_number = if variable_block {
    number
  } else {
    number * info.max_block_size.to_int64()
  }
  (
    {
      sample_number,
      number,
      variable_block,
      sample_rate,
      bits_per_sample,
      channels,
      block_size,
      byte_offset: absolute_offset,
      byte_length: r.pos - start,
    },
    r.pos,
  )
}