// kcp.mbt — KCP ARQ 核心(K2;skywind3000/kcp ikcp.c 精确复刻;刀1 Bytes 化)
//
// 纯状态机:零 IO、零时钟——current 全注入,update 返回出帧,宿主投递。
// 数据面:send(应用消息按 mss 分片入 snd_queue) → update(区间到点则 flush) →
//        input(收报文:ACK 结算 / PUSH 入缓冲 / WASK·WINS 探窗) →
//        recv(应用读:碎片合并成整消息)。
// 队列四件套:snd_queue(应用已交未进窗)→ snd_buf(已发未确认)→
//            对端 rcv_buf(收到但非连续)→ rcv_queue(连续就绪待读)。
// 线面全 Bytes(K1 刀1):send 单片段零拷贝共享;帧组装 FixedArray 直写 +
// from_fixedarray;recv 单片段零拷贝直返。

///|
/// 无延迟档最小 RTO(ms)。
pub const RTO_NDL : Int32 = 30

///|
/// 常规档最小 RTO(ms)。
pub const RTO_MIN : Int32 = 100

///|
/// 初始 RTO(ms)。
pub const RTO_DEF : Int32 = 200

///|
/// RTO 上限(ms)。
pub const RTO_MAX : Int32 = 60000

///|
/// 探窗标志:需发 WASK(问对方窗口)。
pub const ASK_SEND : Int32 = 1

///|
/// 探窗标志:需发 WINS(报自己窗口)。
pub const ASK_TELL : Int32 = 2

///|
/// 默认发送窗口。
pub const WND_SND : Int32 = 32

///|
/// 默认接收窗口(必须 >= 最大分片数)。
pub const WND_RCV : Int32 = 128

///|
/// 默认 MTU(字节)。
pub const MTU_DEF : Int32 = 1400

///|
/// 默认 flush 间隔(ms)。
pub const INTERVAL_DEF : Int32 = 100

///|
/// 同段重发达此次数判链路死(state = -1)。
pub const DEADLINK : Int32 = 20

///|
/// 慢启动门限初值。
pub const THRESH_INIT : Int32 = 2

///|
/// 慢启动门限下限。
pub const THRESH_MIN : Int32 = 2

///|
/// 探窗间隔初值(ms)。
pub const PROBE_INIT : Int32 = 5000

///|
/// 探窗间隔上限(ms)。
pub const PROBE_LIMIT : Int32 = 120000

///|
/// 快速重传触发上限次数。
pub const FASTACK_LIMIT : Int32 = 5

///|
/// 32 位回绕有符号差:C `_itimediff(later, earlier) = (IINT32)(later - earlier)`
/// 直译。MoonBit Int 减法同为 32 位回绕,行为等价(测试钉住)。
fn itimediff(later : Int32, earlier : Int32) -> Int32 {
  later - earlier
}

///|
fn imax(a : Int32, b : Int32) -> Int32 {
  if a > b {
    a
  } else {
    b
  }
}

///|
fn imin(a : Int32, b : Int32) -> Int32 {
  if a < b {
    a
  } else {
    b
  }
}

///|
fn ibound(lower : Int32, middle : Int32, upper : Int32) -> Int32 {
  imin(imax(lower, middle), upper)
}

///|
/// KCP 状态机一实例(一条会话一实例;conv 双端一致)。
pub(all) struct Kcp {
  conv : Int32
  mut mtu : Int32
  mut mss : Int32
  mut snd_wnd : Int32
  mut rcv_wnd : Int32
  mut nodelay : Int32
  mut interval : Int32
  mut fastresend : Int32
  mut fastlimit : Int32
  mut nocwnd : Int32
  mut dead_link : Int32
  mut current : Int32
  mut updated : Int32
  mut ts_flush : Int32
  mut snd_una : Int32
  mut snd_nxt : Int32
  mut rcv_nxt : Int32
  mut ts_probe : Int32
  mut probe_wait : Int32
  mut probe : Int32
  mut rmt_wnd : Int32
  mut cwnd : Int32
  mut incr : Int32
  mut ssthresh : Int32
  mut rx_srtt : Int32
  mut rx_rttval : Int32
  mut rx_rto : Int32
  mut min_rto : Int32
  mut state : Int32
  mut xmit_total : Int32
  mut rcv_accepted : Int32
  mut last_active : Int32
  snd_queue : Array[KcpSegment]
  snd_buf : Array[KcpSegment]
  rcv_buf : Array[KcpSegment]
  rcv_queue : Array[KcpSegment]
  mut acklist : Array[(Int32, Int32)]
}

