// ===== 心跳编排(节点活性判定——moonkind D-7 家法形:TickPort 注入+三窗守恒)=====
// 职责:connected 节点的活性推演——对端心跳到达刷新 last_seen;poll 按三窗
// 出 verdict(Alive/Stale/Dead);Dead 接 mark_lost 四层闭环(nodedown 链)。
// 形裁:纯同步推演(时戳全由 TickPort 供——零真实 sleep/零 async——罐形
// 时长守恒=假时钟手推,单调不倒退,last_seen 域统一 Int64)。
// 真源对位:net_kernel 节点 tick/心跳(连接活性)——moonkind dist 役 D-7
// 失跳窗三律实证(心跳先行/watch 长驻/罐形时长守恒)。

///|
/// 时钟口(六边形注入——罐=Array 单元闭包假时钟:推进可见+多消费者共享
/// 同一单元即同步推进;生产=单调毫秒钟)
pub(open) trait TickPort {
  fn now_ms(self : Self) -> Int64
}

///|
/// 心跳策略(interval+容错倍数——判死窗=interval×tolerance)
pub(all) struct HeartbeatPolicy {
  interval_ms : Int64 // 心跳间隔(静置窗宽)
  tolerance : Int32 // 容错倍数(容错窗=interval×tolerance;≥1)
}

///|
pub fn HeartbeatPolicy::new(
  interval_ms~ : Int64 = 1000,
  tolerance~ : Int32 = 3,
) -> HeartbeatPolicy {
  { interval_ms, tolerance, }
}

///|
/// 活性判定三窗 verdict
pub(all) enum HeartVerdict {
  Alive // 静置窗:elapsed ≤ interval(含边界——心跳节拍内)
  Stale // 容错窗:interval < elapsed ≤ interval×tolerance(掉拍未判死——上层可探)
  Dead // 判死:elapsed > interval×tolerance(超 deadline——接 nodedown 链)
}

///|
/// 心跳看门(单节点账——Manager 组装面;last_seen 初值=构造时刻)
pub struct Heartbeat {
  policy : HeartbeatPolicy
  tick : &TickPort
  priv mut last_seen : Int64 // 最后活性时戳(ms 域;beat 刷新)
}

///|
pub fn Heartbeat::new(
  policy~ : HeartbeatPolicy = HeartbeatPolicy::new(),
  tick~ : &TickPort,
) -> Heartbeat {
  { policy, tick, last_seen: tick.now_ms(), }
}

///|
/// 对端心跳到达(活性刷新——last_seen=now;节拍守恒面)
pub fn Heartbeat::beat(self : Heartbeat) -> Unit {
  self.last_seen = self.tick.now_ms()
}

///|
/// 活性推演(纯读——三窗判定;elapsed=now-last_seen 单调差)
pub fn Heartbeat::poll(self : Heartbeat) -> HeartVerdict {
  let now = self.tick.now_ms()
  let elapsed = now - self.last_seen
  let deadline = self.policy.interval_ms * self.policy.tolerance.to_int64()
  if elapsed <= self.policy.interval_ms {
    Alive
  } else if elapsed <= deadline {
    Stale
  } else {
    Dead
  }
}

///|
/// 判死组装法(四层闭环接线:poll Dead→mark_lost 链——nodedown/决策/重连);
/// 返回 true=判死且重连成功回 Connected;false=未判死或重连耗尽。
/// 非 Dead 时零动作(静置/容错窗不惊链)。
pub async fn NodeManager::heartbeat_dead(
  self : NodeManager,
  hb : Heartbeat,
) -> Bool raise NodeError {
  match hb.poll() {
    Dead => self.mark_lost()
    _ => false
  }
}