// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
/// Bytecode decoding helpers for the TrueType interpreter.
///
/// Ported from `read_fonts::tables::glyf::bytecode` usage in
/// `fontations/skrifa/src/outline/glyf/hint/engine/dispatch.rs`
/// (Apache-2.0 OR MIT).
priv enum TtProgram {
  Font
  ControlValue
  Glyph
}

///|
priv struct TtInstruction {
  pc : Int
  opcode : Int
  inline_operands : Array[Int]
}

///|
priv struct TtDecoder {
  code : BytesView
  mut pc : Int
}

///|
fn TtDecoder::TtDecoder(code : BytesView) -> TtDecoder {
  { code, pc: 0 }
}

///|
/// Decodes the next TrueType instruction.
///
/// The decoder only expands push instructions into `inline_operands`; all other
/// opcodes have an empty operand list.
fn TtDecoder::decode(self : TtDecoder) -> Result[TtInstruction?, HintError] {
  if self.pc < 0 || self.pc >= self.code.length() {
    return Ok(None)
  }
  let start = self.pc
  let op = self.code.at(self.pc).to_int()
  self.pc = self.pc + 1
  let operands : Array[Int] = Array::new()
  // PUSHB[1..8] 0xB0..0xB7
  if op >= 0xB0 && op <= 0xB7 {
    let n = op - 0xB0 + 1
    if self.pc + n > self.code.length() {
      return Err(UnexpectedEndOfBytecode)
    }
    for _ in 0..= 0xB8 && op <= 0xBF {
    let n = op - 0xB8 + 1
    let bytes = n * 2
    if self.pc + bytes > self.code.length() {
      return Err(UnexpectedEndOfBytecode)
    }
    for i in 0.. self.code.length() {
      return Err(UnexpectedEndOfBytecode)
    }
    let n = self.code.at(self.pc).to_int()
    self.pc = self.pc + 1
    if n < 0 || self.pc + n > self.code.length() {
      return Err(UnexpectedEndOfBytecode)
    }
    for _ in 0.. self.code.length() {
      return Err(UnexpectedEndOfBytecode)
    }
    let n = self.code.at(self.pc).to_int()
    self.pc = self.pc + 1
    let bytes = n * 2
    if n < 0 || self.pc + bytes > self.code.length() {
      return Err(UnexpectedEndOfBytecode)
    }
    for i in 0..