// morphology-he.el - Hebrew morphology for the NLG engine.
//                    עברית — עיצוב מורפולוגי למנוע ייצור שפה טבעית
//
// Implements Modern Hebrew verb conjugation (Pa'al binyan, participle-based
// present tense), noun pluralization, and definite-article prefixing.
//
// Hebrew is a Semitic language with a trilateral root system shared with
// Arabic.  Like Arabic, words are built from three-consonant roots by
// applying vowel patterns (mishkalim) around the root.
//
// Modern Hebrew (the target) profile:
//   code=he, name=Hebrew, morph_type=semitic, word_order=SVO,
//   question_strategy=intonation, script=hebrew, family=semitic
//
// Key grammatical facts:
//   - Grammatical gender:  masculine (m) / feminine (f)
//   - Number: singular / plural (dual exists but is marginal in Modern Hebrew)
//   - Verbs: built from 3-letter roots via binyanim (verb patterns)
//     Pa'al (פָּעַל) is covered here — the most common pattern for everyday verbs
//   - Present tense is participle-based (בינוני / binyan) with gender/number
//     agreement suffixes on the verb; it doubles as an adjective form
//   - Copula: present tense uses zero copula (omit "to be" entirely);
//     past tense uses היה/הייתה/היו (haya/hayta/hayu)
//   - Definite article: prefix ה (ha-) attached directly to the noun;
//     consonant doubling after ה is simplified to just "ha" prefix here
//   - Questions: rising intonation (no morphological change); optional
//     particle האם (ha'im) at sentence start; this engine uses intonation
//     strategy (question mark added by realizer)
//   - Script: Hebrew Unicode (right-to-left).  The El runtime currently
//     outputs non-ASCII as numeric hashes (runtime limitation), but str_eq
//     and string literals work correctly internally.  When the VM adds UTF-8
//     output support, all Hebrew strings will display correctly automatically.
//
// Verbs covered (by infinitive, transliterated and Hebrew):
//   "lihyot"   / לִהְיוֹת  — to be   (copula, zero-present, haya-past)
//   "haya"     / הָיָה     — to be   (dictionary alias → lihyot)
//   "be"                   — English canonical → lihyot
//   "lir'ot"   / לִרְאוֹת  — to see
//   "le'exol"  / לֶאֱכוֹל  — to eat
//   "ledaber"  / לְדַבֵּר  — to speak
//   "lalechet" / לָלֶכֶת  — to go
//
// Conventions used throughout:
//   person:  "first" | "second" | "third"
//   gender:  "m" | "f"
//   number:  "singular" | "plural"
//   tense:   "present" | "past" | "future"
//
// Depends on: morphology.el (str_eq, str_len, str_slice, str_ends_with,
//             str_drop_last, str_concat/+)

// ── String helpers ─────────────────────────────────────────────────────────────

fn he_str_ends(s: String, suf: String) -> Bool {
    return str_ends_with(s, suf)
}

fn he_str_len(s: String) -> Int {
    return str_len(s)
}

fn he_str_drop_last(s: String, n: Int) -> String {
    let len: Int = str_len(s)
    if n >= len {
        return ""
    }
    return str_slice(s, 0, len - n)
}

fn he_str_last_char(s: String) -> String {
    let n: Int = str_len(s)
    if n == 0 {
        return ""
    }
    return str_slice(s, n - 1, n)
}

// ── Slot index ─────────────────────────────────────────────────────────────────
//
// Maps person × gender × number to a 0-based slot for table lookups.
// Modern Hebrew uses 12 paradigm cells (3 persons × 2 genders × 2 numbers),
// but first person is gender-neutral in Modern Hebrew for verbs, so we
// collapse 1s-m and 1s-f to the same slot, and likewise 1p.
//
// Slot layout:
//   0  = 3ms  (הוא  hu   — he)
//   1  = 3fs  (היא  hi   — she)
//   2  = 2ms  (אתה  ata  — you m sg)
//   3  = 2fs  (את   at   — you f sg)
//   4  = 1s   (אני  ani  — I, gender-neutral in Modern Hebrew)
//   5  = 3mp  (הם   hem  — they m pl)
//   6  = 3fp  (הן   hen  — they f pl)
//   7  = 2mp  (אתם  atem — you m pl)
//   8  = 2fp  (אתן  aten — you f pl)
//   9  = 1p   (אנחנו anakhnu — we, gender-neutral)

