/// engine/engine_assistant.mbt —— 项目助理登记(multi-agent-lock v3 阶段2 精简版)
///
/// 纯转发到后端 StoreBackend 的 assistant_*,供 server 工具统一走引擎,避免跨层直接摸 store。

///|
pub fn FistEngine::assistant_upsert(
  self : FistEngine,
  reg : @store.AssistantReg,
) -> Unit {
  self.store.assistant_upsert(reg)
}

///|
pub fn FistEngine::assistant_get(
  self : FistEngine,
  agent : String,
) -> @store.AssistantReg? {
  self.store.assistant_get(agent)
}

///|
pub fn FistEngine::assistant_list(
  self : FistEngine,
) -> Array[@store.AssistantReg] {
  self.store.assistant_list()
}

///|
pub fn FistEngine::assistant_set_status(
  self : FistEngine,
  agent : String,
  status : String,
) -> Bool {
  self.store.assistant_set_status(agent, status)
}

///|
/// 找现任 active 主助理(is_primary 且 status=active,取 registered_at 最新)。
pub fn FistEngine::assistant_active_primary(
  self : FistEngine,
) -> @store.AssistantReg? {
  let mut best : @store.AssistantReg? = None
  for r in self.store.assistant_list() {
    if r.is_primary && r.status == "active" {
      match best {
        None => best = Some(r)
        Some(b) if r.registered_at > b.registered_at => best = Some(r)
        _ => ()
      }
    }
  }
  best
}

///|
/// 最近登记的**曾任**主助理(不要求 `status == "active"`)—— BUG-431。
///
/// 为什么必须与 `assistant_active_primary` 分开:
/// `assistant_sweep` 会把心跳陈旧的主助理标 `dead`,而 `active_primary` **只认 active**
/// ⇒ sweep 跑过之后 `claim` 看到 `prev = None` ⇒ `assistant_claim_action` 判 **`elected`**
/// 且 `prev_agent = ""` ⇒ `server.mbt` 的留痕分支(只在 `taken_over` 时记)**不记违例**。
/// ⇒ **同一个业务事件**(B 心跳陈旧、A 接管)会因「sweep 是否恰好先跑过」
/// 产出两种不同的账本结果(一种有 `force_takeover` 案底、一种没有)。
///
/// 语义边界(刻意的):
/// - **`dead` 参与** —— 它正是「曾持有、已陈旧」的那一档,接管要认它
/// - **`resigned` 排除** —— 主动退位后应重新选举(旧语义),不算被接管
/// - 排序键与 `active_primary` 一致(`registered_at` 最新),只放宽 status 过滤
pub fn FistEngine::assistant_last_primary(
  self : FistEngine,
) -> @store.AssistantReg? {
  let mut best : @store.AssistantReg? = None
  for r in self.store.assistant_list() {
    if r.is_primary && r.status != "resigned" {
      match best {
        None => best = Some(r)
        Some(b) if r.registered_at > b.registered_at => best = Some(r)
        _ => ()
      }
    }
  }
  best
}

///|
/// 记一条锁违例(助理接管等治理动作落案底)。
pub fn FistEngine::lock_violations_record(
  self : FistEngine,
  ts~ : String,
  agent~ : String,
  scope~ : String,
  reason~ : String,
  lock_id~ : String,
) -> Unit {
  self.store.lock_violations_push(
    @store.LockViolation::new(ts~, agent~, scope~, reason~, lock_id~),
  )
}