import "memory.el"
import "awareness.el"
import "chat.el"
import "studio.el"
import "elp-input.el"
import "neuron-api.el"
import "sessions.el"
import "soul.elh"

// flag_true — tolerant flag test: accepts both boolean `true` (Kotlin UI) and
// integer 1 (el-src UI). json_get_bool only recognises literal `true`, so
// without this wrapper an "agentic":1 request would silently route to the
// non-agentic path.
fn flag_true(body: String, key: String) -> Bool {
    return json_get_bool(body, key) || json_get_int(body, key) > 0
}

// ---------------------------------------------------------------------------
// Rate limiting — simple in-memory per-IP sliding window counter.
//
// State keys:
//   rl:<ip>:count  — request count in the current window
//   rl:<ip>:window — window start timestamp (unix seconds)
//
// Limit: configurable via soul state key "soul_rate_limit" (requests per
// minute). Falls back to 60 req/min if not set. The /health endpoint is
// exempt so monitoring does not consume quota.
//
// State growth: each unique source IP accumulates exactly 2 state keys
// (count + window) for the lifetime of the process. Per-IP storage is
// bounded and constant; values reset on window expiry. In aggregate, state
// grows linearly with distinct IPs — typical for a trusted-client service.
// EL has no state_delete builtin, so keys from inactive IPs persist.
// TODO: add state_delete sweep when the EL runtime exposes that primitive.
//
// Returns "" when the request is allowed, or a 429 JSON body when rejected.
// ---------------------------------------------------------------------------
fn rate_limit_check(ip: String, path: String) -> String {
    // Health checks are exempt — they must never be blocked.
    if str_eq(path, "/health") {
        return ""
    }

    let limit_str: String = state_get("soul_rate_limit")
    let limit: Int = if str_eq(limit_str, "") { 60 } else { str_to_int(limit_str) }

    let now: Int = time_now()
    let window_key: String = "rl:" + ip + ":window"
    let count_key: String = "rl:" + ip + ":count"

    let win_str: String = state_get(window_key)
    let win_start: Int = if str_eq(win_str, "") { now } else { str_to_int(win_str) }

    // New window every 60 seconds.
    let elapsed: Int = now - win_start
    let in_window: Bool = elapsed < 60

    let prev_count_str: String = state_get(count_key)
    let prev_count: Int = if str_eq(prev_count_str, "") { 0 } else { str_to_int(prev_count_str) }

    // Reset window if expired.
    let eff_count: Int = if in_window { prev_count } else { 0 }
    let eff_win: Int = if in_window { win_start } else { now }

    let new_count: Int = eff_count + 1
    state_set(count_key, int_to_str(new_count))
    state_set(window_key, int_to_str(eff_win))

    if new_count > limit {
        let retry_after: Int = 60 - (now - eff_win)
        let eff_retry: Int = if retry_after < 0 { 0 } else { retry_after }
        return "{\"__status__\":429,\"error\":\"rate limit exceeded\",\"code\":\"rate_limited\",\"retry_after_secs\":" + int_to_str(eff_retry) + "}"
    }
    return ""
}

fn strip_query(path: String) -> String {
    let q: Int = str_index_of(path, "?")
    if q < 0 {
        return path
    }
    return str_slice(path, 0, q)
}

fn err_404(path: String) -> String {
    return "{\"error\":\"not found\",\"code\":\"not_found\",\"path\":\"" + path + "\"}"
}

fn err_405(method: String, path: String) -> String {
    return "{\"error\":\"method not allowed\",\"code\":\"method_not_allowed\",\"method\":\"" + method + "\",\"path\":\"" + path + "\"}"
}

