///|
struct MoonlightClusterConfig {
  manager : Manager
  worker_list : Array[Worker]
}

///|
pub fn local_cluster_config(worker_num : Int) -> MoonlightClusterConfig {
  {
    manager: Manager::new(),
    worker_list: Array::makei(worker_num, fn(i) {
      Worker::new("MoonlightWorker_\{i}")
    }),
  }
}

///|
fn MoonlightClusterConfig::into_locations(
  self : MoonlightClusterConfig,
) -> Array[&@moonchor.Location] {
  let locations : Array[&@moonchor.Location] = []
  locations.push(self.manager)
  for worker in self.worker_list {
    locations.push(worker)
  }
  locations
}

///|
fn make_choreo(
  f : async (MoonlightContext) -> Unit,
  config : MoonlightClusterConfig,
) -> @moonchor.Choreo[Unit] {
  async fn(ctx) {
    let mctx = MoonlightContext::new(ctx, config)
    f(mctx)
  }
}

///|
pub async fn MoonlightClusterConfig::start(
  self : MoonlightClusterConfig,
  f : async (MoonlightContext) -> Unit,
) -> Unit {
  @async.with_task_group(fn(group) {
    let backend = @moonchor.make_local_backend(self.into_locations(), group)
    let choreo = make_choreo(f, self)
    group.spawn_bg(async fn() {
      @moonchor.run_choreo(backend, choreo, self.manager)
    })
    for worker in self.worker_list {
      group.spawn_bg(async fn() {
        @moonchor.run_choreo(backend, choreo, worker)
      })
    }
  })
}

///|
async test "Local cluster start" {
  let cluster = local_cluster_config(4)
  cluster.start(fn(_mctx) { println("Hello, Moonlight!") })
}