// JsonBuilder — Minimal helpers to construct AST JSON v0 fragments as strings
// Usage: local JB = include "apps/lib/json_builder.hako"
//        local s = JB.literal_string("x")

static box JsonBuilder {
  // Join array of strings with a separator
  join(arr, sep) {
    local out = ""
    local i = 0
    local n = arr.length()
    loop(i < n) {
      out = out + arr.get(i)
      if i + 1 < n { out = out + sep }
      i = i + 1
    }
    return out
  }

  // JSON string escaping (minimal): backslash, quote
  escape_string(s) {
    local out = ""
    local i = 0
    loop(i < s.length()) {
      local ch = s.substring(i, i + 1)
      if ch == "\\" {
        out = out + "\\\\"
      } else {
        if ch == "\"" { out = out + "\\\"" } else { out = out + ch }
      }
      i = i + 1
    }
    return out
  }

  quote(s) { return "\"" + this.escape_string(s) + "\"" }

  // ==== Node builders (strings) ====
  literal_string(s) {
    return "{\"kind\":\"Literal\",\"value\":{\"type\":\"string\",\"value\":" + this.quote(s) + "}}"
  }
  literal_int(i) {
    return "{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" + i + "}}"
  }
  literal_bool(b) {
    if b { return "{\"kind\":\"Literal\",\"value\":{\"type\":\"bool\",\"value\":true}}" }
    return "{\"kind\":\"Literal\",\"value\":{\"type\":\"bool\",\"value\":false}}"
  }
  literal_null() { return "{\"kind\":\"Literal\",\"value\":{\"type\":\"null\"}}" }

  variable(name) {
    return "{\"kind\":\"Variable\",\"name\":" + this.quote(name) + "}"
  }

  binary(op, lhs_json, rhs_json) {
    return "{\"kind\":\"BinaryOp\",\"op\":" + this.quote(op) + ",\"left\":" + lhs_json + ",\"right\":" + rhs_json + "}"
  }

  assignment(target_json, value_json) {
    return "{\"kind\":\"Assignment\",\"target\":" + target_json + ",\"value\":" + value_json + "}"
  }

  print_(expr_json) {
    return "{\"kind\":\"Print\",\"expression\":" + expr_json + "}"
  }

  return_(value_json) {
    local v = "null"
    if value_json != null { v = value_json }
    return "{\"kind\":\"Return\",\"value\":" + v + "}"
  }

  local_decl(vars, inits) {
    // vars: array[string], inits: array[string|null]
    local vs = []
    local i = 0
    loop(i < vars.length()) {
      vs.push(this.quote(vars.get(i)))
      i = i + 1
    }
    local is = []
    i = 0
    loop(i < inits.length()) {
      local v = inits.get(i)
      if v == null { is.push("null") } else { is.push(v) }
      i = i + 1
    }
    return "{\"kind\":\"Local\",\"variables\":[" + this.join(vs, ",") + "],\"inits\":[" + this.join(is, ",") + "]}"
  }

  array(elems_json) {
    return "{\"kind\":\"Array\",\"elements\":[" + this.join(elems_json, ",") + "]}"
  }
  map(entries) {
    // entries: array of [k:string, v:json]
    local parts = []
    local i = 0
    loop(i < entries.length()) {
      local kv = entries.get(i)
      local k = kv.get(0)
      local v = kv.get(1)
      parts.push("{\"k\":" + this.quote(k) + ",\"v\":" + v + "}")
      i = i + 1
    }
    return "{\"kind\":\"Map\",\"entries\":[" + this.join(parts, ",") + "]}"
  }

  if_(cond_json, then_stmts_json, else_stmts_json) {
    local then_s = "[" + this.join(then_stmts_json, ",") + "]"
    local else_s = "null"
    if else_stmts_json != null { else_s = "[" + this.join(else_stmts_json, ",") + "]" }
    return "{\"kind\":\"If\",\"condition\":" + cond_json + ",\"then\":" + then_s + ",\"else\":" + else_s + "}"
  }

  loop_(cond_json, body_stmts_json) {
    return "{\"kind\":\"Loop\",\"condition\":" + cond_json + ",\"body\":[" + this.join(body_stmts_json, ",") + "]}"
  }

  program(stmts_json) {
    return "{\"kind\":\"Program\",\"statements\":[" + this.join(stmts_json, ",") + "]}"
  }
}