fn he_slot(person: String, gender: String, number: String) -> Int {
    if str_eq(person, "third") {
        if str_eq(number, "singular") {
            if str_eq(gender, "f") { return 1 }
            return 0
        }
        // plural
        if str_eq(gender, "f") { return 6 }
        return 5
    }
    if str_eq(person, "second") {
        if str_eq(number, "singular") {
            if str_eq(gender, "f") { return 3 }
            return 2
        }
        // plural
        if str_eq(gender, "f") { return 8 }
        return 7
    }
    // first person — gender-neutral in Modern Hebrew verb conjugation
    if str_eq(number, "plural") { return 9 }
    return 4
}

// ── Present-tense (participle / binyan) agreement suffixes ────────────────────
//
// Modern Hebrew present tense is built from the Pa'al participle stem.
// The participle agrees with the subject in gender and number.
//
// For Pa'al (CoCeC pattern), the present-tense forms are:
//   Masc sg:   base participle stem (e.g. רוֹאֶה ro'e — sees)  [no suffix]
//   Fem  sg:   stem + ת (-t / -et)  depending on root
//   Masc pl:   stem + ים (-im)      (often with vowel change in the root)
//   Fem  pl:   stem + ות (-ot)
//
// Rather than attempting to derive these from the root (which requires knowing
// the full vowel pattern), we store the four present-tense forms explicitly
// for each covered verb.  This is the standard approach for a finite NLG
// system covering a curated verb set.
//
// Present forms are indexed by a 2-bit form code:
//   0 = masc sg   (ms)
//   1 = fem  sg   (fs)
//   2 = masc pl   (mp)
//   3 = fem  pl   (fp)

fn he_present_form_code(slot: Int) -> Int {
    // Slots 0, 2, 4, 7 → masc sg form (1s and 2ms use same form as 3ms)
    if slot == 0 { return 0 }   // 3ms
    if slot == 1 { return 1 }   // 3fs
    if slot == 2 { return 0 }   // 2ms → masc sg
    if slot == 3 { return 1 }   // 2fs → fem  sg
    if slot == 4 { return 0 }   // 1s  → masc sg (gender-neutral, default masc)
    if slot == 5 { return 2 }   // 3mp → masc pl
    if slot == 6 { return 3 }   // 3fp → fem  pl
    if slot == 7 { return 2 }   // 2mp → masc pl
    if slot == 8 { return 3 }   // 2fp → fem  pl
    return 2                    // 1p  (slot 9) → masc pl (gender-neutral default)
}

// ── Copula: היה haya — to be ──────────────────────────────────────────────────
//
// Present copula: ZERO (omitted from surface form).
// Past copula:    היה haya (3ms), הייתה hayta (3fs/2fs), היו hayu (3pl),
//                 הייתי hayiti (1s), הייתם hayitem (2mp), הייתן hayiten (2fp),
//                 היינו hayinu (1p), היית hayita (2ms).
// Future copula:  יהיה yihye (3ms), תהיה tihye (3fs/2), אהיה ehye (1s),
//                 יהיו yihyu (3pl/2pl), נהיה nihye (1p) — included for completeness.

