// ===== decode:ETF 字节流 → EtfTerm =====
// 纯核零依赖:Bytes/String 即 core builtin;真帧金罐守护(见 golden_test)。

///|
pub(all) suberror EtfError {
  Truncated(String)
  Malformed(String)
  DepthExceeded(String) // 嵌套超限(恶意深嵌套帧——递归栈爆防护)
}

///|
/// 读入口:带 VERSION_MAGIC 的整帧(0x83 起);无 magic 诚实拒
pub fn decode(
  data : Bytes,
  attab~ : Array[String] = [],
) -> EtfTerm raise EtfError {
  if data.length() < 1 {
    raise EtfError::Truncated("empty")
  }
  if data[0].to_int() != VERSION_MAGIC {
    raise EtfError::Malformed("missing 0x83 magic")
  }
  let pair = dec(data, 1, DEPTH_LIMIT, attab)
  pair.0
}

///|
/// 读入口(无 magic,段内):返回 (term, 下一 pos)——组合用
pub fn decode_term(
  data : Bytes,
  pos : Int32,
  attab~ : Array[String] = [],
) -> (EtfTerm, Int32) raise EtfError {
  dec(data, pos, DEPTH_LIMIT, attab)
}

///|
/// 嵌套深度上限(恶意深嵌套帧=递归栈爆防护——dist 直连暴露面;
/// dist 面 tuple/list 实测深 3-5,64 远超业务余量)
const DEPTH_LIMIT : Int32 = 64

///|
/// 流内严格解码(131 流内=错帧——版本字节只属流头/独立流入口 decode;
/// A3 同流多项契约:dist header 后续项省略 131,现 131=线形违)
fn dec(
  data : Bytes,
  pos : Int32,
  depth : Int32,
  attab : Array[String],
) -> (EtfTerm, Int32) raise EtfError {
  if depth <= 0 {
    raise EtfError::DepthExceeded("nesting exceeds \{DEPTH_LIMIT} at \{pos}")
  }
  if pos >= data.length() {
    raise EtfError::Truncated("tag at \{pos}")
  }
  let tag = data[pos].to_int()
  if tag == VERSION_MAGIC {
    raise EtfError::Malformed(
      "spurious VERSION_MAGIC at \{pos}(流内只属流头)",
    )
  }
  match tag {
    TAG_SMALL_INTEGER => (EtfTerm::EInt(data[pos + 1].to_int()), pos + 2)
    TAG_INTEGER => {
      let v = rd_u32(data, pos + 1)
      if v < 0 {
        // u32 高位=Int32 符号位(静默负溢 bug 面——EInt 值域 Int32 诚实钉死)
        raise EtfError::Malformed("INTEGER exceeds Int32 domain")
      }
      (EtfTerm::EInt(v), pos + 5)
    }
    TAG_NEW_FLOAT => {
      // 8B IEEE754 BE——按位组装 Double(骨架:读 64bit 整数再 reinterpret)
      let bits = rd_u64(data, pos + 1)
      (EtfTerm::EFloat(bits.reinterpret_as_double()), pos + 9)
    }
    TAG_ATOM_EXT => {
      let n = rd_u16(data, pos + 1)
      (EtfTerm::EAtom(latin(data, pos + 3, n)), pos + 3 + n)
    }
    TAG_ATOM_UTF8 => {
      let n = rd_u16(data, pos + 1)
      (EtfTerm::EAtom(latin(data, pos + 3, n)), pos + 3 + n)
    }
    TAG_SMALL_ATOM_UTF8 => {
      let n = data[pos + 1].to_int()
      (EtfTerm::EAtom(latin(data, pos + 2, n)), pos + 2 + n)
    }
    TAG_SMALL_TUPLE => {
      let arity = data[pos + 1].to_int()
      let (items, np) = decode_n(data, pos + 2, arity, depth, attab)
      (EtfTerm::ETuple(items), np)
    }
    TAG_LARGE_TUPLE => {
      let arity = rd_u32(data, pos + 1)
      let (items, np) = decode_n(data, pos + 5, arity, depth, attab)
      (EtfTerm::ETuple(items), np)
    }
    TAG_NIL => (EtfTerm::ENil, pos + 1)
    TAG_STRING => {
      // latin1 字节列→String(整数字节快捷形)
      let n = rd_u16(data, pos + 1)
      (EtfTerm::EString(latin(data, pos + 3, n)), pos + 3 + n)
    }
    TAG_LIST => {
      let n = rd_u32(data, pos + 1)
      let (items, np) = decode_n(data, pos + 5, n, depth, attab)
      // 尾项必须 ENil(proper list; improper 挂账)
      let (tail, np2) = dec(data, np, depth - 1, attab)
      if tail is EtfTerm::ENil {
        (EtfTerm::EList(items), np2)
      } else {
        raise EtfError::Malformed("improper list tail")
      }
    }
    TAG_BINARY => {
      let n = rd_u32(data, pos + 1)
      if pos + 5 + n > data.length() {
        raise EtfError::Truncated("binary at \{pos}")
      }
      (EtfTerm::EBinary(data[pos + 5:pos + 5 + n].to_owned()), pos + 5 + n)
    }
    TAG_MAP => {
      let n = rd_u32(data, pos + 1)
      let pairs : Array[(EtfTerm, EtfTerm)] = []
      let mut cur = pos + 5
      for _ in 0.. {
      let (node, np) = decode_atom_item(data, pos + 1, depth - 1, attab)
      let id = rd_u32(data, np)
      let serial = rd_u32(data, np + 4)
      let creation = rd_u32(data, np + 8)
      (EtfTerm::EPid(node, id, serial, creation), np + 12)
    }
    TAG_NEW_PORT => {
      let (node, np) = decode_atom_item(data, pos + 1, depth - 1, attab)
      let id = rd_u32(data, np)
      let creation = rd_u32(data, np + 4)
      (EtfTerm::EPort(node, id, creation), np + 8)
    }
    TAG_NEW_PORT_V2 => {
      // OTP26 port 扩展形:node+id u32+serial u32+creation u32(真帧 dump 铁证
      // probea@dev 6 端口项 port_idx 键值;serial 位 port 对象占位跳过)
      let (node, np) = decode_atom_item(data, pos + 1, depth - 1, attab)
      let id = rd_u32(data, np)
      let creation = rd_u32(data, np + 8)
      (EtfTerm::EPort(node, id, creation), np + 12)
    }
    TAG_NEW_REFERENCE => {
      let idlen = rd_u16(data, pos + 1)
      let (node, np) = decode_atom_item(data, pos + 3, depth - 1, attab)
      let creation = rd_u32(data, np) // 'Z' 形 creation u32(OTP21+)
      let id0 = rd_u32(data, np + 4)
      (EtfTerm::ERef(node, id0, 0, creation), np + 4 + 4 * idlen)
    }
    114 => { // 'r' NEW_REFERENCE_EXT creation u8 形(与 'Z' 只差位宽——规格书 §7)
      let idlen = rd_u16(data, pos + 1)
      let (node, np) = decode_atom_item(data, pos + 3, depth - 1, attab)
      let creation = data[np].to_int()
      let id0 = rd_u32(data, np + 1)
      (EtfTerm::ERef(node, id0, 0, creation), np + 1 + 4 * idlen)
    }
    115 => { // 's' SMALL_ATOM(len u8 latin1)
      let n = data[pos + 1].to_int()
      (EtfTerm::EAtom(latin(data, pos + 2, n)), pos + 2 + n)
    }
    TAG_SMALL_BIG => {
      // 110 SMALL_BIG_EXT:nbytes u8 | sign u8 | digits 小端(big.c bytes_to_big 铁证)
      let n = data[pos + 1].to_int()
      let sign = data[pos + 2].to_int()
      if n > 4 {
        raise EtfError::Malformed("bignum exceeds i32 domain (\{n} bytes)")
      }
      if pos + 3 + n > data.length() {
        raise EtfError::Truncated("small_big at \{pos}")
      }
      if sign > 1 {
        raise EtfError::Malformed("bignum sign " + sign.to_string())
      }
      // 小端组装(digits[0]=最低字节)
      let mut v = 0
      for i in 0.. 2147483647) {
        raise EtfError::Malformed("bignum exceeds i32 domain")
      }
      let val = if sign == 1 { -v } else { v }
      (EtfTerm::EInt(val), pos + 3 + n)
    }
    TAG_ATOM_CACHE_REF => {
      // 'R' ATOM_CACHE_REF:u8 槽号→查分发头 attab(真帧 52 00/52 01 大量;
      // attab 空或越界=诚实拒——单帧无 dist header 语境)
      if pos + 2 > data.length() {
        raise EtfError::Truncated("cache ref at \{pos}")
      }
      let ix = data[pos + 1].to_int()
      if ix >= attab.length() {
        raise EtfError::Malformed(
          "atom cache ref \{ix} 越界(attab \{attab.length()})",
        )
      }
      (EtfTerm::EAtom(attab[ix]), pos + 2)
    }
    other => raise EtfError::Malformed("unsupported ETF tag \{other} at \{pos}")
  }
}

