// LLVMAotFacadeBox — IR 文字列(JSON v0)をファイルに書き出し、AotBox で compile/link する薄い委譲層
using selfhost.llvm.ir.LLVMBuilderBox as LLVMBuilderBox
// Note: Convenience wrappers build JSON inline to avoid nested resolver issues

static box LLVMAotFacadeBox {
  _truthy(s){ if !s { return 0 } local l = s.toLowerCase(); return (l=="1"||l=="true"||l=="on"||l=="yes") }
  _route(){
    // Decide route by env (read-only). Default = lib (via AotBox)
    // HAKO_AOT_USE_FFI=1 → ffi, HAKO_AOT_USE_PLUGIN=1 → plugin, else lib
    local ffi = env.get("HAKO_AOT_USE_FFI"); if LLVMAotFacadeBox._truthy(ffi) { return "ffi" }
    local plug = env.get("HAKO_AOT_USE_PLUGIN"); if LLVMAotFacadeBox._truthy(plug) { return "plugin" }
    return "lib"
  }
  _q(s){ return "\"" + s + "\"" }
  _i(n){ return "" + n }
  _inst_const(dst, val){
    return "{\"op\":\"const\",\"dst\":" + me._i(dst) + ",\"value\":{\"type\":\"i64\",\"value\":" + me._i(val) + "}}"
  }
  _inst_ret(val){ return "{\"op\":\"ret\",\"value\":" + me._i(val) + "}" }
  _map_binop_kind(opk){
    if opk == "+" { return "Add" }
    if opk == "-" { return "Sub" }
    if opk == "*" { return "Mul" }
    if opk == "/" { return "Div" }
    if opk == "%" { return "Mod" }
    return opk
  }
  _inst_binop(kind, lhs, rhs, dst){
    return "{\"op\":\"binop\",\"op_kind\":" + me._q(kind) + ",\"lhs\":" + me._i(lhs) + ",\"rhs\":" + me._i(rhs) + ",\"dst\":" + me._i(dst) + "}"
  }
  _wrap_fn(body_json){
    return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [ { \"id\": 0, \"instructions\": [" + body_json + "] } ] } ] }"
  }
  compile_link_json(json_text, obj_out, exe_out, flags){
    // Fail‑Fast: validate args
    if !json_text || !obj_out || !exe_out { return -1 }
    // Write JSON to a temp file next to obj_out
    local fb = new FileBox()
    local json_path = obj_out + ".json"
    // Ensure file is created and truncated
    fb.open(json_path, "w")
    fb.write(json_text)
    fb.close()
    // Delegate to AotBox (route is read-only; actual path is handled by C‑ABI/env)
    local _r = LLVMAotFacadeBox._route()
    local a = new AotBox()
    local rc1 = a.compile(json_path, obj_out)
    if rc1 != 0 { return rc1 }
    local rc2 = a.link(obj_out, exe_out, flags ? flags : "")
    return rc2
  }

  // Convenience wrappers (delegate to LLVMBuilderBox when gate=on; else inline JSON)
  compile_link_ret0(obj_out, exe_out, flags){
    local on = env.get("HAKO_LLVM_SCRIPT_BUILDER");
    if on && (LLVMAotFacadeBox._truthy(on)) {
      local json = LLVMBuilderBox.program_ret0()
      return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
    }
    // Inline JSON fallback to avoid nested using resolver dependencies
    local body = me._inst_const(1, 0) + "," + me._inst_ret(1)
    local json = me._wrap_fn(body)
    return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
  }
  compile_link_ret_i64(v, obj_out, exe_out, flags){
    local on = env.get("HAKO_LLVM_SCRIPT_BUILDER");
    if on && (LLVMAotFacadeBox._truthy(on)) {
      local json = LLVMBuilderBox.program_ret_i64(v)
      return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
    }
    local body = me._inst_const(1, v) + "," + me._inst_ret(1)
    local json = me._wrap_fn(body)
    return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
  }
  compile_link_binop_i64(lhs, rhs, opk, obj_out, exe_out, flags){
    local on = env.get("HAKO_LLVM_SCRIPT_BUILDER");
    if on && (LLVMAotFacadeBox._truthy(on)) {
      local json = LLVMBuilderBox.program_binop_i64(lhs, rhs, opk)
      return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
    }
    // Inline JSON fallback
    local kind = me._map_binop_kind(opk)
    local body = me._inst_const(1, lhs) + "," + me._inst_const(2, rhs) + "," + me._inst_binop(kind, 1, 2, 3) + "," + me._inst_ret(3)
    local json = me._wrap_fn(body)
    return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
  }

  // v1(compare minimal) — emit a compare (Eq) but return 0 to keep exe exit code stable
  // This exercises the compare path in AOT while ensuring the process exit is 0.
  compile_link_compare_eq_i64(lhs, rhs, obj_out, exe_out, flags){
    // Build: const 1=lhs, const 2=rhs, compare(dst=3, operation==, lhs=1, rhs=2),
    // then const 4=0, binop(dst=5, op="*", lhs=3, rhs=4), ret 5
    local inst_c1 = "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + me._i(lhs) + "}}"
    local inst_c2 = "{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":" + me._i(rhs) + "}}"
    local inst_cmp = "{\"op\":\"compare\",\"dst\":3,\"operation\":\"==\",\"lhs\":1,\"rhs\":2}"
    local inst_c0 = "{\"op\":\"const\",\"dst\":4,\"value\":{\"type\":\"i64\",\"value\":0}}"
    local inst_mul = "{\"op\":\"binop\",\"dst\":5,\"operation\":\"*\",\"lhs\":3,\"rhs\":4}"
    local inst_ret = "{\"op\":\"ret\",\"value\":5}"
    local body = inst_c1 + "," + inst_c2 + "," + inst_cmp + "," + inst_c0 + "," + inst_mul + "," + inst_ret
    local json = me._wrap_fn(body)
    return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
  }

  // v1(compare+branch minimal) — generate multi-block JSON with conditional branch; both paths return 0
  compile_link_compare_branch_i64(lhs, rhs, opk, obj_out, exe_out, flags){
    local op = opk ? opk : ">"
    // blocks: 0=cmp+branch, 1=then(ret 0), 2=else(ret 0)
    local b0 = "{\"id\":0,\"instructions\":[" +
               "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + me._i(lhs) + "}}," +
               "{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":" + me._i(rhs) + "}}," +
               "{\"op\":\"compare\",\"dst\":3,\"operation\":" + me._q(op) + ",\"lhs\":1,\"rhs\":2}," +
               "{\"op\":\"branch\",\"cond\":3,\"then\":1,\"else\":2}] }"
    local b1 = "{\"id\":1,\"instructions\":[" +
               "{\"op\":\"const\",\"dst\":4,\"value\":{\"type\":\"i64\",\"value\":0}}," +
               "{\"op\":\"ret\",\"value\":4}] }"
    local b2 = "{\"id\":2,\"instructions\":[" +
               "{\"op\":\"const\",\"dst\":5,\"value\":{\"type\":\"i64\",\"value\":0}}," +
               "{\"op\":\"ret\",\"value\":5}] }"
    local json = "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [" + b0 + "," + b1 + "," + b2 + "] } ] }"
    return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
  }

  // v1(phi-if minimal) — diamond shape with PHI at merge; returns 0 to keep exit code stable
  compile_link_phi_if_i64(val_then, val_else, obj_out, exe_out, flags){
    // 0: jump->1 always via const(true) compare; 1: const then; 2: const else; 3: phi merge; ret 0
    local b0 = "{\"id\":0,\"instructions\":[" +
               "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":1}}," +
               "{\"op\":\"compare\",\"dst\":2,\"operation\":\"==\",\"lhs\":1,\"rhs\":1}," +
               "{\"op\":\"branch\",\"cond\":2,\"then\":1,\"else\":2}] }"
    local b1 = "{\"id\":1,\"instructions\":[" +
               "{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":" + me._i(val_then) + "}}," +
               "{\"op\":\"jump\",\"target\":3}] }"
    local b2 = "{\"id\":2,\"instructions\":[" +
               "{\"op\":\"const\",\"dst\":4,\"value\":{\"type\":\"i64\",\"value\":" + me._i(val_else) + "}}," +
               "{\"op\":\"jump\",\"target\":3}] }"
    local b3 = "{\"id\":3,\"instructions\":[" +
               "{\"op\":\"phi\",\"dst\":5,\"type\":\"i64\",\"incoming\":[{\"block\":1,\"value\":3},{\"block\":2,\"value\":4}]}," +
               "{\"op\":\"const\",\"dst\":6,\"value\":{\"type\":\"i64\",\"value\":0}}," +
               "{\"op\":\"ret\",\"value\":6}] }"
    local json = "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [" + b0 + "," + b1 + "," + b2 + "," + b3 + "] } ] }"
    return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
  }

  // extern call convenience wrappers (console.*) — build via Builder and link
  compile_link_call_console_log(obj_out, exe_out, flags){
    local on = env.get("HAKO_LLVM_SCRIPT_BUILDER");
    local json
    if on && (LLVMAotFacadeBox._truthy(on)) { json = LLVMBuilderBox.program_call_console_log_ret0() }
    else {
      local body = "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"string\",\"value\":\"hello\"}}," +
                   "{\"op\":\"mir_call\",\"dst\":2,\"mir_call\":{\"callee\":{\"type\":\"Extern\",\"name\":\"env.console.log\"},\"args\":[1],\"effects\":[]}}," +
                   "{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," +
                   "{\"op\":\"ret\",\"value\":3}"
      json = me._wrap_fn(body)
    }
    return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
  }
  compile_link_call_console_warn(obj_out, exe_out, flags){
    local on = env.get("HAKO_LLVM_SCRIPT_BUILDER");
    local json
    if on && (LLVMAotFacadeBox._truthy(on)) { json = LLVMBuilderBox.program_call_console_warn_ret0() }
    else {
      local body = "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"string\",\"value\":\"warn-message\"}}," +
                   "{\"op\":\"mir_call\",\"dst\":2,\"mir_call\":{\"callee\":{\"type\":\"Extern\",\"name\":\"env.console.warn\"},\"args\":[1],\"effects\":[]}}," +
                   "{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," +
                   "{\"op\":\"ret\",\"value\":3}"
      json = me._wrap_fn(body)
    }
    return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
  }
  compile_link_call_console_error(obj_out, exe_out, flags){
    local on = env.get("HAKO_LLVM_SCRIPT_BUILDER");
    local json
    if on && (LLVMAotFacadeBox._truthy(on)) { json = LLVMBuilderBox.program_call_console_error_ret0() }
    else {
      local body = "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"string\",\"value\":\"error-message\"}}," +
                   "{\"op\":\"mir_call\",\"dst\":\"null\",\"mir_call\":{\"callee\":{\"type\":\"Extern\",\"name\":\"env.console.error\"},\"args\":[1],\"effects\":[]}}," +
                   "{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," +
                   "{\"op\":\"ret\",\"value\":3}"
      json = me._wrap_fn(body)
    }
    return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
  }
  // Negative helper for smoke: invalid extern name to observe Fail‑Fast
  compile_link_call_console_invalid(obj_out, exe_out, flags){
    // Construct minimal JSON inline to avoid depending on Builder for invalid case
    local body = "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"string\",\"value\":\"hello\"}}," +
                 "{\"op\":\"mir_call\",\"dst\":2,\"mir_call\":{\"callee\":{\"type\":\"Extern\",\"name\":\"env.console.nope\"},\"args\":[1],\"effects\":[]}}," +
                 "{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," +
                 "{\"op\":\"ret\",\"value\":3}"
    local json = me._wrap_fn(body)
    return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
  }
  // time.now_ms — build via Builder when gate, else inline JSON; ret 0
  compile_link_call_time_now_ms(obj_out, exe_out, flags){
    local on = env.get("HAKO_LLVM_SCRIPT_BUILDER");
    local json
    if on && (LLVMAotFacadeBox._truthy(on)) { json = LLVMBuilderBox.program_call_time_now_ms_ret0() }
    else {
      local body = "{\"op\":\"mir_call\",\"dst\":2,\"mir_call\":{\"callee\":{\"type\":\"Extern\",\"name\":\"env.time.now_ms\"},\"args\":[],\"effects\":[]}}," +
                   "{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," +
                   "{\"op\":\"ret\",\"value\":3}"
      json = me._wrap_fn(body)
    }
    return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
  }
  // JSON.stringify(any) — via nyash.json.stringify_h; ret 0
  compile_link_call_json_stringify(obj_out, exe_out, flags){
    local on = env.get("HAKO_LLVM_SCRIPT_BUILDER");
    local json
    if on && (LLVMAotFacadeBox._truthy(on)) { json = LLVMBuilderBox.program_call_json_stringify_ret0() }
    else {
      local body = "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":42}}," +
                   "{\"op\":\"mir_call\",\"dst\":2,\"mir_call\":{\"callee\":{\"type\":\"Extern\",\"name\":\"nyash.json.stringify_h\"},\"args\":[1],\"effects\":[]}}," +
                   "{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," +
                   "{\"op\":\"ret\",\"value\":3}"
      json = me._wrap_fn(body)
    }
    return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
  }
  // env.mem.alloc/free wrapper — ret 0
  compile_link_call_mem_alloc_free(sz, obj_out, exe_out, flags){
    local on = env.get("HAKO_LLVM_SCRIPT_BUILDER");
    local json
    if on && (LLVMAotFacadeBox._truthy(on)) { json = LLVMBuilderBox.program_call_mem_alloc_free_ret0(sz) }
    else {
      local s = sz ? sz : 16
      local body = "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + me._i(s) + "}}," +
                   "{\"op\":\"mir_call\",\"dst\":2,\"mir_call\":{\"callee\":{\"type\":\"Extern\",\"name\":\"env.mem.alloc\"},\"args\":[1],\"effects\":[]}}," +
                   "{\"op\":\"mir_call\",\"dst\":3,\"mir_call\":{\"callee\":{\"type\":\"Extern\",\"name\":\"env.mem.free\"},\"args\":[2],\"effects\":[]}}," +
                   "{\"op\":\"const\",\"dst\":4,\"value\":{\"type\":\"i64\",\"value\":0}}," +
                   "{\"op\":\"ret\",\"value\":4}"
      json = me._wrap_fn(body)
    }
    return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
  }
  // env.local.get wrapper — ret 0 (value ignored)
  compile_link_call_env_local_get(key, obj_out, exe_out, flags){
    local on = env.get("HAKO_LLVM_SCRIPT_BUILDER");
    local json
    if on && (LLVMAotFacadeBox._truthy(on)) { json = LLVMBuilderBox.program_call_env_local_get_ret0(key) }
    else {
      local k = key ? key : "SMOKES_ENV_LOCAL_GET"
      local body = "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"string\",\"value\":\"" + k + "\"}}," +
                   "{\"op\":\"mir_call\",\"dst\":2,\"mir_call\":{\"callee\":{\"type\":\"Extern\",\"name\":\"env.local.get\"},\"args\":[1],\"effects\":[]}}," +
                   "{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," +
                   "{\"op\":\"ret\",\"value\":3}"
      json = me._wrap_fn(body)
    }
    return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
  }
}