fn he_copula_past(slot: Int) -> String {
    if slot == 0 { return "היה" }       // 3ms  haya
    if slot == 1 { return "הייתה" }     // 3fs  hayta
    if slot == 2 { return "היית" }      // 2ms  hayita
    if slot == 3 { return "הייתה" }     // 2fs  hayta (same as 3fs in Modern Hebrew)
    if slot == 4 { return "הייתי" }     // 1s   hayiti
    if slot == 5 { return "היו" }       // 3mp  hayu
    if slot == 6 { return "היו" }       // 3fp  hayu  (same as 3mp in Modern Hebrew)
    if slot == 7 { return "הייתם" }     // 2mp  hayitem
    if slot == 8 { return "הייתן" }     // 2fp  hayiten
    return "היינו"                       // 1p   hayinu
}

fn he_copula_future(slot: Int) -> String {
    if slot == 0 { return "יהיה" }      // 3ms  yihye
    if slot == 1 { return "תהיה" }      // 3fs  tihye
    if slot == 2 { return "תהיה" }      // 2ms  tihye
    if slot == 3 { return "תהיי" }      // 2fs  tihyi
    if slot == 4 { return "אהיה" }      // 1s   ehye
    if slot == 5 { return "יהיו" }      // 3mp  yihyu
    if slot == 6 { return "יהיו" }      // 3fp  yihyu
    if slot == 7 { return "תהיו" }      // 2mp  tihyu
    if slot == 8 { return "תהיו" }      // 2fp  tihyu
    return "נהיה"                        // 1p   nihye
}

// he_is_copula: detect whether the input verb means "to be".
fn he_is_copula(verb: String) -> Bool {
    if str_eq(verb, "lihyot")  { return true }
    if str_eq(verb, "haya")    { return true }
    if str_eq(verb, "be")      { return true }
    if str_eq(verb, "היה")     { return true }
    if str_eq(verb, "לִהְיוֹת") { return true }
    return false
}

// he_conjugate_copula: conjugate the copula for the given tense/slot.
fn he_conjugate_copula(tense: String, slot: Int) -> String {
    // Present copula: zero in Modern Hebrew
    if str_eq(tense, "present") { return "" }
    if str_eq(tense, "past")    { return he_copula_past(slot) }
    if str_eq(tense, "future")  { return he_copula_future(slot) }
    // Default: zero copula
    return ""
}

// ── Pa'al present-tense forms: verb-by-verb table ─────────────────────────────
//
// Each verb stores four present-tense participle forms:
//   [masc sg, fem sg, masc pl, fem pl]
// indexed by he_present_form_code(slot).
//
// Transliterations for reference:
//   lir'ot   (לִרְאוֹת  — to see):   ro'e / ro'a / ro'im / ro'ot
//   le'exol  (לֶאֱכוֹל — to eat):   oxel / oxelet / oxlim / oxlot
//   ledaber  (לְדַבֵּר — to speak): medaber / medaberet / medabrim / medabrot
//   lalechet (לָלֶכֶת  — to go):    holech / holechet / holchim / holchot

fn he_present_lir_ot(form: Int) -> String {
    if form == 0 { return "רוֹאֶה" }    // ro'e    — masc sg
    if form == 1 { return "רוֹאָה" }    // ro'a    — fem  sg
    if form == 2 { return "רוֹאִים" }   // ro'im   — masc pl
    return "רוֹאוֹת"                     // ro'ot   — fem  pl (form == 3)
}

fn he_present_le_exol(form: Int) -> String {
    if form == 0 { return "אוֹכֵל" }    // oxel    — masc sg
    if form == 1 { return "אוֹכֶלֶת" }  // oxelet  — fem  sg
    if form == 2 { return "אוֹכְלִים" }  // oxlim   — masc pl
    return "אוֹכְלוֹת"                   // oxlot   — fem  pl
}

fn he_present_ledaber(form: Int) -> String {
    if form == 0 { return "מְדַבֵּר" }   // medaber    — masc sg
    if form == 1 { return "מְדַבֶּרֶת" } // medaberet  — fem  sg
    if form == 2 { return "מְדַבְּרִים" } // medabrim   — masc pl
    return "מְדַבְּרוֹת"                  // medabrot   — fem  pl
}