///|
/// 初始化:ikcp_create 默认值直译。
pub fn Kcp::create(conv : Int32) -> Kcp {
  {
    conv,
    mtu: MTU_DEF,
    mss: MTU_DEF - HEADER_SIZE,
    snd_wnd: WND_SND,
    rcv_wnd: WND_RCV,
    nodelay: 0,
    interval: INTERVAL_DEF,
    fastresend: 0,
    fastlimit: FASTACK_LIMIT,
    nocwnd: 0,
    dead_link: DEADLINK,
    current: 0,
    updated: 0,
    ts_flush: INTERVAL_DEF,
    snd_una: 0,
    snd_nxt: 0,
    rcv_nxt: 0,
    ts_probe: 0,
    probe_wait: 0,
    probe: 0,
    rmt_wnd: WND_RCV,
    cwnd: 0,
    incr: 0,
    ssthresh: THRESH_INIT,
    rx_srtt: 0,
    rx_rttval: 0,
    rx_rto: RTO_DEF,
    min_rto: RTO_MIN,
    state: 0,
    xmit_total: 0,
    rcv_accepted: 0,
    last_active: 0,
    snd_queue: [],
    snd_buf: [],
    rcv_buf: [],
    rcv_queue: [],
    acklist: [],
  }
}

///|
/// nodelay 配置(ikcp_nodelay 直译):nodelay 档位 / interval(ms) /
/// 快速重传触发(0 关)/ 是否关拥塞控制。传 -1 表示该项不动。
pub fn Kcp::set_nodelay(
  self : Kcp,
  nodelay : Int32,
  interval : Int32,
  resend : Int32,
  nc : Int32,
) -> Unit {
  if nodelay >= 0 {
    self.nodelay = nodelay
    if nodelay != 0 {
      self.min_rto = RTO_NDL
    } else {
      self.min_rto = RTO_MIN
    }
  }
  if interval >= 0 {
    let clamped = if interval < 10 {
      10
    } else if interval > 5000 {
      5000
    } else {
      interval
    }
    self.interval = clamped
  }
  if resend >= 0 {
    self.fastresend = resend
  }
  if nc >= 0 {
    self.nocwnd = nc
  }
}

///|
/// 窗口配置(ikcp_wndsize 直译):传 0 表示该项不动;rcv_wnd 有下限钳制
/// `imax(rcvwnd, WND_RCV)`(C 参照同式——收窗永不低于 128,差分门逮出的
/// 直译偏差,2026-10-25)。
pub fn Kcp::set_wnd(self : Kcp, sndwnd : Int32, rcvwnd : Int32) -> Unit {
  if sndwnd > 0 {
    self.snd_wnd = sndwnd
  }
  if rcvwnd > 0 {
    self.rcv_wnd = imax(rcvwnd, WND_RCV)
  }
}

///|
/// MTU 配置(ikcp_setmtu 直译;帧组装即席分配,无预留块)。
pub fn Kcp::set_mtu(self : Kcp, mtu : Int32) -> Int32 {
  if mtu < 50 || mtu < HEADER_SIZE {
    return -1
  }
  self.mtu = mtu
  self.mss = mtu - HEADER_SIZE
  0
}

///|
/// 待确认段总数(应用层流控参考)。
pub fn Kcp::waitsnd(self : Kcp) -> Int32 {
  self.snd_queue.length() + self.snd_buf.length()
}

