// frame.mbt — FEC 线格式适配器(K8 刀3;合同 = domain/fec_dialect.toml)
//
// 12B 头(大端,对位 KCP 24B 头字节序惯例):
//   [0..4)   group_id    u32  组号,发侧逐组递增
//   [4]      shard_index u8   片位:=k 冗余片
//   [5]      k           u8
//   [6]      m           u8
//   [7]      shard_total u8   = k+m(一致性校验位)
//   [8..10)  payload_len u16  头内载荷长(体内 body_len 的镜像)
//   [10..12) reserved    u16  = 0
//
// 片体(受保护域,RS 全片可重建):[0..2) body_len u16 + 载荷 + 零垫。
// 载荷长双写的原因:恢复重建的整片含体,12B 头不可重建——直通快径读头,
// 恢复径只认体内 body_len(单一真相在体内,头是镜像,一致性有门钉)。

///|
/// FEC 头字节数(线帧 = 头 + 片体;刀4 以此让位 KCP mtu,D-FEC5)。
pub const FEC_HEADER_SIZE : Int32 = 12

///|
priv struct FecHeader {
  group_id : Int32
  shard_index : Int32
  k : Int32
  m : Int32
  shard_total : Int32
  payload_len : Int32
}

///|
/// 写 12B 头(帧头可编码后重盖:冗余帧即此用法)。
fn fec_write_header(
  frame : FixedArray[Byte],
  group_id : Int32,
  shard_index : Int32,
  k : Int32,
  m : Int32,
  payload_len : Int32,
) -> Unit {
  frame[0] = ((group_id >> 24) & 0xFF).to_byte()
  frame[1] = ((group_id >> 16) & 0xFF).to_byte()
  frame[2] = ((group_id >> 8) & 0xFF).to_byte()
  frame[3] = (group_id & 0xFF).to_byte()
  frame[4] = (shard_index & 0xFF).to_byte()
  frame[5] = (k & 0xFF).to_byte()
  frame[6] = (m & 0xFF).to_byte()
  frame[7] = ((k + m) & 0xFF).to_byte()
  frame[8] = ((payload_len >> 8) & 0xFF).to_byte()
  frame[9] = (payload_len & 0xFF).to_byte()
  frame[10] = (0).to_byte()
  frame[11] = (0).to_byte()
}

///|
/// 读 12B 头 + 一致性校验:短帧 / k·m 越域 / shard_total 失配 /
/// index 越组 / payload_len 超帧余量 → None(弃置面自计)。
fn fec_read_header(frame : FixedArray[Byte]) -> FecHeader? {
  if frame.length() < FEC_HEADER_SIZE {
    return None
  }
  let group_id = (frame[0].to_int() << 24) |
    (frame[1].to_int() << 16) |
    (frame[2].to_int() << 8) |
    frame[3].to_int()
  let k = frame[5].to_int()
  let m = frame[6].to_int()
  let shard_total = frame[7].to_int()
  let payload_len = (frame[8].to_int() << 8) | frame[9].to_int()
  // 线域:shard_total 单字节 ⇒ k+m ≤ 255(k+m=256 写不出——字节回卷
  // 为 0,恒被 shard_total 核拒;此门拨 255 与之同判,免死宽)。
  // 编解码域(GF 上限 256)由 RsCodec::new 守卫另执,两级不同面。
  if k < 1 || m < 1 || k + m > 255 || shard_total != k + m {
    return None
  }
  let shard_index = frame[4].to_int()
  if shard_index >= shard_total {
    return None
  }
  if payload_len > frame.length() - FEC_HEADER_SIZE {
    return None
  }
  let header : FecHeader = {
    group_id,
    shard_index,
    k,
    m,
    shard_total,
    payload_len,
  }
  Some(header)
}

///|
/// 读体内体长前缀(受保护域,恢复径的单一真相)。
fn fec_body_len(shard : FixedArray[Byte]) -> Int32 {
  (shard[FEC_HEADER_SIZE].to_int() << 8) | shard[FEC_HEADER_SIZE + 1].to_int()
}

///|
/// 剥头剥垫取载荷:体内 body_len 定长(直通帧与恢复重建片同形)。
fn fec_payload_of(shard : FixedArray[Byte]) -> FixedArray[Byte] {
  let body_len = fec_body_len(shard)
  let payload = FixedArray::make(body_len, (0).to_byte())
  FixedArray::unsafe_blit(payload, 0, shard, FEC_HEADER_SIZE + 2, body_len)
  payload
}