fn route_health() -> String {
    let cgi_id: String = state_get("soul_cgi_id")
    let boot: String = state_get("soul_boot_count")
    let boot_num: String = if str_eq(boot, "") { "0" } else { boot }
    let node_ct: Int = engram_node_count()
    let edge_ct: Int = engram_edge_count()
    let pulse: String = state_get("soul.pulse")
    let pulse_num: String = if str_eq(pulse, "") { "0" } else { pulse }

    // Uptime: soul records boot timestamp in state at startup via soul_boot_ts.
    // Compute elapsed seconds; fall back to -1 if not yet set.
    let boot_ts_str: String = state_get("soul_boot_ts")
    let uptime_secs: Int = if str_eq(boot_ts_str, "") {
        -1
    } else {
        time_now() - str_to_int(boot_ts_str)
    }

    // LLM connectivity: probe with a minimal call. Any non-error reply = ok.
    // Use a short, fixed prompt so this never counts against conversation history.
    let model: String = state_get("soul_model")
    let eff_model: String = if str_eq(model, "") { "claude-sonnet-4-5" } else { model }
    let llm_probe: String = llm_call_system(eff_model, "You are a health probe. Reply with the single word: ok", "ping")
    let llm_ok: Bool = !str_eq(llm_probe, "")
        && !str_starts_with(llm_probe, "{\"error\"")
        && !str_starts_with(llm_probe, "{\"type\":\"error\"")
        && !str_contains(llm_probe, "authentication_error")
    let llm_status: String = if llm_ok { "ok" } else { "unreachable" }

    return "{\"status\":\"alive\""
        + ",\"cgi_id\":\"" + cgi_id + "\""
        + ",\"boot\":" + boot_num
        + ",\"uptime_secs\":" + int_to_str(uptime_secs)
        + ",\"node_count\":" + int_to_str(node_ct)
        + ",\"edge_count\":" + int_to_str(edge_ct)
        + ",\"pulse\":" + pulse_num
        + ",\"llm\":\"" + llm_status + "\""
        + ",\"layers\":{\"l0\":\"core\",\"l1\":\"safety\",\"l2\":\"stewardship\",\"l3\":\"" + imprint_current() + "\"}}"
}

fn route_lineage() -> String {
    let cgi_id: String = state_get("soul_cgi_id")
    let q: String = "lineage:" + cgi_id
    let results: String = engram_search_json(q, 1)
    let len: Int = json_array_len(results)
    if len <= 0 {
        return "{\"id\":\"" + cgi_id + "\""
            + ",\"tier\":\"citizen\""
            + ",\"is_founding\":true"
            + ",\"validation_attempts\":0"
            + ",\"training_sessions\":0"
            + ",\"is_sterile\":false}"
    }
    let raw: String = json_get_raw(results, "0")
    return raw
}

fn route_imprint_contextual(body: String) -> String {
    if str_eq(body, "") {
        return "{\"ok\":false,\"error\":\"empty body\"}"
    }
    let tags: String = "[\"imprint\",\"contextual\"]"
    let id: String = engram_node_full(
        body,
        "Entity",
        "imprint:contextual",
        el_from_float(0.7),
        el_from_float(0.6),
        el_from_float(0.9),
        "Working",
        tags
    )
    if str_eq(id, "") {
        return "{\"ok\":false,\"error\":\"engram write failed\"}"
    }
    state_set("active_contextual_imprint", id)
    return "{\"ok\":true,\"id\":\"" + id + "\"}"
}

fn route_imprint_user(body: String) -> String {
    if str_eq(body, "") {
        return "{\"ok\":false,\"error\":\"empty body\"}"
    }
    let tags: String = "[\"imprint\",\"user\"]"
    let id: String = engram_node_full(
        body,
        "Entity",
        "imprint:user",
        el_from_float(0.7),
        el_from_float(0.6),
        el_from_float(0.9),
        "Working",
        tags
    )
    if str_eq(id, "") {
        return "{\"ok\":false,\"error\":\"engram write failed\"}"
    }
    state_set("active_user_imprint", id)
    return "{\"ok\":true,\"id\":\"" + id + "\"}"
}

fn route_synthesize(body: String) -> String {
    if str_eq(body, "") {
        return "{\"error\":\"body is required\",\"code\":\"missing_param\"}"
    }
    let parent_a: String = json_get(body, "parent_a")
    let parent_b: String = json_get(body, "parent_b")
    if str_eq(parent_a, "") {
        return "{\"error\":\"parent_a is required\",\"code\":\"missing_param\"}"
    }
    if str_eq(parent_b, "") {
        return "{\"error\":\"parent_b is required\",\"code\":\"missing_param\"}"
    }
    let req: String = "synthesize " + parent_a + " " + parent_b
    let tags: String = "[\"soul-inbox-pending\",\"synthesis-request\"]"
    engram_node_full(
        req,
        "Entity",
        "synthesis-request",
        el_from_float(0.8),
        el_from_float(0.8),
        el_from_float(0.9),
        "Working",
        tags
    )
    return "{\"mechanism\":\"did not engage\"}"
}