///|
fn decode_n(
  data : Bytes,
  pos : Int32,
  count : Int32,
  depth : Int32,
  attab : Array[String],
) -> (Array[EtfTerm], Int32) raise EtfError {
  let items : Array[EtfTerm] = []
  let mut cur = pos
  for _ in 0.. (String, Int32) raise EtfError {
  let (t, np) = dec(data, pos, depth - 1, attab)
  match t {
    EtfTerm::EAtom(s) => (s, np)
    _ => raise EtfError::Malformed("node term not atom")
  }
}

///|
fn rd_u16(data : Bytes, pos : Int32) -> Int32 raise EtfError {
  if pos + 2 > data.length() {
    raise EtfError::Truncated("u16 at \{pos}")
  }
  (data[pos].to_int() << 8) | data[pos + 1].to_int()
}

///|
fn rd_u32(data : Bytes, pos : Int32) -> Int32 raise EtfError {
  if pos + 4 > data.length() {
    raise EtfError::Truncated("u32 at \{pos}")
  }
  (data[pos].to_int() << 24) |
  (data[pos + 1].to_int() << 16) |
  (data[pos + 2].to_int() << 8) |
  data[pos + 3].to_int()
}

///|
fn rd_u64(data : Bytes, pos : Int32) -> UInt64 raise EtfError {
  if pos + 8 > data.length() {
    raise EtfError::Truncated("u64 at \{pos}")
  }
  let mut v : UInt64 = 0UL
  for k in 0..<8 {
    v = (v << 8) | data[pos + k].to_int().to_uint64()
  }
  v
}

///|
/// latin-1/ASCII 域字节串→String(骨架 v0:原子/节点名全 ASCII 域;零 @utf8 依赖——core 零依赖守恒)
fn latin(data : Bytes, pos : Int32, len : Int32) -> String raise EtfError {
  if pos + len > data.length() {
    raise EtfError::Truncated("latin[\{len}] at \{pos} over \{data.length()}")
  }
  let sb = StringBuilder()
  let mut i = pos
  while i < pos + len {
    match data[i].to_int().to_char() {
      Some(c) => sb.write_char(c)
      None => sb.write_char('?')
    }
    i = i + 1
  }
  sb.to_string()
}