///|
/// 接收窗口余量(对端通告用)。
fn Kcp::wnd_unused(self : Kcp) -> Int32 {
  if self.rcv_queue.length() < self.rcv_wnd {
    self.rcv_wnd - self.rcv_queue.length()
  } else {
    0
  }
}

///|
/// RTT 平滑(RFC 6298 同式;ikcp_update_ack 直译)。
fn Kcp::update_ack(self : Kcp, rtt : Int32) -> Unit {
  if self.rx_srtt == 0 {
    self.rx_srtt = rtt
    self.rx_rttval = rtt / 2
  } else {
    let mut delta = rtt - self.rx_srtt
    if delta < 0 {
      delta = -delta
    }
    self.rx_rttval = (3 * self.rx_rttval + delta) / 4
    self.rx_srtt = (7 * self.rx_srtt + rtt) / 8
    if self.rx_srtt < 1 {
      self.rx_srtt = 1
    }
  }
  let rto = self.rx_srtt + imax(self.interval, 4 * self.rx_rttval)
  self.rx_rto = ibound(self.min_rto, rto, RTO_MAX)
}

///|
/// snd_una 回缩:snd_buf 队首即新 una;空则追平 snd_nxt。
fn Kcp::shrink_buf(self : Kcp) -> Unit {
  if self.snd_buf.length() > 0 {
    self.snd_una = self.snd_buf[0].sn
  } else {
    self.snd_una = self.snd_nxt
  }
}

///|
/// una 结算:snd_buf 队首连续小于 una 的段全部确认移除。
fn Kcp::parse_una(self : Kcp, una : Int32) -> Unit {
  while self.snd_buf.length() > 0 && itimediff(una, self.snd_buf[0].sn) > 0 {
    let _ = self.snd_buf.remove(0)
  }
}

///|
/// 单 sn 确认:在 snd_buf 找到该 sn 移除(找不到静默)。
fn Kcp::parse_ack(self : Kcp, sn : Int32) -> Unit {
  if itimediff(sn, self.snd_una) < 0 || itimediff(sn, self.snd_nxt) >= 0 {
    return
  }
  let mut i = 0
  while i < self.snd_buf.length() {
    let seg = self.snd_buf[i]
    if sn == seg.sn {
      let _ = self.snd_buf.remove(i)
      break
    }
    if itimediff(sn, seg.sn) < 0 {
      break
    }
    i += 1
  }
}

///|
/// 快速重传记账(FASTACK_CONSERVE 变体,同本仓 C 参照):sn 之后
/// 且 ts 不早于本段 ts 的在途段 fastack 计数 +1。
fn Kcp::parse_fastack(self : Kcp, sn : Int32, ts : Int32) -> Unit {
  if itimediff(sn, self.snd_una) < 0 || itimediff(sn, self.snd_nxt) >= 0 {
    return
  }
  let mut i = 0
  while i < self.snd_buf.length() {
    let seg = self.snd_buf[i]
    if itimediff(sn, seg.sn) < 0 {
      break
    }
    if sn != seg.sn && itimediff(ts, seg.ts) >= 0 {
      seg.fastack += 1
    }
    i += 1
  }
}

///|
/// 记一笔待发 ACK(sn, 对端 ts)。
fn Kcp::ack_push(self : Kcp, sn : Int32, ts : Int32) -> Unit {
  self.acklist.push((sn, ts))
}

///|
/// 收到的 PUSH 段入 rcv_buf(去重 + 按 sn 升序插位),
/// 随后把连续前缀搬入 rcv_queue。
fn Kcp::parse_data(self : Kcp, newseg : KcpSegment) -> Unit {
  let sn = newseg.sn
  let too_far = itimediff(sn, self.rcv_nxt + self.rcv_wnd) >= 0
  let already_seen = itimediff(sn, self.rcv_nxt) < 0
  if too_far || already_seen {
    return
  }
  let mut insert_at = self.rcv_buf.length()
  let mut i = 0
  while i < self.rcv_buf.length() {
    let seg = self.rcv_buf[i]
    if seg.sn == sn {
      return
    }
    if itimediff(sn, seg.sn) < 0 {
      insert_at = i
      break
    }
    i += 1
  }
  self.rcv_buf.insert(insert_at, newseg)
  // 接收守恒账:PUSH 非重复入库即记账——
  // rcv_accepted == rcv_queue.length() + rcv_buf.length()(任意时刻可验)
  self.rcv_accepted += 1
  self.move_rcv_buf_to_queue()
}