fn he_present_lalechet(form: Int) -> String {
    if form == 0 { return "הוֹלֵךְ" }   // holech     — masc sg
    if form == 1 { return "הוֹלֶכֶת" }  // holechet   — fem  sg
    if form == 2 { return "הוֹלְכִים" }  // holchim    — masc pl
    return "הוֹלְכוֹת"                   // holchot    — fem  pl
}

// ── Pa'al past-tense forms: verb-by-verb table ───────────────────────────────
//
// Past tense in Pa'al uses suffixes on a past stem (the 3ms form is the stem).
// Suffix pattern (slot → suffix appended to stem consonants):
//   slot 0 (3ms):  base (e.g. ראה ra'a)
//   slot 1 (3fs):  -ta  (ראתה ra'ata)
//   slot 2 (2ms):  -ta  (ראית ra'ita)
//   slot 3 (2fs):  -t   (ראית ra'it — same spelling as 2ms in Modern Hebrew)
//   slot 4 (1s):   -ti  (ראיתי ra'iti)
//   slot 5 (3mp):  -u   (ראו ra'u)
//   slot 6 (3fp):  -u   (ראו ra'u — same as 3mp in Modern Hebrew)
//   slot 7 (2mp):  -tem (ראיתם ra'item)
//   slot 8 (2fp):  -ten (ראיתן ra'iten)
//   slot 9 (1p):   -nu  (ראינו ra'inu)
//
// We store full past paradigms for each verb — suffix application to the base
// requires knowing each verb's past stem vowel pattern.

fn he_past_lir_ot(slot: Int) -> String {
    if slot == 0 { return "רָאָה" }     // ra'a    — 3ms
    if slot == 1 { return "רָאֲתָה" }   // ra'ata  — 3fs
    if slot == 2 { return "רָאִיתָ" }   // ra'ita  — 2ms
    if slot == 3 { return "רָאִית" }    // ra'it   — 2fs
    if slot == 4 { return "רָאִיתִי" }  // ra'iti  — 1s
    if slot == 5 { return "רָאוּ" }     // ra'u    — 3mp
    if slot == 6 { return "רָאוּ" }     // ra'u    — 3fp
    if slot == 7 { return "רְאִיתֶם" }  // re'item — 2mp
    if slot == 8 { return "רְאִיתֶן" }  // re'iten — 2fp
    return "רָאִינוּ"                    // ra'inu  — 1p
}

fn he_past_le_exol(slot: Int) -> String {
    if slot == 0 { return "אָכַל" }     // axal    — 3ms
    if slot == 1 { return "אָכְלָה" }   // axla    — 3fs
    if slot == 2 { return "אָכַלְתָּ" } // axalta  — 2ms
    if slot == 3 { return "אָכַלְתְּ" } // axalt   — 2fs
    if slot == 4 { return "אָכַלְתִּי" }// axalti  — 1s
    if slot == 5 { return "אָכְלוּ" }   // axlu    — 3mp
    if slot == 6 { return "אָכְלוּ" }   // axlu    — 3fp
    if slot == 7 { return "אֲכַלְתֶּם" }// axaltem — 2mp
    if slot == 8 { return "אֲכַלְתֶּן" }// axalten — 2fp
    return "אָכַלְנוּ"                  // axalnu  — 1p
}

fn he_past_ledaber(slot: Int) -> String {
    if slot == 0 { return "דִּבֵּר" }   // diber   — 3ms  (Pi'el past)
    if slot == 1 { return "דִּבְּרָה" } // dibra   — 3fs
    if slot == 2 { return "דִּבַּרְתָּ" }// dibarta — 2ms
    if slot == 3 { return "דִּבַּרְתְּ" }// dibart  — 2fs
    if slot == 4 { return "דִּבַּרְתִּי" }// diberti — 1s
    if slot == 5 { return "דִּבְּרוּ" } // dibru   — 3mp
    if slot == 6 { return "דִּבְּרוּ" } // dibru   — 3fp
    if slot == 7 { return "דִּבַּרְתֶּם" }// dibertem— 2mp
    if slot == 8 { return "דִּבַּרְתֶּן" }// dibertn — 2fp
    return "דִּבַּרְנוּ"                 // dibernu — 1p
}

