// A runnable tour of MoonLoom.
//
//   moon run examples/demo
//
// Every step prints the plan, the rows and what the run cost, so the demo is
// also the smallest possible integration test of the library.

///|
const ACCESS_LOG : String =
  #|192.0.2.14 - - [11/Mar/2024:10:00:01 +0000] "GET /api/orders HTTP/1.1" 200 1532 "-" "Mozilla/5.0"
  #|192.0.2.14 - - [11/Mar/2024:10:00:02 +0000] "GET /static/app.js HTTP/1.1" 200 84210 "-" "Mozilla/5.0"
  #|198.51.100.7 - - [11/Mar/2024:10:00:03 +0000] "POST /api/orders HTTP/1.1" 201 310 "-" "Mozilla/5.0"
  #|198.51.100.7 - - [11/Mar/2024:10:00:04 +0000] "GET /api/orders HTTP/1.1" 500 214 "-" "curl/8.4.0"
  #|203.0.113.51 - - [11/Mar/2024:10:00:05 +0000] "GET /api/orders HTTP/1.1" 500 214 "-" "curl/8.4.0"
  #|203.0.113.51 - - [11/Mar/2024:10:00:06 +0000] "GET /health HTTP/1.1" 200 12 "-" "kube-probe/1.29"
  #|203.0.113.9 - - [11/Mar/2024:10:00:07 +0000] "GET /api/products HTTP/1.1" 503 198 "-" "Googlebot/2.1"
  #|192.0.2.88 - - [11/Mar/2024:10:00:08 +0000] "GET /api/users/me HTTP/1.1" 401 87 "-" "Mozilla/5.0"
  #|192.0.2.88 - - [11/Mar/2024:10:00:09 +0000] "POST /api/login HTTP/1.1" 200 421 "-" "Mozilla/5.0"
  #|192.0.2.14 - - [11/Mar/2024:10:00:10 +0000] "GET /does-not-exist HTTP/1.1" 404 153 "-" "Mozilla/5.0"
  #|

///|
const SALES_CSV : String =
  #|region,channel,units,amount
  #|North,online,120,4800.50
  #|North,retail,80,3120.00
  #|South,online,210,8610.25
  #|South,retail,45,1780.00
  #|East,online,310,12400.00
  #|East,retail,60,2400.00
  #|West,online,95,3610.75
  #|West,retail,140,5320.00
  #|

///|
const SERVICE_LOG : String =
  #|2024-03-11T10:00:01Z info orders: order 8812 created
  #|2024-03-11T10:00:04Z error orders: database timeout after 5 retries
  #|2024-03-11T10:00:06Z warn auth: missing token for /api/users/me
  #|2024-03-11T10:00:09Z info catalog: product 4471 refreshed
  #|2024-03-11T10:00:11Z error catalog: upstream unavailable, serving 503
  #|

///|
fn heading(title : String) -> Unit {
  println("")
  println("=== " + title + " ===")
}

///|
/// Runs one query over a dataset and prints the plan, the rows and the cost.
fn show(
  title : String,
  source : String,
  format : String,
  query_text : String,
  use_index : Bool,
) -> Unit {
  heading(title)
  let dataset = @text.parse_auto(source, format~)
  let query = match @query.Query::parse(query_text) {
    Ok(parsed) => parsed
    Err(message) => {
      println("query error: " + message)
      return
    }
  }
  let built = if use_index {
    Some(@index.TableIndex::build(dataset.table))
  } else {
    None
  }
  let plan = @plan.compile(query, dataset.table, built)
  println(plan.explain())
  let result = @exec.run(query, dataset.table, built)
  println(@render.render_table(result))
  println(@render.render_stats(result.stats))
}

///|
fn main {
  println("MoonLoom demo: " + @text.known_input_formats().join(", "))
  show(
    "which requests failed",
    ACCESS_LOG,
    "access",
    "where status >= 500 | stats count() as failures by path | sort failures desc",
    true,
  )
  show(
    "where the bytes go",
    ACCESS_LOG,
    "access",
    "stats sum(bytes) as total, count() as hits by method | sort total desc",
    true,
  )
  show(
    "every request from one address",
    ACCESS_LOG,
    "access",
    "where remote_host == \"203.0.113.51\" | fields time_text, method, path, status",
    true,
  )
  show(
    "revenue by region",
    SALES_CSV,
    "csv",
    "eval thousands = amount / 1000 | stats sum(amount) as revenue, avg(units) as mean_units by region | sort revenue desc",
    true,
  )
  show(
    "the same revenue query without an index",
    SALES_CSV,
    "csv",
    "eval thousands = amount / 1000 | stats sum(amount) as revenue, avg(units) as mean_units by region | sort revenue desc",
    false,
  )
  show(
    "errors extracted from plain text",
    SERVICE_LOG,
    "lines",
    "parse \"{time} {level} {service}: {message}\" | where level == \"error\" | fields time, service, message",
    false,
  )
}