///|
/// rcv_buf 连续前缀搬入 rcv_queue(rcv_nxt 推进)。
fn Kcp::move_rcv_buf_to_queue(self : Kcp) -> Unit {
  while self.rcv_buf.length() > 0 {
    let seg = self.rcv_buf[0]
    if seg.sn == self.rcv_nxt && self.rcv_queue.length() < self.rcv_wnd {
      let _ = self.rcv_buf.remove(0)
      self.rcv_queue.push(seg)
      self.rcv_nxt += 1
    } else {
      break
    }
  }
}

///|
/// 输入一报文(可含多段;ikcp_input 直译)。返回 0 / 负错码:
/// -1 长度或 conv 不符;-2 声明 len 超出;-3 非法 cmd。
pub fn Kcp::input(self : Kcp, datagram : FixedArray[Byte]) -> Int32 {
  let prev_una = self.snd_una
  let mut offset = 0
  let mut remaining = datagram.length()
  let mut flag = 0
  let mut maxack = 0
  let mut latest_ts = 0
  if remaining < HEADER_SIZE {
    return -1
  }
  while remaining >= HEADER_SIZE {
    let conv = read_u32(datagram, offset)
    if conv != self.conv {
      return -1
    }
    // 活性戳:合法对端报文即活跃(闲置回收判据;ms 注入面)
    self.last_active = self.current
    let cmd = datagram[offset + 4].to_int()
    let frg = datagram[offset + 5].to_int()
    let wnd = read_u16(datagram, offset + 6)
    let ts = read_u32(datagram, offset + 8)
    let sn = read_u32(datagram, offset + 12)
    let una = read_u32(datagram, offset + 16)
    let len = read_u32(datagram, offset + 20)
    offset += HEADER_SIZE
    remaining -= HEADER_SIZE
    if remaining < len {
      return -2
    }
    if cmd != CMD_PUSH && cmd != CMD_ACK && cmd != CMD_WASK && cmd != CMD_WINS {
      return -3
    }
    self.rmt_wnd = wnd
    self.parse_una(una)
    self.shrink_buf()
    if cmd == CMD_ACK {
      if itimediff(self.current, ts) >= 0 {
        self.update_ack(itimediff(self.current, ts))
      }
      self.parse_ack(sn)
      self.shrink_buf()
      if flag == 0 {
        flag = 1
        maxack = sn
        latest_ts = ts
      } else if itimediff(sn, maxack) > 0 && itimediff(ts, latest_ts) > 0 {
        maxack = sn
        latest_ts = ts
      }
    } else if cmd == CMD_PUSH {
      if itimediff(sn, self.rcv_nxt + self.rcv_wnd) < 0 {
        self.ack_push(sn, ts)
        if itimediff(sn, self.rcv_nxt) >= 0 {
          let data : FixedArray[Byte] = FixedArray::make(len, 0b0)
          if len > 0 {
            FixedArray::unsafe_blit(data, 0, datagram, offset, len)
          }
          let seg = KcpSegment::make(conv, cmd, frg, wnd, ts, sn, una, data)
          self.parse_data(seg)
        }
      }
    } else if cmd == CMD_WASK {
      self.probe = self.probe | ASK_TELL
    } else {
      // CMD_WINS:无需动作
    }
    offset += len
    remaining -= len
  }
  if flag != 0 {
    self.parse_fastack(maxack, latest_ts)
  }
  if itimediff(self.snd_una, prev_una) > 0 {
    let mss = self.mss
    if self.cwnd < self.rmt_wnd {
      if self.cwnd < self.ssthresh {
        self.cwnd += 1
        self.incr += mss
      } else {
        if self.incr < mss {
          self.incr = mss
        }
        self.incr += mss * mss / self.incr + mss / 16
        if (self.cwnd + 1) * mss <= self.incr {
          let safe_mss = if mss > 0 { mss } else { 1 }
          self.cwnd = (self.incr + mss - 1) / safe_mss
        }
      }
      if self.cwnd > self.rmt_wnd {
        self.cwnd = self.rmt_wnd
        self.incr = self.rmt_wnd * mss
      }
    }
  }
  0
}

