// MoonBit SQLite Benchmark
// Run with: moon bench --target native

///|
fn setup_database() -> Database {
  let db = Database::open(":memory:").unwrap()
  db.exec(
    "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL, age INTEGER NOT NULL)",
  )
  |> ignore
  db
}

///|
/// Database Open/Close
test "bench: Database Open/Close" (b : @bench.T) {
  b.bench(fn() {
    let db = Database::open(":memory:").unwrap()
    db.close()
  })
}

///|
/// Create Table
test "bench: Create Table" (b : @bench.T) {
  b.bench(fn() {
    let db = Database::open(":memory:").unwrap()
    db.exec(
      "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL, age INTEGER NOT NULL)",
    )
    |> ignore
    db.close()
  })
}

///|
/// Insert Single Row
test "bench: Insert Single Row" (b : @bench.T) {
  b.bench(fn() {
    let db = setup_database()
    let stmt = db
      .prepare("INSERT INTO users (name, age) VALUES (?, ?)")
      .unwrap()
    stmt.bind(1, Text(cstring("Alice"))) |> ignore
    stmt.bind(2, Int(30)) |> ignore
    stmt.execute() |> ignore
    stmt.finalize()
    db.close()
  })
}

///|
/// Insert 100 Rows
test "bench: Insert 100 Rows" (b : @bench.T) {
  b.bench(fn() {
    let db = setup_database()
    let stmt = db
      .prepare("INSERT INTO users (name, age) VALUES (?, ?)")
      .unwrap()
    for i = 0; i < 100; i = i + 1 {
      stmt.bind(1, Text(cstring("User\{i}"))) |> ignore
      stmt.bind(2, Int(20 + i % 50)) |> ignore
      stmt.execute() |> ignore
      stmt.reset()
    }
    stmt.finalize()
    db.close()
  })
}

///|
/// Insert with Transaction (100 rows)
test "bench: Insert with Transaction (100 rows)" (b : @bench.T) {
  b.bench(fn() {
    let db = setup_database()
    db.begin() |> ignore
    let stmt = db
      .prepare("INSERT INTO users (name, age) VALUES (?, ?)")
      .unwrap()
    for i = 0; i < 100; i = i + 1 {
      stmt.bind(1, Text(cstring("User\{i}"))) |> ignore
      stmt.bind(2, Int(20 + i % 50)) |> ignore
      stmt.execute() |> ignore
      stmt.reset()
    }
    stmt.finalize()
    db.commit() |> ignore
    db.close()
  })
}

///|
/// Select All Rows
test "bench: Select All Rows" (b : @bench.T) {
  b.bench(fn() {
    let db = setup_database()
    // Insert test data
    let insert_stmt = db
      .prepare("INSERT INTO users (name, age) VALUES (?, ?)")
      .unwrap()
    for i = 0; i < 100; i = i + 1 {
      insert_stmt.bind(1, Text(cstring("User\{i}"))) |> ignore
      insert_stmt.bind(2, Int(20 + i % 50)) |> ignore
      insert_stmt.execute() |> ignore
      insert_stmt.reset()
    }
    insert_stmt.finalize()
    // Select all
    let select_stmt = db.prepare("SELECT * FROM users").unwrap()
    while select_stmt.step() {
      select_stmt.column_int(0) |> ignore
      select_stmt.column_text(1) |> ignore
      select_stmt.column_int(2) |> ignore
    }
    select_stmt.finalize()
    db.close()
  })
}

///|
/// Select with WHERE clause
test "bench: Select with WHERE clause" (b : @bench.T) {
  b.bench(fn() {
    let db = setup_database()
    // Insert test data
    let insert_stmt = db
      .prepare("INSERT INTO users (name, age) VALUES (?, ?)")
      .unwrap()
    for i = 0; i < 100; i = i + 1 {
      insert_stmt.bind(1, Text(cstring("User\{i}"))) |> ignore
      insert_stmt.bind(2, Int(20 + i % 50)) |> ignore
      insert_stmt.execute() |> ignore
      insert_stmt.reset()
    }
    insert_stmt.finalize()
    // Select with WHERE
    let select_stmt = db.prepare("SELECT * FROM users WHERE age > ?").unwrap()
    select_stmt.bind(1, Int(30)) |> ignore
    while select_stmt.step() {
      select_stmt.column_int(0) |> ignore
      select_stmt.column_text(1) |> ignore
      select_stmt.column_int(2) |> ignore
    }
    select_stmt.finalize()
    db.close()
  })
}

///|
/// Update Rows
test "bench: Update Rows" (b : @bench.T) {
  b.bench(fn() {
    let db = setup_database()
    // Insert test data
    let insert_stmt = db
      .prepare("INSERT INTO users (name, age) VALUES (?, ?)")
      .unwrap()
    for i = 0; i < 100; i = i + 1 {
      insert_stmt.bind(1, Text(cstring("User\{i}"))) |> ignore
      insert_stmt.bind(2, Int(20 + i % 50)) |> ignore
      insert_stmt.execute() |> ignore
      insert_stmt.reset()
    }
    insert_stmt.finalize()
    // Update
    let update_stmt = db
      .prepare("UPDATE users SET age = ? WHERE age > ?")
      .unwrap()
    update_stmt.bind(1, Int(25)) |> ignore
    update_stmt.bind(2, Int(30)) |> ignore
    update_stmt.execute() |> ignore
    update_stmt.finalize()
    db.close()
  })
}

///|
/// Delete Rows
test "bench: Delete Rows" (b : @bench.T) {
  b.bench(fn() {
    let db = setup_database()
    // Insert test data
    let insert_stmt = db
      .prepare("INSERT INTO users (name, age) VALUES (?, ?)")
      .unwrap()
    for i = 0; i < 100; i = i + 1 {
      insert_stmt.bind(1, Text(cstring("User\{i}"))) |> ignore
      insert_stmt.bind(2, Int(20 + i % 50)) |> ignore
      insert_stmt.execute() |> ignore
      insert_stmt.reset()
    }
    insert_stmt.finalize()
    // Delete
    let delete_stmt = db.prepare("DELETE FROM users WHERE age > ?").unwrap()
    delete_stmt.bind(1, Int(40)) |> ignore
    delete_stmt.execute() |> ignore
    delete_stmt.finalize()
    db.close()
  })
}

///|
/// Prepared Statement Reuse
test "bench: Prepared Statement Reuse" (b : @bench.T) {
  b.bench(fn() {
    let db = setup_database()
    let stmt = db
      .prepare("INSERT INTO users (name, age) VALUES (?, ?)")
      .unwrap()
    for i = 0; i < 50; i = i + 1 {
      stmt.bind(1, Text(cstring("User\{i}"))) |> ignore
      stmt.bind(2, Int(20 + i)) |> ignore
      stmt.execute() |> ignore
      stmt.reset()
    }
    stmt.finalize()
    db.close()
  })
}