fn he_past_lalechet(slot: Int) -> String {
    if slot == 0 { return "הָלַךְ" }    // halax   — 3ms
    if slot == 1 { return "הָלְכָה" }   // halxa   — 3fs
    if slot == 2 { return "הָלַכְתָּ" } // halaxta — 2ms
    if slot == 3 { return "הָלַכְתְּ" } // halaxt  — 2fs
    if slot == 4 { return "הָלַכְתִּי" }// halaxti — 1s
    if slot == 5 { return "הָלְכוּ" }   // halxu   — 3mp
    if slot == 6 { return "הָלְכוּ" }   // halxu   — 3fp
    if slot == 7 { return "הֲלַכְתֶּם" }// halaxtem— 2mp
    if slot == 8 { return "הֲלַכְתֶּן" }// halaxten— 2fp
    return "הָלַכְנוּ"                  // halaxnu — 1p
}

// ── Future-tense forms: verb-by-verb table ─────────────────────────────────────
//
// Future tense in Pa'al uses prefix + root + suffix (yiqtol pattern).
// We store full paradigms for each covered verb.

fn he_future_lir_ot(slot: Int) -> String {
    if slot == 0 { return "יִרְאֶה" }   // yir'e   — 3ms
    if slot == 1 { return "תִּרְאֶה" }  // tir'e   — 3fs
    if slot == 2 { return "תִּרְאֶה" }  // tir'e   — 2ms
    if slot == 3 { return "תִּרְאִי" }  // tir'i   — 2fs
    if slot == 4 { return "אֶרְאֶה" }   // er'e    — 1s
    if slot == 5 { return "יִרְאוּ" }   // yir'u   — 3mp
    if slot == 6 { return "תִּרְאֶינָה" }// tir'ena — 3fp
    if slot == 7 { return "תִּרְאוּ" }  // tir'u   — 2mp
    if slot == 8 { return "תִּרְאֶינָה" }// tir'ena — 2fp
    return "נִרְאֶה"                     // nir'e   — 1p
}

fn he_future_le_exol(slot: Int) -> String {
    if slot == 0 { return "יֹאכַל" }    // yoxal   — 3ms
    if slot == 1 { return "תֹּאכַל" }   // toxal   — 3fs
    if slot == 2 { return "תֹּאכַל" }   // toxal   — 2ms
    if slot == 3 { return "תֹּאכְלִי" } // toxli   — 2fs
    if slot == 4 { return "אֹכַל" }     // oxal    — 1s
    if slot == 5 { return "יֹאכְלוּ" }  // yoxlu   — 3mp
    if slot == 6 { return "תֹּאכַלְנָה" }// toxalna — 3fp
    if slot == 7 { return "תֹּאכְלוּ" } // toxlu   — 2mp
    if slot == 8 { return "תֹּאכַלְנָה" }// toxalna — 2fp
    return "נֹאכַל"                      // noxal   — 1p
}

fn he_future_ledaber(slot: Int) -> String {
    if slot == 0 { return "יְדַבֵּר" }  // yedaber  — 3ms
    if slot == 1 { return "תְּדַבֵּר" } // tedaber  — 3fs
    if slot == 2 { return "תְּדַבֵּר" } // tedaber  — 2ms
    if slot == 3 { return "תְּדַבְּרִי" }// tedabri  — 2fs
    if slot == 4 { return "אֲדַבֵּר" }  // adaber   — 1s
    if slot == 5 { return "יְדַבְּרוּ" }// yedabru  — 3mp
    if slot == 6 { return "תְּדַבֵּרְנָה" }// tedaberna — 3fp
    if slot == 7 { return "תְּדַבְּרוּ" }// tedabru  — 2mp
    if slot == 8 { return "תְּדַבֵּרְנָה" }// tedaberna — 2fp
    return "נְדַבֵּר"                    // nedaber  — 1p
}