///|
/// 应用下发一消息(按 mss 分片,frg 倒计;ikcp_send 消息模式直译)。
/// 返回字节数;超接收窗口分片数返回 -2。单片段零拷贝共享载荷。
pub fn Kcp::send(self : Kcp, payload : FixedArray[Byte]) -> Int32 {
  let length = payload.length()
  let mut count = if length <= self.mss {
    1
  } else {
    (length + self.mss - 1) / self.mss
  }
  if count >= WND_RCV {
    return -2
  }
  if count == 0 {
    count = 1
  }
  let mut offset = 0
  let mut remaining = length
  let mut i = 0
  while i < count {
    let size = if remaining > self.mss { self.mss } else { remaining }
    let data = if count == 1 {
      payload
    } else {
      let frag : FixedArray[Byte] = FixedArray::make(size, 0b0)
      FixedArray::unsafe_blit(frag, 0, payload, offset, size)
      frag
    }
    let seg = KcpSegment::make(
      self.conv,
      CMD_PUSH,
      count - i - 1,
      0,
      0,
      0,
      0,
      data,
    )
    self.snd_queue.push(seg)
    offset += size
    remaining -= size
    i += 1
  }
  length
}

///|
/// 下一条消息字节数(碎片合并视角;ikcp_peeksize 直译)。
/// 队列空或碎片未齐返回 -1。
pub fn Kcp::peeksize(self : Kcp) -> Int32 {
  if self.rcv_queue.length() == 0 {
    return -1
  }
  let first = self.rcv_queue[0]
  if first.frg == 0 {
    return first.len
  }
  if self.rcv_queue.length() < first.frg + 1 {
    return -1
  }
  let mut length = 0
  let mut go = true
  let mut i = 0
  while i < self.rcv_queue.length() && go {
    let seg = self.rcv_queue[i]
    length += seg.len
    if seg.frg == 0 {
      go = false
    }
    i += 1
  }
  length
}

///|
/// 应用读一整消息(碎片合并);队列空或碎片未齐返回 None。
/// C ikcp_recv 序:先 peeksize 完整性判(负值拒读),后合并。
/// 单片段零拷贝直返;多片段 FixedArray 直写合并。
pub fn Kcp::recv(self : Kcp) -> FixedArray[Byte]? {
  if self.rcv_queue.length() == 0 {
    return None
  }
  if self.peeksize() < 0 {
    return None
  }
  let recover = self.rcv_queue.length() >= self.rcv_wnd
  let first = self.rcv_queue[0]
  let out = if first.frg == 0 {
    let _ = self.rcv_queue.remove(0)
    first.data
  } else {
    let total = self.peeksize()
    let fa : FixedArray[Byte] = FixedArray::make(total, 0b0)
    let mut off = 0
    let mut fragment = 1
    while self.rcv_queue.length() > 0 && fragment != 0 {
      let seg = self.rcv_queue.remove(0)
      let dl = seg.data.length()
      if dl > 0 {
        FixedArray::unsafe_blit(fa, off, seg.data, 0, dl)
      }
      off += dl
      fragment = seg.frg
    }
    fa
  }
  self.move_rcv_buf_to_queue()
  if recover && self.rcv_queue.length() < self.rcv_wnd {
    self.probe = self.probe | ASK_TELL
  }
  Some(out)
}

///|
/// 写 little-endian u16 到帧缓冲。
fn write_le_u16(fa : FixedArray[Byte], offset : Int32, value : Int32) -> Unit {
  fa[offset] = (value & 0xFF).to_byte()
  fa[offset + 1] = ((value >> 8) & 0xFF).to_byte()
}

