// el-ui-compiler — El→browser-target component compiler (STUB).
//
// The Rust crate transforms `.el` component files into JavaScript using a
// real lexer/parser/codegen pipeline backed by the el-ui runtime
// (`el-ui.js`). This El surface is a placeholder.
//
// RUNTIME GAP — load-bearing:
//   `elc` (the bootstrap El compiler) currently emits C only. There is no
//   JavaScript or WebAssembly backend yet, so the El surface cannot
//   actually compile a component to JS today.
//
//   What this vessel provides:
//     - The shape of the public API (Compiler with runtime_path,
//       compile_component, compile_app).
//     - A `CompileResult` record consumers can branch on.
//     - Stub bodies that return a deterministic "not yet implemented"
//       module string so downstream tooling can integration-test against
//       a stable contract.
//
//   When elc gains a JS/Wasm backend, swap the bodies of `lex`, `parse`,
//   `semantic_check`, and `codegen` for real implementations — the public
//   surface should not need to change.

// ── Errors ──────────────────────────────────────────────────────────────────

fn err_lex()             -> String { "elc.lex" }
fn err_parse()           -> String { "elc.parse" }
fn err_semantic()        -> String { "elc.semantic" }
fn err_codegen()         -> String { "elc.codegen" }
fn err_backend_missing() -> String { "elc.backend_missing" }

// ── Compile result ──────────────────────────────────────────────────────────
//
// Modeled as JSON since the runtime's product types and field accessors
// don't yet support the Bool/String mix we want here cleanly.

fn result_ok(code: String) -> String {
    "{\"ok\":true,\"code\":" + json_quote(code) + ",\"error\":\"\"}"
}

fn result_err(error: String) -> String {
    "{\"ok\":false,\"code\":\"\",\"error\":\"" + error + "\"}"
}

// Minimal JSON string quoter (escape backslash + double-quote only).
// elc still doesn't expose a json_string_quote builtin.
fn json_quote(s: String) -> String {
    let escaped: String = str_replace(s, "\\", "\\\\")
    let escaped = str_replace(escaped, "\"", "\\\"")
    "\"" + escaped + "\""
}

fn result_ok_p(result_json: String) -> Bool {
    json_get_bool(result_json, "ok")
}

// ── Compiler config ─────────────────────────────────────────────────────────

fn compiler_default_runtime_path() -> String { "./el-ui.js" }
fn compiler_default_target()       -> String { "js" }

fn compiler_new() -> String {
    "{\"runtime_path\":\"./el-ui.js\",\"target\":\"js\"}"
}

fn compiler_with_runtime(c_json: String, path: String) -> String {
    json_set(c_json, "runtime_path", json_quote(path))
}

fn compiler_with_target(c_json: String, target: String) -> String {
    json_set(c_json, "target", json_quote(target))
}

fn compiler_runtime_path(c_json: String) -> String {
    json_get_string(c_json, "runtime_path")
}

fn compiler_target(c_json: String) -> String {
    json_get_string(c_json, "target")
}

// ── Pipeline stages (stubs) ─────────────────────────────────────────────────
//
// Real implementations live in the Rust crate (lexer.rs, parser.rs,
// semantic.rs, codegen.rs). These El stubs only validate inputs and
// produce a marker payload so callers can wire the contract.

fn lex(source: String) -> String {
    if str_eq(source, "") { return "" }
    "[]"   // would be tokens JSON
}

fn parse(tokens_json: String) -> String {
    if str_eq(tokens_json, "") { return "" }
    "[]"   // would be Component AST JSON
}

fn semantic_check(ast_json: String) -> String {
    ast_json   // pass-through stub
}

fn codegen(c_json: String, ast_json: String) -> String {
    let runtime: String = compiler_runtime_path(c_json)
    let preamble: String = "// AUTOGENERATED by el-ui-compiler (STUB)\n"
    let import_line: String = "import { register, h } from \"" + runtime + "\";\n"
    let body: String = "throw new Error(\"" + err_backend_missing()
        + ": el-ui-compiler has no JS backend yet; emit C with elc instead\");\n"
    preamble + import_line + body
}

// ── Public entry points ─────────────────────────────────────────────────────

fn compile_component(c_json: String, source: String) -> String {
    let tokens: String = lex(source)
    if str_eq(tokens, "") { return result_err(err_lex()) }
    let ast: String = parse(tokens)
    if str_eq(ast, "") { return result_err(err_parse()) }
    let checked: String = semantic_check(ast)
    if str_eq(checked, "") { return result_err(err_semantic()) }
    let js: String = codegen(c_json, checked)
    result_ok(js)
}

// `entry_source` is the app entry; `components_json` is a JSON object map of
// name -> source text. We compile each component first, then the entry.
fn compile_app(c_json: String, entry_source: String, components_json: String) -> String {
    // RUNTIME GAP: no json_object_keys() yet, so we cannot iterate the map
    // generically here. Real implementation will iterate and short-circuit
    // on first compile error. For the stub we just compile the entry.
    compile_component(c_json, entry_source)
}

// ── Entry — smoke test ──────────────────────────────────────────────────────

let c: String = compiler_new()
let c = compiler_with_runtime(c, "./el-ui.js")
let r: String = compile_component(c, "component Hello { template { <p>hi</p> } }")
if result_ok_p(r) {
    println("[el-ui-compiler] STUB compiled (target=" + compiler_target(c) + ")")
} else {
    println("[el-ui-compiler] error: " + json_get_string(r, "error"))
}