fn he_future_lalechet(slot: Int) -> String {
    if slot == 0 { return "יֵלֵךְ" }    // yelex    — 3ms
    if slot == 1 { return "תֵּלֵךְ" }   // telex    — 3fs
    if slot == 2 { return "תֵּלֵךְ" }   // telex    — 2ms
    if slot == 3 { return "תֵּלְכִי" }  // telxi    — 2fs
    if slot == 4 { return "אֵלֵךְ" }    // elex     — 1s
    if slot == 5 { return "יֵלְכוּ" }   // yelxu    — 3mp
    if slot == 6 { return "תֵּלַכְנָה" } // telaxna  — 3fp
    if slot == 7 { return "תֵּלְכוּ" }  // telxu    — 2mp
    if slot == 8 { return "תֵּלַכְנָה" } // telaxna  — 2fp
    return "נֵלֵךְ"                      // nelex    — 1p
}

// ── Known-verb dispatcher ─────────────────────────────────────────────────────
//
// he_known_verb: return the inflected form for a known verb, or "" if the
// verb is not in the lookup table.  Accepts both transliterated and Hebrew
// script infinitives.

fn he_known_verb(verb: String, tense: String, slot: Int) -> String {
    // ── lir'ot / לִרְאוֹת — to see ───────────────────────────────────────────
    if str_eq(verb, "lir'ot") {
        if str_eq(tense, "present") { return he_present_lir_ot(he_present_form_code(slot)) }
        if str_eq(tense, "past")    { return he_past_lir_ot(slot) }
        if str_eq(tense, "future")  { return he_future_lir_ot(slot) }
        return he_present_lir_ot(he_present_form_code(slot))
    }
    if str_eq(verb, "לִרְאוֹת") {
        if str_eq(tense, "present") { return he_present_lir_ot(he_present_form_code(slot)) }
        if str_eq(tense, "past")    { return he_past_lir_ot(slot) }
        if str_eq(tense, "future")  { return he_future_lir_ot(slot) }
        return he_present_lir_ot(he_present_form_code(slot))
    }

    // ── le'exol / לֶאֱכוֹל — to eat ──────────────────────────────────────────
    if str_eq(verb, "le'exol") {
        if str_eq(tense, "present") { return he_present_le_exol(he_present_form_code(slot)) }
        if str_eq(tense, "past")    { return he_past_le_exol(slot) }
        if str_eq(tense, "future")  { return he_future_le_exol(slot) }
        return he_present_le_exol(he_present_form_code(slot))
    }
    if str_eq(verb, "לֶאֱכוֹל") {
        if str_eq(tense, "present") { return he_present_le_exol(he_present_form_code(slot)) }
        if str_eq(tense, "past")    { return he_past_le_exol(slot) }
        if str_eq(tense, "future")  { return he_future_le_exol(slot) }
        return he_present_le_exol(he_present_form_code(slot))
    }

    // ── ledaber / לְדַבֵּר — to speak ────────────────────────────────────────
    if str_eq(verb, "ledaber") {
        if str_eq(tense, "present") { return he_present_ledaber(he_present_form_code(slot)) }
        if str_eq(tense, "past")    { return he_past_ledaber(slot) }
        if str_eq(tense, "future")  { return he_future_ledaber(slot) }
        return he_present_ledaber(he_present_form_code(slot))
    }
    if str_eq(verb, "לְדַבֵּר") {
        if str_eq(tense, "present") { return he_present_ledaber(he_present_form_code(slot)) }
        if str_eq(tense, "past")    { return he_past_ledaber(slot) }
        if str_eq(tense, "future")  { return he_future_ledaber(slot) }
        return he_present_ledaber(he_present_form_code(slot))
    }

    // ── lalechet / לָלֶכֶת — to go ───────────────────────────────────────────
    if str_eq(verb, "lalechet") {
        if str_eq(tense, "present") { return he_present_lalechet(he_present_form_code(slot)) }
        if str_eq(tense, "past")    { return he_past_lalechet(slot) }
        if str_eq(tense, "future")  { return he_future_lalechet(slot) }
        return he_present_lalechet(he_present_form_code(slot))
    }
    if str_eq(verb, "לָלֶכֶת") {
        if str_eq(tense, "present") { return he_present_lalechet(he_present_form_code(slot)) }
        if str_eq(tense, "past")    { return he_past_lalechet(slot) }
        if str_eq(tense, "future")  { return he_future_lalechet(slot) }
        return he_present_lalechet(he_present_form_code(slot))
    }

    // Verb not in table
    return ""
}

