///|
fn workload(count : Int) -> Array[String] {
  let keys : Array[String] = []
  for index = 0; index < count; index = index + 1 {
    keys.push("workload-\{index}")
  }
  keys
}

///|
fn nodes(count : Int) -> Array[@shard.ShardNode] {
  let result : Array[@shard.ShardNode] = []
  for index = 0; index < count; index = index + 1 {
    result.push(
      @shard.ShardNode::new(
        "node-\{index}",
        zone="zone-\{index % 4}",
        rack="rack-\{index % 8}",
      ),
    )
  }
  result
}

///|
fn main {
  let before = nodes(8)
  let after = nodes(9)
  println("keys,moved,ratio,spread,waves,issues,evidence")
  for count in [1000, 10000, 100000] {
    let keys = workload(count)
    let report = @shard.analyze_distribution(keys, before, replicas=3)
    let plan = @shard.plan_migration(keys, before, after, replicas=3)
    let workflow = @shard.plan_safe_migration(
      keys,
      before,
      after,
      replicas=3,
      max_actions_per_wave=128,
      max_actions_per_node=16,
    )
    let evidence = @shard.stable_hash(
      "\{report.min_primary}|\{report.max_primary}|\{report.spread}|\{plan.moved_keys}",
    )
    println(
      "\{count},\{plan.moved_keys},\{@shard.movement_ratio(plan)},\{report.spread},\{workflow.waves.length()},\{@shard.validate_safe_migration(workflow).length()},\{evidence}",
    )
  }
}