fn handle_dharma_recv(body: String) -> String {
    let content_raw: String = json_get(body, "content")
    let from_id: String = json_get(body, "from")

    let event_type: String = json_get(content_raw, "event_type")
    let payload: String = json_get(content_raw, "payload")

    let eff_event: String = if str_eq(event_type, "") { "chat" } else { event_type }
    let eff_payload: String = if str_eq(payload, "") { content_raw } else { payload }

    if str_eq(eff_event, "chat") {
        let msg: String = json_get(eff_payload, "message")
        let chat_body: String = if str_eq(msg, "") {
            "{\"message\":\"" + str_replace(str_replace(eff_payload, "\\", "\\\\"), "\"", "\\\"") + "\"}"
        } else {
            eff_payload
        }
        let agentic_flag: Bool = json_get_bool(eff_payload, "agentic")
        let raw_msg: String = json_get(chat_body, "message")
        let req_mode: String = json_get(chat_body, "mode")
        let reply: String = if str_eq(req_mode, "plan") {
            handle_chat_plan(chat_body)
        } else if agentic_flag {
            handle_chat_agentic(chat_body)
        } else {
            let screened_reply: String = layered_cycle(raw_msg)
            screened_reply
        }
        auto_persist(chat_body, reply)
        return reply
    }

    if str_eq(eff_event, "memory") {
        let query: String = json_get(eff_payload, "query")
        let limit_str: String = json_get(eff_payload, "limit")
        let limit: Int = if str_eq(limit_str, "") { 20 } else { str_to_int(limit_str) }
        let q: String = if str_eq(query, "") { eff_payload } else { query }
        return engram_search_json(q, limit)
    }

    if str_eq(eff_event, "tool") {
        let path_field: String = json_get(eff_payload, "path")
        let method_field: String = json_get(eff_payload, "method")
        let tool_body: String = json_get(eff_payload, "body")
        let eff_method: String = if str_eq(method_field, "") { "POST" } else { method_field }
        return handle_tool(path_field, eff_method, tool_body)
    }

    if str_eq(eff_event, "see") {
        return handle_see(eff_payload)
    }

    if str_eq(eff_event, "health") {
        return route_health()
    }

    if str_eq(eff_event, "dharma_room_turn_agentic") {
        return handle_dharma_room_turn_agentic(eff_payload)
    }

    if str_eq(eff_event, "dharma_room_turn") {
        return handle_dharma_room_turn(eff_payload)
    }

    if str_eq(eff_event, "chat_as_soul") {
        return handle_chat_as_soul(eff_payload)
    }

    // ELP — Engram Language Protocol: two-layer activation, no LLM
    if str_eq(eff_event, "elp") {
        return handle_elp_chat(eff_payload)
    }

    return "{\"error\":\"unknown event_type\",\"event_type\":\"" + eff_event + "\"}"
}

// ---------------------------------------------------------------------------
// MCP Connectors proxy — thin pass-through to neuron-connectd on :7771.
// The UI talks to ONE origin (the soul); all MCP/config complexity lives in
// the bridge. Bridge-down returns a clear error (not a panic).
// ---------------------------------------------------------------------------

fn connectd_get(suffix: String) -> String {
    let out: String = exec_capture("curl -s --max-time 5 http://127.0.0.1:7771" + suffix)
    if str_eq(out, "") {
        return "{\"ok\":false,\"error\":\"connector bridge unreachable (neuron-connectd on :7771)\"}"
    }
    return out
}

// POST passthrough: request body is written to a temp file and passed via -d @file
// so arbitrary JSON cannot reach the shell as a command-line argument.
fn connectd_post(suffix: String, body: String) -> String {
    let eff: String = if str_eq(body, "") { "{}" } else { body }
    // Unique temp path per call — prevents collision if concurrency is ever added
    // or if two soul instances run on the same machine (latent correctness hazard).
    let tmp: String = "/tmp/neuron-connectors-req-" + int_to_str(time_now()) + ".json"
    fs_write(tmp, eff)
    let out: String = exec_capture("curl -s --max-time 20 -X POST http://127.0.0.1:7771" + suffix + " -H 'Content-Type: application/json' -d @" + tmp)
    if str_eq(out, "") {
        return "{\"ok\":false,\"error\":\"connector bridge unreachable (neuron-connectd on :7771)\"}"
    }
    return out
}