///|
/// 写 little-endian u32 到帧缓冲。
fn write_le_u32(fa : FixedArray[Byte], offset : Int32, value : Int32) -> Unit {
  fa[offset] = (value & 0xFF).to_byte()
  fa[offset + 1] = ((value >> 8) & 0xFF).to_byte()
  fa[offset + 2] = ((value >> 16) & 0xFF).to_byte()
  fa[offset + 3] = ((value >> 24) & 0xFF).to_byte()
}

///|
/// 帧滚切:当前帧再加 need 字节将超 mtu 时,整帧成形收编、开新帧。
/// pending = 当前帧已攒的段引用;size_box = 当前帧字节数单格。
fn frame_roll(
  pending : Array[KcpSegment],
  size_box : Array[Int32],
  frames : Array[FixedArray[Byte]],
  mtu : Int32,
  need : Int32,
) -> Unit {
  if size_box[0] + need > mtu {
    frames.push(materialize_frame(pending, size_box[0]))
    let mut k = pending.length() - 1
    while k >= 0 {
      let _ = pending.remove(k)
      k -= 1
    }
    size_box[0] = 0
  }
}

///|
/// 帧成形:段引用序列 → 一条 Bytes(FixedArray 直写 + from_fixedarray)。
fn materialize_frame(
  pending : Array[KcpSegment],
  total : Int32,
) -> FixedArray[Byte] {
  let fa : FixedArray[Byte] = FixedArray::make(total, 0b0)
  let mut off = 0
  let mut i = 0
  while i < pending.length() {
    let seg = pending[i]
    write_le_u32(fa, off, seg.conv)
    fa[off + 4] = seg.cmd.to_byte()
    fa[off + 5] = seg.frg.to_byte()
    write_le_u16(fa, off + 6, seg.wnd)
    write_le_u32(fa, off + 8, seg.ts)
    write_le_u32(fa, off + 12, seg.sn)
    write_le_u32(fa, off + 16, seg.una)
    let data_len = seg.data.length()
    write_le_u32(fa, off + 20, data_len)
    if data_len > 0 {
      FixedArray::unsafe_blit(fa, off + 24, seg.data, 0, data_len)
    }
    off += 24 + data_len
    i += 1
  }
  fa
}

