// ===== 节点账本(blueprint: moonactor/erl_dist dist_account.mbt 移植;门 C 真件)=====
// 职责:monitor 账(我方 watcher 侧登记页)/被监视者了断通道/连接丢失事件源。
// 节点层裁形(解协议依赖——协议词住 beam-dist,本件零 ETF/DOP 词外泄):
//   ref : EtfTerm → RefKey(不透明配对句柄——beam-dist 解码 ERef 后三元上抛);
//   watched : EtfTerm → String(节点层账语义=具名进程/pid 文本句柄——真件
//   A4 门 C 形=具名 atom 监视);AccountHooks/DopMsg(L3 接线口)裁掉——账面
//   方法直给(beam-dist 分派后调,节点层不接分派器)。
// 真源对位:net_kernel monitor_nodes/节点监视语义;on_conn_lost=本地判定
// (net_kernel.erl up_nodedown:controller-exit→delete_connection——不依赖
// 对端 EXIT 帧,对端死时发不出)。

///|
/// monitor 配对句柄(不透明键——demonitor/exit 按 ref 配对摘账;
/// 结构化三元=ERef(node 名序号/序号/creation)解码形,相等比较即配对)
pub(all) struct RefKey {
  a : Int64
  b : Int64
  c : Int64
}

///|
pub fn RefKey::new(a~ : Int64, b~ : Int64 = 0, c~ : Int64 = 0) -> RefKey {
  { a, b, c, }
}

///|
fn RefKey::same(self : RefKey, other : RefKey) -> Bool {
  self.a == other.a && self.b == other.b && self.c == other.c
}

///|
/// monitor 账页(我方 = watcher 侧登记)
pub(all) struct MonEntry {
  key : RefKey // 会话引用(demonitor/exit 配对键;ref 是保留字——避名家法)
  watched : String // 被监视者(具名进程/pid 文本句柄)
}

///|
/// 节点事件订阅面(门 C 第三监督者接线口——net_kernel:monitor_nodes 对应形;
/// 连接 FIN/读错→on_conn_lost→订阅者收 nodedown——本地判定语义)
pub(open) trait NodeEvents {
  fn on_nodedown(self : Self, node : String) -> Unit
}

///|
/// 节点账本(单连接单账——多节点多账由 NodeRegistry 组装)
pub struct NodeAccount {
  priv mut mons : Array[MonEntry]
  priv mut exit_n : Int32 // 被监视者了断计数
  priv mut lost_n : Int32 // 连接丢失计数(nodedown 事件面)
  node : String // 本账所属对端节点名
}

///|
pub fn NodeAccount::new(node~ : String = "") -> NodeAccount {
  { mons: [], exit_n: 0, lost_n: 0, node, }
}

///|
/// monitor 账登记页数(直读)
pub fn NodeAccount::monitor_count(self : NodeAccount) -> Int32 {
  self.mons.length()
}

///|
/// 被监视者了断计数(直读)
pub fn NodeAccount::exit_count(self : NodeAccount) -> Int32 {
  self.exit_n
}

///|
/// monitor 登记(watcher 侧;beam-dist 分派 {19,watcher,watched,ref} 后调)
pub fn NodeAccount::register(
  self : NodeAccount,
  key~ : RefKey,
  watched~ : String,
) -> Unit {
  let _ = self.mons.push({ key, watched, })
}

///|
/// monitor 摘账(按 ref 配对;beam-dist 分派 {20,…,ref} 后调)
pub fn NodeAccount::demonitor(self : NodeAccount, key~ : RefKey) -> Unit {
  self.mons = self.keep_others(key)
}

///|
/// 被监视者了断(按 ref 清账+事件计数;beam-dist 分派 {21,…,reason} 后调)
pub fn NodeAccount::monitored_exit(self : NodeAccount, key~ : RefKey) -> Unit {
  self.mons = self.keep_others(key)
  self.exit_n = self.exit_n + 1
}

///|
/// 摘除辅助:保留 ref 不匹配的页(配对摘除——闭域唯一性)
fn NodeAccount::keep_others(
  self : NodeAccount,
  key : RefKey,
) -> Array[MonEntry] {
  let keep : Array[MonEntry] = []
  for e in self.mons {
    if !e.key.same(key) {
      let _ = keep.push(e)
    }
  }
  keep
}

///|
/// 连接丢失(门 C 事件源):TCP FIN/读错→清账+lost 计数+订阅者回调——
/// 本地判定(不依赖对端 EXIT 帧——对端死时发不出);Erlang 语义:
/// monitor 的该节点所有 watch 同时了断(reason=noconnection)
pub fn NodeAccount::on_conn_lost(
  self : NodeAccount,
  events : &NodeEvents,
) -> Unit {
  self.mons = []
  self.exit_n = 0
  self.lost_n = self.lost_n + 1
  events.on_nodedown(self.node)
}

///|
/// 连接丢失计数(罐测断言用)
pub fn NodeAccount::lost_count(self : NodeAccount) -> Int32 {
  self.lost_n
}