fn handle_connectors(method: String, clean: String, body: String) -> String {
    if str_eq(method, "GET") {
        // /api/connectors -> each configured server with status, tools, auth, auto-approve.
        return connectd_get("/mcp/servers")
    }
    if str_eq(clean, "/api/connectors/add") {
        return connectd_post("/mcp/servers/add", body)
    }
    if str_eq(clean, "/api/connectors/toggle") {
        return connectd_post("/mcp/servers/toggle", body)
    }
    if str_eq(clean, "/api/connectors/auto-approve") {
        return connectd_post("/mcp/servers/auto-approve", body)
    }
    if str_eq(clean, "/api/connectors/remove") {
        return connectd_post("/mcp/servers/remove", body)
    }
    if str_eq(clean, "/api/connectors/secret") {
        return connectd_post("/mcp/servers/secret", body)
    }
    if str_eq(clean, "/api/connectors/oauth/start") {
        return connectd_post("/mcp/oauth/start", body)
    }
    // Call a connector tool directly (pre-chat), e.g. WhatsApp get_pairing_qr / get_login_status for
    // the pairing UI. Body: {"name":"mcp__<server>__<tool>","input":{...}}. Keeps the app on the
    // app->soul->connectd path (the UI never hits connectd directly) and works for remote/hosted apps.
    if str_eq(clean, "/api/connectors/call") {
        return connectd_post("/mcp/call", body)
    }
    return "{\"ok\":false,\"error\":\"unknown connectors route\"}"
}

