// ============================================================
// Scheduler: Multi-Tree Concurrent Behavior Tree Scheduler
//
// The Scheduler manages a list of named behavior tree roots
// and ticks them in priority order each frame. This allows
// multiple independent AI agents (NPCs) to share a single
// tick loop while maintaining isolated Blackboard contexts.
//
// Features:
//   - Add/remove named trees at runtime
//   - Priority-ordered tick (lower index = higher priority)
//   - Per-tree Blackboard isolation
//   - Pause / resume individual trees
//   - Collect per-tree tick results
// ============================================================

///|
/// Entry wraps a behavior tree with its dedicated blackboard and runtime state.
pub struct SchedulerEntry {
  name : String
  root : Node
  bb : Blackboard
  paused : Ref[Bool]
}

///|
/// SchedulerEntry::new creates an entry for the given tree root.
pub fn SchedulerEntry::new(
  name : String,
  root : Node,
  bb : Blackboard,
) -> SchedulerEntry {
  { name, root, bb, paused: Ref::new(false) }
}

///|
/// TickResult records the outcome of a single tree tick in the scheduler.
pub struct TickResult {
  name : String
  status : Status
}

///|
/// Scheduler drives multiple named behavior trees in priority order.
pub struct Scheduler {
  entries : Array[SchedulerEntry]
}

///|
/// Create a new empty Scheduler.
pub fn Scheduler::new() -> Scheduler {
  { entries: [] }
}

///|
/// Add a behavior tree to the scheduler.
/// Trees are ticked in the order they are added.
pub fn Scheduler::add(self : Scheduler, entry : SchedulerEntry) -> Unit {
  self.entries.push(entry)
}

///|
/// Remove a behavior tree by name.
pub fn Scheduler::remove(self : Scheduler, name : String) -> Unit {
  let mut i = 0
  while i < self.entries.length() {
    if self.entries[i].name == name {
      let _ = self.entries.remove(i)
      break
    }
    i = i + 1
  }
}

///|
/// Pause a named tree so it is skipped during tick.
pub fn Scheduler::pause(self : Scheduler, name : String) -> Unit {
  for entry in self.entries {
    if entry.name == name {
      entry.paused.set(true)
      break
    }
  }
}

///|
/// Resume a paused tree.
pub fn Scheduler::restart(self : Scheduler, name : String) -> Unit {
  for entry in self.entries {
    if entry.name == name {
      entry.paused.set(false)
      break
    }
  }
}

///|
/// Reset all trees managed by this scheduler.
pub fn Scheduler::reset_all(self : Scheduler) -> Unit {
  for entry in self.entries {
    entry.root.reset()
  }
}

///|
/// Tick all non-paused trees once and return per-tree results.
pub fn Scheduler::tick(self : Scheduler) -> Array[TickResult] {
  let results : Array[TickResult] = []
  for entry in self.entries {
    if !entry.paused.get() {
      let status = entry.root.tick(entry.bb)
      results.push({ name: entry.name, status })
    }
  }
  results
}

///|
/// Returns the number of entries registered in the scheduler.
pub fn Scheduler::size(self : Scheduler) -> Int {
  self.entries.length()
}

///|
/// Returns true if a tree with the given name exists in the scheduler.
pub fn Scheduler::has(self : Scheduler, name : String) -> Bool {
  let found = Ref::new(false)
  for entry in self.entries {
    if entry.name == name {
      found.set(true)
    }
  }
  found.get()
}