// fec_session.mbt — FEC 会话壳(K8 刀4)
//
// 组合宿主:KcpSession + FecTx/FecRx 薄包装,应用面 API 一一透传。
// 接线(茗篇 §一):
//   - send_message → KcpSession.send_message(KCP 面零改动)
//   - tick         → KCP 帧 逐帧 FecTx.feed(组满同突发出冗余)
//   - on_datagram  → 线帧 FecRx.feed 出 KCP 报文 逐个喂会话
//   - poll_message → 直通
// 线预算(D-FEC5):片容量 = KCP mtu + FEC 头 + 体长前缀(缺省 1414
// ≤ 路径 MTU 1500);更紧预算的路径,建壳前先 session.kcp.set_mtu(预算−14)
// (容量构造时冻结)。载荷超容量时 FecTx.feed abort(诚实急停,刀3 语义)。
// FEC 关闭 = 直接用 KcpSession——本壳不存在即直通,核零沾。

///|
/// FEC 会话:KCP 会话 + FEC 发/收机(层外组合,双向对称)。
pub struct FecSession {
  session : KcpSession
  tx : @fec.FecTx
  rx : @fec.FecRx
}

///|
/// 新会话:conv 双端一致;high_water = 背压水位;k/m 组形;
/// 恢复窗深缺省 8 组。片容量按 KCP 当前 mtu 推导。
pub fn FecSession::new(
  conv : Int32,
  high_water : Int32,
  k : Int32,
  m : Int32,
) -> FecSession {
  let session = KcpSession::new(conv, high_water)
  let capacity = session.kcp.mtu + @fec.FEC_HEADER_SIZE + 2
  { session, tx: @fec.FecTx::new(k, m, capacity), rx: @fec.FecRx::new(8), }
}

///|
/// 应用下发一消息(透传;返回同 KcpSession::send_message)。
pub fn FecSession::send_message(
  self : FecSession,
  payload : FixedArray[Byte],
) -> Int32 {
  self.session.send_message(payload)
}

///|
/// 宿主投递一线帧:FEC 收机结算,出的 KCP 报文逐个喂会话。
/// 返回第一个非零 input 错码(全零返 0)。
pub fn FecSession::on_datagram(
  self : FecSession,
  frame : FixedArray[Byte],
) -> Int32 {
  let mut code = 0
  for msg in self.rx.feed(frame) {
    let c = self.session.on_datagram(msg)
    if c != 0 && code == 0 {
      code = c
    }
  }
  code
}

///|
/// 宿主时钟推进:KCP 到点 flush 出的帧逐个入 FEC 发机,
/// 返回待发送线帧(宿主逐帧走 UDP 发出)。
pub fn FecSession::tick(
  self : FecSession,
  now : Int32,
) -> Array[FixedArray[Byte]] {
  let wire : Array[FixedArray[Byte]] = []
  for frame in self.session.tick(now) {
    for out in self.tx.feed(frame) {
      wire.push(out)
    }
  }
  wire
}

///|
/// 应用收一消息(直通,FIFO)。
pub fn FecSession::poll_message(self : FecSession) -> FixedArray[Byte]? {
  self.session.poll_message()
}

///|
pub fn FecSession::is_dead(self : FecSession) -> Bool {
  self.session.is_dead()
}

///|
pub fn FecSession::last_active(self : FecSession) -> Int32 {
  self.session.last_active()
}

///|
/// KCP 观测快照(直通;FEC 侧读数走 fec_tx_stats / fec_rx_stats)。
pub fn FecSession::stats(self : FecSession) -> KcpStats {
  self.session.stats()
}

///|
pub fn FecSession::fec_tx_stats(self : FecSession) -> @fec.FecTxStats {
  self.tx.stats()
}

///|
pub fn FecSession::fec_rx_stats(self : FecSession) -> @fec.FecRxStats {
  self.rx.stats()
}