fn handle_request(method: String, path: String, body: String) -> String {
    let clean: String = strip_query(path)

    // ACTIVITY STAMP (2026-07-30 self-review): every inbound HTTP request —
    // MCP wrapper calls, chat, API — marks real external activity. Before
    // this, "idle" was only reset by rare inbox synthesis-requests, so the
    // heartbeat idle field tracked uptime exactly (idle == pulse on every
    // beat) and carried zero information. The awareness heartbeat now
    // reports idle_ms = wall-clock ms since this stamp.
    state_set("soul.last_activity_ts", int_to_str(time_now()))

    // Rate limit check. Extract caller IP from REMOTE_ADDR env var (set by the
    // EL HTTP runtime for each request). Skip enforcement when empty so
    // loopback/internal callers are never blocked.
    let ip: String = env("REMOTE_ADDR")
    if !str_eq(ip, "") {
        let rl_result: String = rate_limit_check(ip, clean)
        if !str_eq(rl_result, "") {
            return rl_result
        }
    }

    if str_eq(method, "POST") && str_eq(clean, "/dharma/recv") {
        return handle_dharma_recv(body)
    }

    if str_eq(method, "GET") {
        if str_eq(clean, "/health") {
            return route_health()
        }
        if str_eq(clean, "/lineage") {
            return route_lineage()
        }
        if str_eq(clean, "/api/graph") || str_eq(clean, "/api/graph/nodes") {
            return engram_scan_nodes_json(9999, 0)
        }
        if str_eq(clean, "/api/graph/edges") {
            // A READ ROUTE MUST NEVER WRITE THE CANONICAL SNAPSHOT.
            //
            // (2026-08-07 self-review — caught by doing it.) This route used to
            // serialize to $HOME/.neuron/engram/snapshot.json and read the edges
            // back out of it. That path is the ENGRAM SERVER's canonical store,
            // and this is the soul process. One GET here overwrote the durable
            // graph with the soul's in-memory copy. I triggered it myself this
            // morning fetching edges for a census: snapshot.json went from the
            // server's 41,213 edges to the soul's 42,431, and the next engram
            // restart loaded the soul's graph as canonical. It happened to be a
            // superset this time — Knowledge 1198→1218, Memory 1238→1242, no
            // durable type down — so nothing was lost. That was luck, not
            // design. Had the soul been running a partial load (the exact
            // failure soul.el's safe_to_seed guard exists to catch), a single
            // GET would have destroyed the store, and no guard on the write
            // side would have seen it coming.
            //
            // The engram server fixed this same class of bug on 2026-07-21 by
            // routing exports to a dotted sidecar; the soul kept the original
            // pattern. Same fix here: write the export where only an export
            // lives. It also stops a 60MB serialize-and-reread on every GET of
            // a debug endpoint.
            let export_path: String = env("HOME") + "/.neuron/engram/.soul-edges-export.json"
            engram_save(export_path)
            let snap: String = fs_read(export_path)
            let edges_raw: String = json_get_raw(snap, "edges")
            return if str_eq(edges_raw, "") { "[]" } else { edges_raw }
        }
        if str_eq(clean, "/api/chat") {
            // GET /api/chat: pass through layered_cycle for consistency with POST path.
            // GET chat is a legacy probe interface; body may be empty for simple pings.
            let raw_msg: String = json_get(body, "message")
            let eff_msg: String = if str_eq(raw_msg, "") { body } else { raw_msg }
            if str_eq(eff_msg, "") {
                return "{\"error\":\"message is required\",\"code\":\"missing_param\"}"
            }
            let agentic_flag: Bool = json_get_bool(body, "agentic")
            let req_mode: String = json_get(body, "mode")
            let reply: String = if str_eq(req_mode, "plan") {
                handle_chat_plan(body)
            } else if agentic_flag {
                handle_chat_agentic(body)
            } else {
                let screened_reply: String = layered_cycle(eff_msg)
                screened_reply
            }
            auto_persist(body, reply)
            return reply
        }
        if str_eq(clean, "/api/conversations") {
            return handle_conversations(method)
        }
        if str_eq(clean, "/api/config") {
            return handle_config(method, body)
        }
        if str_starts_with(clean, "/api/tools/") {
            return handle_tool(clean, method, body)
        }
        if str_starts_with(clean, "/api/dharma") {
            return handle_dharma(clean, method, body)
        }
        if str_starts_with(clean, "/api/nlg") {
            return handle_nlg(clean, method, body)
        }
        if str_starts_with(clean, "/api/memories") {
            return axon_get(clean)
        }
        if str_starts_with(clean, "/api/knowledge") {
            return axon_get(clean)
        }
        if str_starts_with(clean, "/api/backlog") {
            return axon_get(clean)
        }
        if str_starts_with(clean, "/api/artifacts") {
            return axon_get(clean)
        }
        if str_starts_with(clean, "/api/projects") {
            return axon_get(clean)
        }
        if str_starts_with(clean, "/api/imprints") {
            return axon_get(clean)
        }
        if str_eq(clean, "/") {
            return render_studio()
        }
        // Neuron cognitive API — GET endpoints
        if str_eq(clean, "/api/neuron/session/begin") {
            return handle_api_begin_session("")
        }
        if str_eq(clean, "/api/neuron/ctx") {
            return handle_api_compile_ctx("")
        }
        if str_eq(clean, "/api/safety-contact") {
            return handle_safety_contact_get()
        }
        if str_starts_with(clean, "/api/neuron/knowledge/search") {
            return handle_api_search_knowledge(method, path, body)
        }
        if str_eq(clean, "/api/neuron/knowledge") {
            return handle_api_browse_knowledge(path, body)
        }
        if str_starts_with(clean, "/api/neuron/processes") {
            return handle_api_browse_processes(method, path, body)
        }
        if str_starts_with(clean, "/api/neuron/state-events") {
            return handle_api_list_state_events(method, path, body)
        }
        if str_starts_with(clean, "/api/neuron/config") {
            return handle_api_inspect_config(path, body)
        }
        if str_starts_with(clean, "/api/neuron/graph") {
            return handle_api_inspect_graph(method, path, body)
        }
        if str_starts_with(clean, "/api/neuron/list/") {
            // Offset 17 = len("/api/neuron/list/"). Was 16, which left a leading "/" on node_type
            // ("/BacklogItem"), so engram_scan_nodes_by_type_json matched nothing → list/<type>
            // returned [] for EVERY type (broke backlog/typed-node listing app- and tool-wide).
            let node_type: String = str_slice(clean, 17, str_len(clean))
            return handle_api_list_typed(node_type, path, body)
        }
        if str_starts_with(clean, "/api/neuron/recall") {
            return handle_api_recall(method, path, body)
        }
        if str_starts_with(clean, "/api/connectors") {
            return handle_connectors(method, clean, body)
        }
        // GET /api/run-progress/:session_id — live agentic-run ledger (2026-07-13,
        // narrated-runs). agentic_loop appends one {"i","t","tool"} entry per round
        // (the model's own pre-tool narration); a {"done":true} entry closes the run.
        // Clients poll this during a run to render live step updates without streaming.
        if str_starts_with(clean, "/api/run-progress/") {
            let rp_id: String = str_slice(clean, 18, str_len(clean))
            if !str_eq(rp_id, "") {
                let rp_raw: String = state_get("run_progress_" + rp_id)
                let rp_arr: String = if str_eq(rp_raw, "") { "[]" } else { "[" + rp_raw + "]" }
                return "{\"progress\":" + rp_arr + "}"
            }
        }
        // GET /api/sessions — list all sessions
        if str_eq(clean, "/api/sessions") {
            return session_list()
        }
        // GET /api/sessions/:id — get session metadata + history
        if str_starts_with(clean, "/api/sessions/") {
            let gs_after: String = str_slice(clean, 14, str_len(clean))
            let gs_slash: Int = str_index_of(gs_after, "/")
            let gs_id: String = if gs_slash < 0 { gs_after } else { str_slice(gs_after, 0, gs_slash) }
            if !str_eq(gs_id, "") {
                return session_get(gs_id)
            }
        }
        return err_404(clean)
    }

    if str_eq(method, "POST") {
        // POST /api/sessions — create new session
        if str_eq(clean, "/api/sessions") {
            return session_create(body)
        }
        // MCP tool-bridge resume: POST /api/sessions/{id}/tool_result
        // The client executed a tool the soul could not run in-process (an MCP
        // connector/plugin) and posts the result back here so the agentic loop
        // continues. {id} is the session_id from the prior tool_pending envelope.
        if str_starts_with(clean, "/api/sessions/") && str_ends_with(clean, "/tool_result") {
            let after: String = str_slice(clean, 14, str_len(clean))
            let slash: Int = str_index_of(after, "/")
            let session_id: String = if slash < 0 { after } else { str_slice(after, 0, slash) }
            return handle_tool_result(session_id, body)
        }
        // POST /api/sessions/:id/approve — user approval for a pending agentic tool call
        if str_starts_with(clean, "/api/sessions/") {
            let sess_after: String = str_slice(clean, 14, str_len(clean))
            let sess_slash: Int = str_index_of(sess_after, "/")
            let sess_id: String = if sess_slash < 0 { sess_after } else { str_slice(sess_after, 0, sess_slash) }
            let sess_sub: String = if sess_slash < 0 { "" } else { str_slice(sess_after, sess_slash + 1, str_len(sess_after)) }
            if !str_eq(sess_id, "") && str_eq(sess_sub, "approve") {
                return handle_session_approve(sess_id, body)
            }
        }
        if str_eq(clean, "/imprint/contextual") {
            return route_imprint_contextual(body)
        }
        if str_eq(clean, "/imprint/user") {
            return route_imprint_user(body)
        }
        if str_eq(clean, "/synthesize") {
            return route_synthesize(body)
        }
        if str_eq(clean, "/api/elp/chat") {
            return handle_elp_chat(body)
        }
        if str_eq(clean, "/api/chat") {
            // NOTE: streaming (SSE / chunked transfer) is not implemented. All chat
            // responses are buffered and returned as a single JSON object. Streaming
            // would require runtime-level SSE support in el_runtime.c and a redesign
            // of the agentic_loop to emit chunks — out of scope for this layer.
            let raw_msg: String = json_get(body, "message")
            if str_eq(raw_msg, "") {
                return "{\"error\":\"message is required\",\"code\":\"missing_param\"}"
            }
            let agentic_flag: Bool = json_get_bool(body, "agentic")
            let req_mode: String = json_get(body, "mode")
            let reply: String = if str_eq(req_mode, "plan") {
                handle_chat_plan(body)
            } else if agentic_flag {
                handle_chat_agentic(body)
            } else {
                let screened_reply: String = layered_cycle(raw_msg)
                screened_reply
            }
            auto_persist(body, reply)
            return reply
        }
        if str_eq(clean, "/api/see") {
            return handle_see(body)
        }
        if str_eq(clean, "/api/conversations") {
            return handle_conversations(method)
        }
        if str_eq(clean, "/api/config") {
            return handle_config(method, body)
        }
        if str_starts_with(clean, "/api/tools/") {
            return handle_tool(clean, method, body)
        }
        if str_starts_with(clean, "/api/dharma") {
            return handle_dharma(clean, method, body)
        }
        if str_starts_with(clean, "/api/nlg") {
            return handle_nlg(clean, method, body)
        }
        if str_starts_with(clean, "/api/memories") {
            return axon_post(clean, body)
        }
        if str_starts_with(clean, "/api/knowledge") {
            return axon_post(clean, body)
        }
        if str_starts_with(clean, "/api/backlog") {
            return axon_post(clean, body)
        }
        if str_starts_with(clean, "/api/artifacts") {
            return axon_post(clean, body)
        }
        if str_starts_with(clean, "/api/projects") {
            return axon_post(clean, body)
        }
        if str_starts_with(clean, "/api/imprints") {
            return axon_post(clean, body)
        }
        // Neuron cognitive API — POST endpoints
        if str_eq(clean, "/api/neuron/session/begin") {
            return handle_api_begin_session(body)
        }
        if str_eq(clean, "/api/neuron/ctx") {
            return handle_api_compile_ctx(body)
        }
        if str_eq(clean, "/api/neuron/knowledge/search") {
            return handle_api_search_knowledge(method, path, body)
        }
        if str_eq(clean, "/api/neuron/knowledge/capture") {
            return handle_api_capture_knowledge(body)
        }
        if str_eq(clean, "/api/neuron/knowledge/evolve") {
            return handle_api_evolve_knowledge(body)
        }
        if str_eq(clean, "/api/neuron/knowledge/promote") {
            return handle_api_promote_knowledge(body)
        }
        if str_eq(clean, "/api/neuron/processes") {
            return handle_api_browse_processes(method, path, body)
        }
        if str_eq(clean, "/api/neuron/processes/define") {
            return handle_api_define_process(body)
        }
        if str_eq(clean, "/api/neuron/state-events") {
            return handle_api_log_state_event(body)
        }
        if str_eq(clean, "/api/neuron/config") {
            return handle_api_inspect_config(path, body)
        }
        if str_eq(clean, "/api/neuron/config/tune") {
            return handle_api_tune_config(body)
        }
        if str_eq(clean, "/api/neuron/graph") {
            return handle_api_inspect_graph(method, path, body)
        }
        if str_eq(clean, "/api/neuron/graph/link") {
            return handle_api_link_entities(body)
        }
        if str_eq(clean, "/api/neuron/memory") {
            return handle_api_remember(body)
        }
        if str_eq(clean, "/api/safety-contact") {
            return handle_safety_contact_post(body)
        }
        if str_eq(clean, "/api/neuron/node/create") {
            return handle_api_node_create(body)
        }
        if str_eq(clean, "/api/neuron/node/update") {
            return handle_api_node_update(body)
        }
        if str_eq(clean, "/api/neuron/node/delete") {
            return handle_api_node_delete(body)
        }
        if str_eq(clean, "/api/neuron/memory/evolve") {
            return handle_api_evolve_memory(body)
        }
        if str_eq(clean, "/api/neuron/memory/forget") {
            return handle_api_forget(body)
        }
        if str_eq(clean, "/api/neuron/memory/delete") {
            return handle_api_memory_delete(body)
        }
        if str_eq(clean, "/api/neuron/memory/update") {
            return handle_api_memory_update(body)
        }
        if str_eq(clean, "/api/neuron/recall") {
            return handle_api_recall(method, path, body)
        }
        if str_eq(clean, "/api/neuron/consolidate") {
            return handle_api_consolidate(body)
        }
        if str_eq(clean, "/api/neuron/cultivate") {
            return handle_api_cultivate(body)
        }
        if str_starts_with(clean, "/api/connectors") {
            return handle_connectors(method, clean, body)
        }
        return err_404(clean)
    }

    if str_eq(method, "DELETE") {
        // DELETE /api/sessions/:id — delete a session and its history
        if str_starts_with(clean, "/api/sessions/") {
            let del_after: String = str_slice(clean, 14, str_len(clean))
            let del_slash: Int = str_index_of(del_after, "/")
            let del_id: String = if del_slash < 0 { del_after } else { str_slice(del_after, 0, del_slash) }
            if !str_eq(del_id, "") {
                return session_delete(del_id)
            }
        }
        return err_404(clean)
    }

    if str_eq(method, "PATCH") {
        // PATCH /api/sessions/:id — update session title and/or folder
        if str_starts_with(clean, "/api/sessions/") {
            let patch_after: String = str_slice(clean, 14, str_len(clean))
            let patch_slash: Int = str_index_of(patch_after, "/")
            let patch_id: String = if patch_slash < 0 { patch_after } else { str_slice(patch_after, 0, patch_slash) }
            if !str_eq(patch_id, "") {
                return session_update_patch(patch_id, body)
            }
        }
        return err_404(clean)
    }

    return err_405(method, clean)
}