// ── Main conjugation entry point ──────────────────────────────────────────────
//
// he_conjugate: conjugate a Hebrew verb.
//
// verb:   infinitive (transliterated or Hebrew script)
// tense:  "present" | "past" | "future"
// person: "first" | "second" | "third"
// gender: "m" | "f"
// number: "singular" | "plural"
//
// Returns:
//   - "" for present copula (zero copula — caller omits the verb)
//   - inflected form for all other cases
//   - the infinitive unchanged for unknown verbs (safe fallback)

fn he_conjugate(verb: String, tense: String, person: String, gender: String, number: String) -> String {
    let slot: Int = he_slot(person, gender, number)

    // Handle copula first
    if he_is_copula(verb) {
        return he_conjugate_copula(tense, slot)
    }

    // Try the known-verb table
    let known: String = he_known_verb(verb, tense, slot)
    if !str_eq(known, "") {
        return known
    }

    // Unknown verb: return the infinitive as a safe placeholder.
    // The caller can detect this when the output equals the input.
    return verb
}

// ── Noun pluralization ─────────────────────────────────────────────────────────
//
// he_pluralize: form the plural of a Hebrew noun.
//
// Rules (simplified for Modern Hebrew):
//   Masculine nouns (and those not ending in -a or -et):
//     Add ים- (-im)
//   Feminine nouns ending in -a (transliteration) or the Hebrew letter ה:
//     Replace final ה with ות (-ot)
//   Feminine nouns ending in -et (transliteration) or ת-:
//     Replace -et / ת with ות (-ot)
//   Fallback:
//     Add ות (-ot) — covers other feminine patterns
//
// Notes:
//   - Many Hebrew nouns have irregular plurals (e.g. ספר/ספרים, בית/בתים).
//     The Engram vocabulary layer should supply these directly.
//   - This function handles the productive, regular pattern.

fn he_pluralize(noun: String, gender: String) -> String {
    if str_eq(gender, "m") {
        // Masculine: add -im
        return noun + "ים"
    }

    // Feminine noun ending in Hebrew ה (he) — most common -a ending in script
    if he_str_ends(noun, "ה") {
        let stem: String = he_str_drop_last(noun, 1)
        return stem + "ות"
    }

    // Feminine noun ending in ת (tav) — covers -et, -at, -it endings
    if he_str_ends(noun, "ת") {
        let stem: String = he_str_drop_last(noun, 1)
        return stem + "ות"
    }

    // Transliteration check: -a ending (e.g. "yalda" → "yaldot")
    if he_str_ends(noun, "a") {
        let stem: String = he_str_drop_last(noun, 1)
        return stem + "ot"
    }

    // Transliteration check: -et ending (e.g. "yaldet" → "yaldot")
    if he_str_ends(noun, "et") {
        let stem: String = he_str_drop_last(noun, 2)
        return stem + "ot"
    }

    // Fallback: add -ot
    return noun + "ות"
}

