// ===== 控制消息解码面(dop 分派)=====
// 帧形(规格书 §4):u32 len(BE) | 0x83 | ['D' atom-cache 段头(可省)] | ETF 项流
//   控制项流首项 = Int tag → dop 词表分派(dop_gen 封闭查表);后续项 = 参数流。
// 六边形:ETF 项解码藏 EtfPort 注入后(moonbit-eetf 组合根 impl)——
//   beam-dist 核心零 eetf 依赖;字节级项解码=组合根役(真件深化候)。
// 'D' 段头(A8 全规格真件):wire='D'|no_atoms u8|位图|指令段——无 hdr_flags 字节
//   (真源 external.c:987);no_atoms=0 空头整块无位图;非空段解析 attab
//   (旧引用诚实拒——我方无 out 表,槽名不可知=协议违约侧)。

///|
pub(all) suberror ControlError {
  ShortFrame(String) // 帧截断/起头非 83
  UnknownDop(Int32) // tag 不在词表(封闭拒)
  BadTag(String) // 首项非整数(控制项流首项=tag 契约)
  CacheSegment(String) // 'D' 非空段(v0 诚实拒——A8 真件役候)
  Codec(String) // ETF 项解码错(EtfPort 转译)
}

///|
/// ETF 项值(控制面所需子集——beam-dist 自持,eetf 组合根映射;
/// 不 import eetf——六边形归位)
pub(all) enum EtfItem {
  IAtom(String)
  IInt(Int32)
  IPid(String, Int32, Int32, Int32) // node, id, serial, creation
  IRef(String, Int32, Int32) // node, id 序列长, creation
  ITuple(Array[EtfItem])
  IList(Array[EtfItem])
  INil
  IBinary(Bytes)
  IOther // 其余项型(骨架占位——float/map/big 等直通)
}

///|
/// ETF 项解码注入位(组合根=moonbit-eetf impl;decode 一项推进一位;
/// attab='D' 段头解析出的 atom cache 表——'R' ATOM_CACHE_REF 查表语境)
pub(open) trait EtfPort {
  fn decode_term(self : Self, bytes : Bytes, pos : Int32, attab : Array[String]) -> (
    EtfItem,
    Int32,
  ) raise ControlError
}

///|
/// 控制消息(tag+词表名+语义动词+参数项流)
pub(all) struct ControlMsg {
  tag : Int32
  name : String
  semantics : String
  items : Array[EtfItem]
  next_pos : Int32 // ctl 段终止 pos(遇 VERSION_MAGIC 停)——msg 段起点(含 131),
  // 上层解 msg 用(dist.c 两段线形:131|ctl|131|msg)
}

///|
/// latin1 字节列→String(段内 atom 名实形 latin1——dist 头 atom 无 utf8 形;
/// 值域 0-255,>127 兑 '?' 兜底——handshake latin 同款;ControlError 域专用
/// 故不与 handshake.DistError 域 latin 同名[4051])
fn latin1_name(
  frame : Bytes,
  pos : Int32,
  len : Int32,
) -> String raise ControlError {
  if pos + len > frame.length() {
    raise ControlError::ShortFrame(
      "latin1[\{len}] at \{pos} over \{frame.length()}",
    )
  }
  let sb = StringBuilder()
  for i in 0.. sb.write_char(c)
      None => sb.write_char('?')
    }
  }
  sb.to_string()
}

