/// WASM runtime type detected on the system.
pub enum RuntimeType {
  Wasmtime
  Wasmer
  Wazero
  Node
  Bun
  Deno
}

/// Result for a single runtime probe.
pub struct RuntimeProbe {
  name : String
  kind : RuntimeType
  installed : Bool
  version : Option[String]
  path : Option[String]
}

/// Overall WASM environment report.
pub struct WASMEnvReport {
  moon_version : String
  runtimes : Array[RuntimeProbe]
}

/// Serialize report to JSON string (CI-friendly, machine-parseable).
pub fn report_to_json(report : WASMEnvReport) -> String {
  let sb = StringBuilder()
  sb.write_string("{\n")
  sb.write_string("  \"moon_version\": ")
  sb.write_string(json_escape(report.moon_version))
  sb.write_string(",\n")

  // Collect missing runtimes while building the runtimes array
  let mut all_installed = true
  let missing_arr = Array::new()

  sb.write_string("  \"runtimes\": [\n")
  let mut first = true
  report.runtimes.each(fn(r) {
    if !first {
      sb.write_string(",\n")
    }
    first = false
    sb.write_string("    {")
    sb.write_string("\"name\": ")
    sb.write_string(json_escape(r.name))
    sb.write_string(", \"installed\": ")
    sb.write_string(if r.installed { "true" } else { "false" })
    sb.write_string(", \"version\": ")
    match r.version {
      Some(v) => { sb.write_string(json_escape(v)) }
      None => { sb.write_string("null") }
    }
    sb.write_string(", \"path\": ")
    match r.path {
      Some(p) => { sb.write_string(json_escape(p)) }
      None => { sb.write_string("null") }
    }
    sb.write_string("}")

    if !r.installed {
      all_installed = false
      missing_arr.push(r.name)
    }
  })
  sb.write_string("\n  ],\n")

  // missing runtimes list
  sb.write_string("  \"missing\": [\n")
  let mut first_miss = true
  missing_arr.each(fn(name) {
    if !first_miss {
      sb.write_string(",\n")
    }
    first_miss = false
    sb.write_string("    ")
    sb.write_string(json_escape(name))
  })
  sb.write_string("\n  ],\n")

  sb.write_string("  \"all_installed\": ")
  sb.write_string(if all_installed { "true" } else { "false" })
  sb.write_string("\n}\n")
  sb.to_string()
}

/// JSON string escaping helper.
fn json_escape(s : String) -> String {
  let sb = StringBuilder()
  sb.write_char('"')
  for i = 0; i < s.length(); i = i + 1 {
    let ch = s[i]
    if ch == '"'.to_int().to_uint16() {
      sb.write_string("\\\"")
    } else if ch == '\\'.to_int().to_uint16() {
      sb.write_string("\\\\")
    } else if ch == '\n'.to_int().to_uint16() {
      sb.write_string("\\n")
    } else if ch == '\r'.to_int().to_uint16() {
      sb.write_string("\\r")
    } else if ch == '\t'.to_int().to_uint16() {
      sb.write_string("\\t")
    } else {
      sb.write_char(ch.unsafe_to_char())
    }
  }
  sb.write_char('"')
  sb.to_string()
}