///|
/// flush(ikcp_flush 直译):ACK 先行 → 探窗 → snd_queue 进窗 →
/// 数据段首发/超时重发/快速重发 → 拥塞窗结算。返回出帧列表。
pub fn Kcp::flush_frames(self : Kcp) -> Array[FixedArray[Byte]] {
  let frames : Array[FixedArray[Byte]] = []
  if self.updated == 0 {
    return frames
  }
  let current = self.current
  let prior_cwnd = self.cwnd
  let pending : Array[KcpSegment] = []
  let size_box : Array[Int32] = [0]
  let seg_wnd = self.wnd_unused()
  // ACK 先行(末笔 ack sn/ts 记下——C flush 复用模板段,探窗帧携带
  // 上一条 ACK 的 sn/ts 残留;精确复刻同形,差分免屏蔽)
  let mut i = 0
  let mut last_ack_sn = 0
  let mut last_ack_ts = 0
  while i < self.acklist.length() {
    let (ack_sn, ack_ts) = self.acklist[i]
    last_ack_sn = ack_sn
    last_ack_ts = ack_ts
    frame_roll(pending, size_box, frames, self.mtu, HEADER_SIZE)
    let ack_seg = KcpSegment::make(
      self.conv,
      CMD_ACK,
      0,
      seg_wnd,
      ack_ts,
      ack_sn,
      self.rcv_nxt,
      FixedArray::make(0, 0b0),
    )
    pending.push(ack_seg)
    size_box[0] += HEADER_SIZE
    i += 1
  }
  self.acklist = []
  // 探窗调度(rmt_wnd == 0 时指数退避排班)
  if self.rmt_wnd == 0 {
    if self.probe_wait == 0 {
      self.probe_wait = PROBE_INIT
      self.ts_probe = current + self.probe_wait
    } else if itimediff(current, self.ts_probe) >= 0 {
      if self.probe_wait < PROBE_INIT {
        self.probe_wait = PROBE_INIT
      }
      self.probe_wait += self.probe_wait / 2
      if self.probe_wait > PROBE_LIMIT {
        self.probe_wait = PROBE_LIMIT
      }
      self.ts_probe = current + self.probe_wait
      self.probe = self.probe | ASK_SEND
    }
  } else {
    self.ts_probe = 0
    self.probe_wait = 0
  }
  // 探窗命令(带末笔 ACK 残留 sn/ts,同 C 模板段语义)
  if (self.probe & ASK_SEND) != 0 {
    frame_roll(pending, size_box, frames, self.mtu, HEADER_SIZE)
    let wask = KcpSegment::make(
      self.conv,
      CMD_WASK,
      0,
      seg_wnd,
      last_ack_ts,
      last_ack_sn,
      self.rcv_nxt,
      FixedArray::make(0, 0b0),
    )
    pending.push(wask)
    size_box[0] += HEADER_SIZE
  }
  if (self.probe & ASK_TELL) != 0 {
    frame_roll(pending, size_box, frames, self.mtu, HEADER_SIZE)
    let wins = KcpSegment::make(
      self.conv,
      CMD_WINS,
      0,
      seg_wnd,
      last_ack_ts,
      last_ack_sn,
      self.rcv_nxt,
      FixedArray::make(0, 0b0),
    )
    pending.push(wins)
    size_box[0] += HEADER_SIZE
  }
  self.probe = 0
  // 生效窗口
  let mut cwnd = imin(self.snd_wnd, self.rmt_wnd)
  if self.nocwnd == 0 {
    cwnd = imin(cwnd, self.cwnd)
  }
  // snd_queue 进窗(sn 现场分配)
  while self.snd_queue.length() > 0 {
    if itimediff(self.snd_nxt, self.snd_una + cwnd) >= 0 {
      break
    }
    let newseg = self.snd_queue.remove(0)
    newseg.conv = self.conv
    newseg.cmd = CMD_PUSH
    newseg.wnd = seg_wnd
    newseg.ts = current
    newseg.sn = self.snd_nxt
    self.snd_nxt += 1
    newseg.una = self.rcv_nxt
    newseg.resendts = current
    newseg.rto = self.rx_rto
    newseg.fastack = 0
    newseg.xmit = 0
    self.snd_buf.push(newseg)
  }
  // 重发参数
  let resent = if self.fastresend > 0 { self.fastresend } else { 0x7FFFFFFF }
  let rtomin = if self.nodelay == 0 { self.rx_rto >> 3 } else { 0 }
  // 数据段:首发 / RTO 超时重发 / fastack 快速重发
  let mut change = 0
  let mut lost = false
  let mut p = 0
  while p < self.snd_buf.length() {
    let segment = self.snd_buf[p]
    let mut needsend = false
    if segment.xmit == 0 {
      needsend = true
      segment.xmit += 1
      segment.rto = self.rx_rto
      segment.resendts = current + segment.rto + rtomin
    } else if itimediff(current, segment.resendts) >= 0 {
      needsend = true
      segment.xmit += 1
      self.xmit_total += 1
      if self.nodelay == 0 {
        segment.rto += imax(segment.rto, self.rx_rto)
      } else {
        let step = if self.nodelay < 2 { segment.rto } else { self.rx_rto }
        segment.rto += step / 2
      }
      segment.resendts = current + segment.rto
      lost = true
    } else if segment.fastack >= resent {
      if segment.xmit <= self.fastlimit || self.fastlimit <= 0 {
        needsend = true
        segment.xmit += 1
        segment.fastack = 0
        segment.resendts = current + segment.rto
        change += 1
      }
    }
    if needsend {
      segment.ts = current
      segment.wnd = seg_wnd
      segment.una = self.rcv_nxt
      frame_roll(pending, size_box, frames, self.mtu, HEADER_SIZE + segment.len)
      pending.push(segment)
      size_box[0] += HEADER_SIZE + segment.len
      if segment.xmit >= self.dead_link {
        self.state = -1
      }
    }
    p += 1
  }
  // 尾帧收编
  if size_box[0] > 0 {
    frames.push(materialize_frame(pending, size_box[0]))
  }
  // 拥塞窗结算:快速重传 → ssthresh 折半 + cwnd 跳到门限+resent
  if change > 0 {
    let inflight = self.snd_nxt - self.snd_una
    self.ssthresh = inflight / 2
    if self.ssthresh < THRESH_MIN {
      self.ssthresh = THRESH_MIN
    }
    self.cwnd = self.ssthresh + resent
    self.incr = self.cwnd * self.mss
  }
  if lost {
    self.ssthresh = prior_cwnd / 2
    if self.ssthresh < THRESH_MIN {
      self.ssthresh = THRESH_MIN
    }
    self.cwnd = 1
    self.incr = self.mss
  }
  if self.cwnd < 1 {
    self.cwnd = 1
    self.incr = self.mss
  }
  frames
}

