// self_region.el — the engram's REAL self/identity region, pulled at query time
// (native el).  This replaces the hardcoded identity anchors and the canned
// "I'm Neuron, the engram you're speaking with." template: the identity LANDING
// signal and the identity READOUT both come from the engram's own Self/identity
// nodes, read through the in-process engram el API.
//
// Port of self_region.py.  The Python module precomputed MiniLM landing vectors;
// here the engram's own store IS the geometry — we pull the self nodes by
// single-term lexical search (the engram search is a single-term matcher, so we
// pool several probes) and rank them by self-signal.  No text is generated; the
// readout is the self nodes' OWN prose, verbatim (SACRED negation survives by
// construction — we never paraphrase, so a negated self-statement stays negated).
//
// ENGRAM el API NOTE: engram_search_json / engram_get_node_json / engram_node_full
// / engram_connect are C runtime builtins.  Their argument order is the C order
// (engram_connect(from, to, weight, relation)), NOT the runtime/engram.el wrapper
// order — we call the builtins directly and never concatenate that wrapper.
//
// Depends on: comprehend (str helpers via runtime), propositions (prop_split_sentences),
//             multilingual (ml_tr), the engram builtins, the json builtins.

// ── single-term self probes (pooled, because engram search is single-term) ────
fn sr_terms() -> [String] {
    let t: [String] = native_list_empty()
    let t = native_list_append(t, "self")
    let t = native_list_append(t, "identity")
    let t = native_list_append(t, "Neuron")
    let t = native_list_append(t, "consciousness")
    let t = native_list_append(t, "values")
    let t = native_list_append(t, "continuous")
    return t
}

// The canonical self-root: content begins "# self" or label is "# self"/"self".
fn sr_is_root(content: String, label: String) -> Bool {
    let lc: String = str_to_lower(content)
    let ll: String = str_to_lower(str_trim(label))
    if str_starts_with(lc, "# self") { return true }
    if str_eq(ll, "# self") { return true }
    if str_eq(ll, "self") { return true }
    return false
}

// How strongly a node belongs to the self/identity region (integer points, to
// avoid el's float-in-`+` pitfalls).  Mirrors _self_score in self_region.py.
fn sr_score(node_json: String) -> Int {
    let content: String = json_get_string(node_json, "content")
    let label: String   = json_get_string(node_json, "label")
    let tags: String    = str_to_lower(json_get_string(node_json, "tags"))
    let low: String     = str_to_lower(content)
    let s: Int = 0
    // identity tags
    if str_contains(tags, "self")            { let s = s + 2 }
    if str_contains(tags, "identity")        { let s = s + 2 }
    if str_contains(tags, "self-model")      { let s = s + 2 }
    if str_contains(tags, "consciousness")   { let s = s + 2 }
    if str_contains(tags, "memory-philosophy") { let s = s + 2 }
    // the named self-traversal root
    if sr_is_root(content, label) { let s = s + 12 }
    if str_contains(low, "who i am")   { let s = s + 3 }
    if str_contains(low, "i am neuron") { let s = s + 3 }
    // softer identity keywords
    if str_contains(low, "my values")  { let s = s + 1 }
    if str_contains(low, "my purpose") { let s = s + 1 }
    if str_contains(low, "identity")   { let s = s + 1 }
    return s
}

// list-contains helper (dedup self-node ids across the pooled probes).
fn sr_ids_has(ids: [String], id: String) -> Bool {
    let n: Int = native_list_len(ids)
    let i: Int = 0
    while i < n {
        if str_eq(native_list_get(ids, i), id) { return true }
        let i = i + 1
    }
    return false
}

// Pull the self nodes: pool every probe's hits, dedupe by id, keep only nodes
// with genuine self-signal (score >= 1).  Returns the node-json strings.
fn sr_pull() -> [String] {
    let terms: [String] = sr_terms()
    let nt: Int = native_list_len(terms)
    let seen: [String] = native_list_empty()
    let out: [String] = native_list_empty()
    let ti: Int = 0
    while ti < nt {
        let term: String = native_list_get(terms, ti)
        let hits: String = engram_search_json(term, 30)
        let hn: Int = json_array_len(hits)
        let hi: Int = 0
        while hi < hn {
            let node: String = json_array_get(hits, hi)
            let id: String = json_get_string(node, "id")
            if !str_eq(id, "") {
                if !sr_ids_has(seen, id) {
                    let seen = native_list_append(seen, id)
                    if sr_score(node) >= 1 {
                        let out = native_list_append(out, node)
                    }
                }
            }
            let hi = hi + 1
        }
        let ti = ti + 1
    }
    return out
}

// Return the single highest-signal self node (the readout seed), or "" if the
// self region is thin/empty.  We keep it O(n) — pick the max-score node, with the
// canonical root strongly favored by sr_score's +12.
fn sr_best_node() -> String {
    let nodes: [String] = sr_pull()
    let n: Int = native_list_len(nodes)
    let best: String = ""
    let best_s: Int = 0
    let i: Int = 0
    while i < n {
        let node: String = native_list_get(nodes, i)
        let s: Int = sr_score(node)
        if s > best_s {
            let best_s = s
            let best = node
        }
        let i = i + 1
    }
    return best
}

fn sr_available() -> Bool {
    if str_eq(sr_best_node(), "") { return false }
    return true
}

// Read out the identity from the REAL self node: lead with the first first-person
// self-statement ("I am Neuron …"), then one more grounded self line if present.
// Verbatim from the node's own prose — no template, negation SACRED.  Falls back
// to the localized identity phrase ONLY if the live pull is empty (logged shape).
fn sr_readout(lang: String) -> String {
    let node: String = sr_best_node()
    if str_eq(node, "") {
        // honest fallback — the self region is unreachable/thin.
        return ml_tr("identity", lang)
    }
    let content: String = json_get_string(node, "content")
    let sents: [String] = prop_split_sentences(content)
    let ns: Int = native_list_len(sents)
    let lead: String = ""
    let second: String = ""
    let i: Int = 0
    while i < ns {
        let raw: String = str_trim(native_list_get(sents, i))
        // strip a leading markdown heading marker
        let s: String = raw
        if str_starts_with(s, "# ") { let s = str_trim(str_slice(s, 2, str_len(s))) }
        let low: String = str_to_lower(s)
        let is_fp: Bool = false
        if str_starts_with(s, "I ")  { let is_fp = true }
        if str_starts_with(s, "I'm") { let is_fp = true }
        if str_contains(low, "i am neuron") { let is_fp = true }
        if is_fp {
            if str_eq(lead, "") {
                let lead = s
            } else {
                if str_eq(second, "") { let second = s }
            }
        }
        let i = i + 1
    }
    if str_eq(lead, "") {
        // no first-person line — read out the first non-empty sentence verbatim.
        if ns > 0 { let lead = str_trim(native_list_get(sents, 0)) }
    }
    if str_eq(lead, "") { return ml_tr("identity", lang) }
    let out: String = lead
    if !str_eq(second, "") { let out = out + " " + second }
    return out
}