// ── Definite noun phrases ──────────────────────────────────────────────────────
//
// he_definite_prefix: attach the definite article ה (ha-) to a noun.
//
// The definite article in Hebrew is the prefix ה (ha-) attached directly
// to the noun without a space.  In formal/Biblical Hebrew the following
// consonant receives a dagesh (doubling), but in Modern Hebrew pronunciation
// the doubling is generally not applied.  We implement the simplified form:
//   definite noun = "ה" + noun   (script form)
// For transliterated nouns: "ha" + noun
//
// Callers pass Hebrew script nouns; transliterated nouns are handled by
// checking whether the noun starts with a Hebrew code-point range.

fn he_is_hebrew_script(noun: String) -> Bool {
    // Hebrew Unicode block: U+05D0 (א) through U+05EA (ת).
    // We check the first character: if str_len > 0 and it is a Hebrew letter,
    // the noun is in Hebrew script.  We use a set of common first letters as
    // a heuristic; the alternative (numeric code-point comparison) is not
    // available in El.  This covers the vast majority of practical cases.
    let n: Int = str_len(noun)
    if n == 0 { return false }
    let first: String = str_slice(noun, 0, 1)
    // Common Hebrew first letters in the Unicode block
    if str_eq(first, "א") { return true }
    if str_eq(first, "ב") { return true }
    if str_eq(first, "ג") { return true }
    if str_eq(first, "ד") { return true }
    if str_eq(first, "ה") { return true }
    if str_eq(first, "ו") { return true }
    if str_eq(first, "ז") { return true }
    if str_eq(first, "ח") { return true }
    if str_eq(first, "ט") { return true }
    if str_eq(first, "י") { return true }
    if str_eq(first, "כ") { return true }
    if str_eq(first, "ל") { return true }
    if str_eq(first, "מ") { return true }
    if str_eq(first, "נ") { return true }
    if str_eq(first, "ס") { return true }
    if str_eq(first, "ע") { return true }
    if str_eq(first, "פ") { return true }
    if str_eq(first, "צ") { return true }
    if str_eq(first, "ק") { return true }
    if str_eq(first, "ר") { return true }
    if str_eq(first, "ש") { return true }
    if str_eq(first, "ת") { return true }
    return false
}

fn he_definite_prefix(noun: String) -> String {
    if he_is_hebrew_script(noun) {
        return "ה" + noun
    }
    // Transliterated noun: prepend "ha"
    return "ha" + noun
}

// he_noun_phrase: build a full noun phrase with definiteness and number.
//
// noun:     base (singular) noun string (Hebrew script or transliteration)
// number:   "singular" | "plural"
// gender:   "m" | "f"
// definite: "true" | "false"
//
// Returns the surface noun phrase string.

fn he_noun_phrase(noun: String, number: String, gender: String, definite: String) -> String {
    // Step 1: apply number (pluralize if needed)
    let stem: String = noun
    if str_eq(number, "plural") {
        let stem = he_pluralize(noun, gender)
    }

    // Step 2: apply definiteness
    if str_eq(definite, "true") {
        return he_definite_prefix(stem)
    }
    return stem
}

// ── Canonical verb mapping ─────────────────────────────────────────────────────
//
// he_map_canonical: map cross-lingual canonical English verb labels to
// their Hebrew equivalents before dispatching to he_conjugate.
//
// This mirrors morph_map_canonical in morphology.el but for Hebrew.
// Called by the morphology dispatcher before he_conjugate.
//
// Canonical labels: "be" | "have" | "do" | "go" | "see" | "eat" | "speak"

fn he_map_canonical(verb: String) -> String {
    if str_eq(verb, "be")     { return "lihyot"   }
    if str_eq(verb, "see")    { return "lir'ot"   }
    if str_eq(verb, "eat")    { return "le'exol"  }
    if str_eq(verb, "speak")  { return "ledaber"  }
    if str_eq(verb, "say")    { return "ledaber"  }
    if str_eq(verb, "go")     { return "lalechet" }
    // Unknown canonical: return as-is; he_conjugate will fall back to infinitive
    return verb
}