///|
/// 'D' atom-cache 段头全规格解析(A8 真件——moonactor 底本移植;
/// 真源 external.c:987 `ep+=2; no_atoms=get_int8(ep)`):
/// wire = 'D' | no_atoms u8 | 位图 | 指令段——无 hdr_flags 字节。
/// no_atoms=0 → 空头('D' 00 直过,整块无位图——FLAG_BYTES(0) 死区,
/// 金罐 44 00 68 实证);位图 fb=(no_atoms>>1)+1 字节,byte 内高 nibble 先;
/// LONG_ATOMS=位图尾 nibble bit0;指令段顺序紧排:每 atom [cix_lo u8]
/// (nibble 高 3 位=cix 高位;我方无表,槽号仅记账)+(新? [len u8|u16][name]
/// 入 attab / 旧引用诚实拒——声明 ATOM_CACHE 位却无 out 表=协议违约侧)。
/// 非 'D' 原位直过(段头可省)。返回 (attab, ETF 项流起始 pos)。
fn decode_cache_segment(
  frame : Bytes,
  pos : Int32,
) -> (Array[String], Int32) raise ControlError {
  let attab : Array[String] = []
  if pos >= frame.length() || frame[pos].to_int() != 68 {
    // 非 'D'——无段头,原位直过
    return (attab, pos)
  }
  if pos + 1 >= frame.length() {
    raise ControlError::ShortFrame("'D' 段头截断")
  }
  let no_atoms = frame[pos + 1].to_int()
  if no_atoms == 0 {
    // 空头:'D' 00——整块无位图
    return (attab, pos + 2)
  }
  let fb = (no_atoms >> 1) + 1
  let map_pos = pos + 2
  if map_pos + fb > frame.length() {
    raise ControlError::ShortFrame(
      "cache 位图[\{fb}] at \{map_pos} over \{frame.length()}",
    )
  }
  // LONG_ATOMS=位图尾 nibble 的 bit0(真源 external.c:1012-1014)
  let la_byte = frame[map_pos + (no_atoms >> 1)].to_int()
  let la_bit = (no_atoms << 2) & 7
  let long_atoms = ((la_byte >> la_bit) & 1) != 0
  let mut cur = map_pos + fb // 指令段游标(顺序紧排)
  let mut tix = 0
  while tix < no_atoms {
    if cur >= frame.length() {
      raise ControlError::ShortFrame(
        "cache 指令段 at \{cur} over \{frame.length()}",
      )
    }
    let b = frame[map_pos + (tix >> 1)].to_int()
    let n = if tix % 2 == 0 { (b >> 4) & 15 } else { b & 15 }
    let new_atom = (n & 8) != 0
    // 第一步:1B cix 低 8 位(槽号仅记账)
    let _ = ((n & 7) << 8) | frame[cur].to_int()
    cur = cur + 1
    if new_atom {
      // 新 atom:名字 len(long_atoms?u16:u8)+latin1 bytes——入 attab
      let mut ln = 0
      if long_atoms {
        if cur + 2 > frame.length() {
          raise ControlError::ShortFrame("cache 长 atom 名长 at \{cur}")
        }
        ln = (frame[cur].to_int() << 8) | frame[cur + 1].to_int()
        cur = cur + 2
      } else {
        ln = frame[cur].to_int()
        cur = cur + 1
      }
      let name = latin1_name(frame, cur, ln)
      cur = cur + ln
      attab.push(name)
    } else {
      // 旧 atom:对端 cache 槽已有名——我方无 out 表,名字不可知→诚实拒
      raise ControlError::CacheSegment(
        "cache 旧引用(我方无 out 表,槽名不可知)",
      )
    }
    tix += 1
  }
  (attab, cur)
}

///|
/// 控制帧解码:83 起头核+['D' 段头跳]+首项 tag 分派+参数项流收集。
/// frame = 裸 ETF 流(传输面剥 u32 len 后交付——线形守恒)。
pub fn decode_control(
  frame : Bytes,
  etf : &EtfPort,
) -> ControlMsg raise ControlError {
  if frame.length() < 2 || frame[0].to_int() != 131 {
    raise ControlError::ShortFrame("起头非 VERSION_MAGIC(131)")
  }
  let (attab, stream_pos) = decode_cache_segment(frame, 1)
  let (first, next_pos) = etf.decode_term(frame, stream_pos, attab)
  // ctl 两形(dist.c 发侧 TUPLE 元组形/老线裸整数形——真 Erlang 节点发元组形
  // {tag, params...},裸形=tag 整数后参数流;decode 两形兼容)
  let (tag, items, ctl_end) : (Int32, Array[EtfItem], Int32) = match first {
    IInt(v) => {
      // 裸形:tag 整数打头,参数项流紧随(遇 VERSION_MAGIC 停——msg 段起)
      let ps : Array[EtfItem] = []
      let mut pos = next_pos
      while pos < frame.length() && frame[pos].to_int() != 131 {
        let (item, next) = etf.decode_term(frame, pos, attab)
        ps.push(item)
        pos = next
      }
      (v, ps, pos)
    }
    ITuple(arr) => {
      // 元组形:{tag, params...}——tag=arr[0],params=arr[1..];msg=元组外续项
      let v = match arr[0] {
        IInt(t) => t
        _ => raise ControlError::BadTag("元组形 ctl 首元须整数 tag")
      }
      let ps : Array[EtfItem] = []
      for i in 1..
      raise ControlError::BadTag(
        "控制项流首项须整数 tag 或 ctl 元组",
      )
  }
  let name = match dop_name_of(tag) {
    Some(found) => found
    None => raise ControlError::UnknownDop(tag)
  }
  let semantics = match dop_semantics_of(tag) {
    Some(found) => found
    // 词表封闭守恒:name 命中而 semantics 缺=词表违(镜像罐防)
    None => raise ControlError::UnknownDop(tag)
  }
  ControlMsg::{ tag, name, semantics, items, next_pos: ctl_end, }
}

///|
/// 控制错误文本面(show 手写——零 derive 守恒)
pub fn show_control_error(e : ControlError) -> String {
  match e {
    ControlError::ShortFrame(m) => "ShortFrame(\{m})"
    ControlError::UnknownDop(tag) => "UnknownDop(\{tag})"
    ControlError::BadTag(m) => "BadTag(\{m})"
    ControlError::CacheSegment(m) => "CacheSegment(\{m})"
    ControlError::Codec(m) => "Codec(\{m})"
  }
}