///|
/// 时间推进(ikcp_update 直译,纯形):到 interval 点则 flush,
/// 返回本次出帧(未到点返回空表)。
pub fn Kcp::update(self : Kcp, current : Int32) -> Array[FixedArray[Byte]] {
  self.current = current
  if self.updated == 0 {
    self.updated = 1
    self.ts_flush = self.current
  }
  let mut slap = itimediff(self.current, self.ts_flush)
  if slap >= 10000 || slap < -10000 {
    self.ts_flush = self.current
    slap = 0
  }
  if slap >= 0 {
    self.ts_flush += self.interval
    if itimediff(self.current, self.ts_flush) >= 0 {
      self.ts_flush = self.current + self.interval
    }
    self.flush_frames()
  } else {
    []
  }
}

///|
/// 观测快照(只读;运维/调试面)。rto_retransmits = C kcp->xmit
/// (超时重传累计;快速重传不计,同参照)。
pub(all) struct KcpStats {
  srtt : Int32
  rttval : Int32
  rto : Int32
  cwnd : Int32
  snd_wnd : Int32
  rmt_wnd : Int32
  in_flight : Int32
  queued : Int32
  rto_retransmits : Int32
  rcv_accepted : Int32
  rcv_queue_len : Int32
  rcv_buf_len : Int32
  last_active : Int32
}

///|
pub fn Kcp::stats(self : Kcp) -> KcpStats {
  {
    srtt: self.rx_srtt,
    rttval: self.rx_rttval,
    rto: self.rx_rto,
    cwnd: self.cwnd,
    snd_wnd: self.snd_wnd,
    rmt_wnd: self.rmt_wnd,
    in_flight: self.snd_buf.length(),
    queued: self.snd_queue.length(),
    rto_retransmits: self.xmit_total,
    rcv_accepted: self.rcv_accepted,
    rcv_queue_len: self.rcv_queue.length(),
    rcv_buf_len: self.rcv_buf.length(),
    last_active: self.last_active,
  }
}

///|
/// 下次该调 update 的时刻(ikcp_check 直译)——省空转用。
pub fn Kcp::check(self : Kcp, current : Int32) -> Int32 {
  if self.updated == 0 {
    return current
  }
  let mut ts_flush = self.ts_flush
  if itimediff(current, ts_flush) >= 10000 ||
    itimediff(current, ts_flush) < -10000 {
    ts_flush = current
  }
  if itimediff(current, ts_flush) >= 0 {
    return current
  }
  let tm_flush = itimediff(ts_flush, current)
  let mut tm_packet = 0x7FFFFFFF
  let mut i = 0
  while i < self.snd_buf.length() {
    let diff = itimediff(self.snd_buf[i].resendts, current)
    if diff <= 0 {
      return current
    }
    if diff < tm_packet {
      tm_packet = diff
    }
    i += 1
  }
  let mut minimal = if tm_packet < tm_flush { tm_packet } else { tm_flush }
  if minimal >= self.interval {
    minimal = self.interval
  }
  current + minimal
}