///|
/// Benchmark: row-wise appender (`begin_row`/`append_*`/`end_row` per cell)
/// vs vectorized `Appender::append_chunk` bulk ingestion (issue #68).
///
/// Usage: `moon run src/cmd/appender_bench --target native --release --`
/// Prints wall-clock ms and rows/s for each path over the same row count.
fn main {
  let rows = 500_000
  @lib.connect(on_ready=fn(result) {
    match result {
      Ok(conn) =>
        conn.query(
          "CREATE TABLE bench_row (id INTEGER, val DOUBLE, tag VARCHAR)",
          on_done=fn(_) {
            conn.query(
              "CREATE TABLE bench_chunk (id INTEGER, val DOUBLE, tag VARCHAR)",
              on_done=fn(_) {
                bench_row_wise(conn, rows)
                bench_chunk_wise(conn, rows)
                conn.close(on_done=fn(_) { () })
              },
            )
          },
        )
      Err(err) => println("connect failed: \{err.message()}")
    }
  })
}

///|
fn fmt_rows_per_s(rows : Int32, elapsed : Double) -> String {
  if elapsed <= 0.0 {
    "inf"
  } else {
    "\{(rows.to_double() / (elapsed / 1000.0)).to_int()}"
  }
}

///|
fn bench_row_wise(conn : @lib.Connection, rows : Int32) -> Unit {
  let start = @bench.monotonic_clock_start()
  conn.create_appender("main", "bench_row", on_done=fn(result) {
    match result {
      Ok(app) => {
        let mut failed = false
        for i in 0..
              match app.append_int(i) {
                Ok(_) =>
                  match app.append_double(i.to_double() * 1.5) {
                    Ok(_) =>
                      match app.append_varchar("row_\{i}") {
                        Ok(_) =>
                          match app.end_row() {
                            Ok(_) => ()
                            Err(e) => {
                              println("end_row failed: \{e.message()}")
                              failed = true
                            }
                          }
                        Err(e) => {
                          println("append_varchar failed: \{e.message()}")
                          failed = true
                        }
                      }
                    Err(e) => {
                      println("append_double failed: \{e.message()}")
                      failed = true
                    }
                  }
                Err(e) => {
                  println("append_int failed: \{e.message()}")
                  failed = true
                }
              }
            Err(e) => {
              println("begin_row failed: \{e.message()}")
              failed = true
            }
          }
        }
        match app.flush() {
          Ok(_) => ()
          Err(e) => println("flush failed: \{e.message()}")
        }
      }
      Err(err) => println("create_appender failed: \{err.message()}")
    }
  })
  let elapsed = @bench.monotonic_clock_end(start) / 1000.0
  println(
    "row-wise appender: \{elapsed}ms, \{rows} rows, \{fmt_rows_per_s(rows, elapsed)} rows/s",
  )
}

///|
fn bench_chunk_wise(conn : @lib.Connection, rows : Int32) -> Unit {
  let chunk_rows = 2048
  // Prebuild the reusable chunk payloads once; the benchmark measures append,
  // not VectorData construction.
  let ids = FixedArray::make(chunk_rows, 0)
  let vals = FixedArray::make(chunk_rows, 0.0)
  let tags : Array[String] = Array::make(chunk_rows, "")
  for i in 0.. {
        let mut appended = 0
        let mut failed = false
        while appended < rows && !failed {
          match app.append_chunk(vector_chunk) {
            Ok(_) => appended = appended + chunk_rows
            Err(e) => {
              println("append_chunk failed: \{e.message()}")
              failed = true
            }
          }
        }
        match app.flush() {
          Ok(_) => ()
          Err(e) => println("flush failed: \{e.message()}")
        }
      }
      Err(err) => println("create_appender failed: \{err.message()}")
    }
  })
  let elapsed = @bench.monotonic_clock_end(start) / 1000.0
  println(
    "chunk appender (\{chunk_rows} rows/chunk): \{elapsed}ms, \{rows} rows, \{fmt_rows_per_s(rows, elapsed)} rows/s",
  )
}