// morphology-gez.el - Ge'ez morphology for the NLG engine.
//                     ግዕዝ — Classical Ethiopic, the liturgical language of the
//                     Ethiopian Orthodox Church and ancestor of Amharic/Tigrinya.
//
// Implements Ge'ez verb conjugation (perfect and imperfect, basic G-stem),
// noun declension (nominative, accusative, construct; singular and plural),
// and noun-phrase construction.
//
// Ge'ez (also: Classical Ethiopic, gǝʿǝz) is the ancient Semitic language
// of the Kingdom of Axum (ca. 300–900 CE active liturgy; ca. 1st century BCE
// epigraphic attestation).  It remains the liturgical language of the
// Ethiopian and Eritrean Orthodox Churches.  Modern Ethiopian Semitic languages
// (Amharic, Tigrinya, Tigre) descend from Ge'ez or a closely related ancestor.
//
// Script: Ge'ez Fidel (ፊደል) — an Ethiopic abugida (Unicode U+1200–U+137F).
// Each Fidel character encodes a consonant + vowel combination (7 orders per
// consonant).  String literals in this file use actual Unicode characters.
//
// NOTE on El runtime: the El VM currently outputs non-ASCII as numeric hashes
// (runtime limitation for non-Latin scripts).  str_eq and string comparisons
// work correctly internally.  When the VM adds full UTF-8 output, all Ge'ez
// strings will display correctly automatically.
//
// Language profile:
//   code=gez, name=Ge'ez, morph_type=semitic, word_order=SOV,
//   script=ethiopic-fidel, family=semitic/south-ethiopic-semitic
//
// Key grammatical facts:
//   - SOV word order — unusual for Semitic (Arabic, Hebrew, Akkadian are VSO);
//     Ge'ez shares SOV with modern Ethiopian Semitic descendants
//   - Semitic trilateral root system (root + vowel pattern = word)
//   - Gender: masculine (default) / feminine (often marked with -t suffix)
//   - Number: singular / plural; dual vestigial
//   - Cases: nominative (unmarked), accusative -a (animate masc nouns),
//     construct/genitive (various; simplified to base form here)
//   - Plural: no single rule; common patterns: -āt (fem/animate), -ān (masc),
//     broken (internal vowel change, unpredictable without lexicon)
//   - Verb system:
//       Perfect (suffix conjugation): completed action
//       Imperfect (prefix conjugation): ongoing / future / habitual
//     Four derived stems: basic (G), causative (ʾa-), intensive (doubling),
//     passive (te-); this file implements basic G-stem throughout
//   - No definite article (unlike Amharic which has suffixed -u/-wa/-itu etc.)
//   - Copula: root kwn (ሆነ honä) — "to be / become"
//
// Verb conjugation conventions:
//   person:  "first" | "second" | "third"
//   gender:  "m" | "f"
//   number:  "singular" | "plural"
//   tense:   "perfect" | "imperfect"
//
// Noun declension conventions:
//   gram_case: "nom" | "acc" | "construct"
//   number:    "singular" | "plural"
//
// Verbs covered (root / Fidel form / transliteration):
//   "kwn"  / ሆነ  (honä)       — to be / become  (copula)
//   "hlw"  / ሀሎ  (hallo)      — to exist / there is
//   "hbl"  / ሰጠ  (säṭṭä)     — to give
//   "rʾy"  / አየ  (ʾayyä)     — to see
//   "qwl"  / ተናገረ (tänagärä) — to speak
//
// Depends on: morphology.el (str_eq, str_len, str_slice, str_ends_with)

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

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

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

fn gez_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)
}

// ── Slot index ─────────────────────────────────────────────────────────────────
//
// Maps person × number to a 0-based slot for table lookups.
// Gender is handled separately for third-person disambiguation.
//
// Slot layout (6 primary cells):
//   0 = 1sg   (I)
//   1 = 2sg   (you sg — gender note: Ge'ez distinguishes 2sg m/f in perfect)
//   2 = 3sg m (he)
//   3 = 3sg f (she)
//   4 = 1pl   (we)
//   5 = 3pl   (they — default masc)

fn gez_slot(person: String, number: String) -> Int {
    if str_eq(person, "first") {
        if str_eq(number, "plural") { return 4 }
        return 0
    }
    if str_eq(person, "second") {
        return 1
    }
    // third
    if str_eq(number, "plural") { return 5 }
    return 2
}

// gez_slot_g: gender-sensitive slot for third-person singular.
fn gez_slot_g(person: String, gender: String, number: String) -> Int {
    let base: Int = gez_slot(person, number)
    if str_eq(person, "third") {
        if str_eq(number, "singular") {
            if str_eq(gender, "f") { return 3 }
        }
    }
    return base
}

// ── Copula: kwn / ሆነ — to be / become ────────────────────────────────────────
//
// Perfect paradigm (suffix forms):
//   3sg m: ሆነ  honä   (base form)
//   3sg f: ሆነት honät  (-t suffix)
//   2sg m: ሆንከ honkä  (-kä suffix)
//   2sg f: ሆንኪ honki  (-ki suffix)
//   1sg:   ሆንኩ honku  (-ku suffix)
//   3pl m: ሆኑ  honu   (-u suffix)
//   3pl f: ሆና  honā   (-ā suffix)
//   2pl:   ሆንክሙ honkǝmu  (-kǝmu suffix)
//   1pl:   ሆንነ honna  (-na suffix)
//
// Imperfect paradigm (prefix forms):
//   3sg m: ይሆን yǝhon   (yǝ- prefix)
//   3sg f: ትሆን tǝhon   (tǝ- prefix)
//   2sg:   ትሆን tǝhon   (tǝ- prefix)
//   1sg:   እሆን ʾǝhon   (ʾǝ- prefix)
//   3pl m: ይሆኑ yǝhonu  (yǝ- + -u suffix)
//   1pl:   ንሆን nǝhon   (nǝ- prefix)

fn gez_kwn_perfect(slot: Int) -> String {
    if slot == 0 { return "ሆንኩ" }       // 1sg   honku
    if slot == 1 { return "ሆንከ" }       // 2sg m  honkä (default; fem: ሆንኪ)
    if slot == 2 { return "ሆነ" }        // 3sg m  honä
    if slot == 3 { return "ሆነት" }       // 3sg f  honät
    if slot == 4 { return "ሆንነ" }       // 1pl   honna
    return "ሆኑ"                          // 3pl   honu
}

fn gez_kwn_imperfect(slot: Int) -> String {
    if slot == 0 { return "እሆን" }       // 1sg   ʾǝhon
    if slot == 1 { return "ትሆን" }       // 2sg   tǝhon
    if slot == 2 { return "ይሆን" }       // 3sg m  yǝhon
    if slot == 3 { return "ትሆን" }       // 3sg f  tǝhon (same prefix as 2sg)
    if slot == 4 { return "ንሆን" }       // 1pl   nǝhon
    return "ይሆኑ"                         // 3pl   yǝhonu
}

fn gez_is_copula(verb: String) -> Bool {
    if str_eq(verb, "kwn")  { return true }
    if str_eq(verb, "ሆነ")   { return true }
    if str_eq(verb, "hona") { return true }
    if str_eq(verb, "be")   { return true }
    return false
}

fn gez_conjugate_copula(tense: String, slot: Int) -> String {
    if str_eq(tense, "imperfect") { return gez_kwn_imperfect(slot) }
    return gez_kwn_perfect(slot)
}

// ── hlw / ሀሎ — to exist / there is ───────────────────────────────────────────
//
// hallo is an existential copula used for "there is/are".
// In Ge'ez it is largely invariant in its classical usage (presentational).
// We provide a minimal paradigm; for existential use, hallo is returned for
// all slots in the "perfect" (existential present).

fn gez_hlw_perfect(slot: Int) -> String {
    // Invariant existential for most purposes
    if slot == 0 { return "ሀሎኩ" }      // 1sg  halloku
    if slot == 1 { return "ሀሎከ" }      // 2sg  hallokä
    if slot == 2 { return "ሀሎ" }       // 3sg m hallo
    if slot == 3 { return "ሀለወት" }     // 3sg f halläwät
    if slot == 4 { return "ሀሎነ" }      // 1pl  hallonä
    return "ሀሉ"                          // 3pl  hallu
}

fn gez_hlw_imperfect(slot: Int) -> String {
    if slot == 0 { return "እሀሉ" }      // 1sg
    if slot == 1 { return "ትሀሉ" }      // 2sg
    if slot == 2 { return "ይሀሉ" }      // 3sg m
    if slot == 3 { return "ትሀሉ" }      // 3sg f
    if slot == 4 { return "ንሀሉ" }      // 1pl
    return "ይሀልዉ"                        // 3pl
}

// ── hbl / ሰጠ — to give ────────────────────────────────────────────────────────
//
// Perfect: säṭṭä (3sg m base); standard G-stem suffix paradigm.
// Imperfect: yǝsäṭ (3sg m).

fn gez_hbl_perfect(slot: Int) -> String {
    if slot == 0 { return "ሰጠኩ" }      // 1sg   säṭṭäku
    if slot == 1 { return "ሰጠከ" }      // 2sg   säṭṭäkä
    if slot == 2 { return "ሰጠ" }       // 3sg m  säṭṭä
    if slot == 3 { return "ሰጠት" }      // 3sg f  säṭṭät
    if slot == 4 { return "ሰጠነ" }      // 1pl   säṭṭänä
    return "ሰጡ"                          // 3pl   säṭṭu
}

fn gez_hbl_imperfect(slot: Int) -> String {
    if slot == 0 { return "እሰጥ" }      // 1sg   ʾǝsäṭ
    if slot == 1 { return "ትሰጥ" }      // 2sg   tǝsäṭ
    if slot == 2 { return "ይሰጥ" }      // 3sg m  yǝsäṭ
    if slot == 3 { return "ትሰጥ" }      // 3sg f  tǝsäṭ
    if slot == 4 { return "ንሰጥ" }      // 1pl   nǝsäṭ
    return "ይሰጡ"                         // 3pl   yǝsäṭu
}

// ── rʾy / አየ — to see ─────────────────────────────────────────────────────────
//
// Third-weak verb (final ʾ).  Perfect: ʾayyä (3sg m); imperfect: yāy (3sg m).

fn gez_ray_perfect(slot: Int) -> String {
    if slot == 0 { return "አየኩ" }      // 1sg   ʾayyäku
    if slot == 1 { return "አየከ" }      // 2sg   ʾayyäkä
    if slot == 2 { return "አየ" }       // 3sg m  ʾayyä
    if slot == 3 { return "አየት" }      // 3sg f  ʾayyät
    if slot == 4 { return "አየነ" }      // 1pl   ʾayyänä
    return "አዩ"                          // 3pl   ʾayyu
}

fn gez_ray_imperfect(slot: Int) -> String {
    if slot == 0 { return "እያይ" }      // 1sg   ʾǝyāy
    if slot == 1 { return "ትያይ" }      // 2sg   tǝyāy
    if slot == 2 { return "ያይ" }       // 3sg m  yāy
    if slot == 3 { return "ትያይ" }      // 3sg f  tǝyāy
    if slot == 4 { return "ንያይ" }      // 1pl   nǝyāy
    return "ያዩ"                          // 3pl   yāyu
}

// ── qwl / ተናገረ — to speak ────────────────────────────────────────────────────
//
// tänagärä is actually a derived (reciprocal / D-stem) form of the root ngrǝ,
// used as the ordinary word for "to speak" in Classical Ge'ez.
// Perfect: tänagärä (3sg m); imperfect: yǝnagär (3sg m).

fn gez_qwl_perfect(slot: Int) -> String {
    if slot == 0 { return "ተናገርኩ" }    // 1sg   tänagärku
    if slot == 1 { return "ተናገርከ" }    // 2sg   tänagärkä
    if slot == 2 { return "ተናገረ" }     // 3sg m  tänagärä
    if slot == 3 { return "ተናገረት" }    // 3sg f  tänagärät
    if slot == 4 { return "ተናገርነ" }    // 1pl   tänagärnä
    return "ተናገሩ"                        // 3pl   tänagäru
}

fn gez_qwl_imperfect(slot: Int) -> String {
    if slot == 0 { return "እናገር" }     // 1sg   ʾǝnagär
    if slot == 1 { return "ትናገር" }     // 2sg   tǝnagär
    if slot == 2 { return "ይናገር" }     // 3sg m  yǝnagär
    if slot == 3 { return "ትናገር" }     // 3sg f  tǝnagär
    if slot == 4 { return "ንናገር" }     // 1pl   nǝnagär
    return "ይናገሩ"                        // 3pl   yǝnagäru
}

// ── Generic G-stem paradigm ────────────────────────────────────────────────────
//
// For regular strong verbs not in the lookup table.
// Ge'ez perfect suffixes: 1sg -ku, 2sg -kä, 3sg m ∅, 3sg f -at, 1pl -nä, 3pl -u
// Ge'ez imperfect prefixes: 1sg ʾǝ-, 2sg tǝ-, 3sg m yǝ-, 3sg f tǝ-, 1pl nǝ-

fn gez_generic_perfect(base3sg: String, slot: Int) -> String {
    if slot == 0 { return base3sg + "ኩ" }   // -ku
    if slot == 1 { return base3sg + "ከ" }   // -kä
    if slot == 2 { return base3sg }           // ∅
    if slot == 3 { return base3sg + "ት" }   // -at (simplified: -t Fidel)
    if slot == 4 { return base3sg + "ነ" }   // -nä
    return base3sg + "ኡ"                      // -u (3pl)
}

fn gez_generic_imperfect(base3sg: String, slot: Int) -> String {
    // base3sg is the 3sg m imperfect form (with yǝ- prefix)
    // We heuristically return the stem with different prefixes.
    if slot == 0 { return "እ" + base3sg }   // ʾǝ-
    if slot == 1 { return "ት" + base3sg }   // tǝ-
    if slot == 2 { return "ይ" + base3sg }   // yǝ-
    if slot == 3 { return "ት" + base3sg }   // tǝ-
    if slot == 4 { return "ን" + base3sg }   // nǝ-
    return "ይ" + base3sg + "ኡ"               // yǝ- + -u (3pl)
}

// ── Known-verb dispatcher ─────────────────────────────────────────────────────

fn gez_known_verb(verb: String, tense: String, slot: Int) -> String {
    // kwn / ሆነ — to be
    if str_eq(verb, "kwn") {
        return gez_conjugate_copula(tense, slot)
    }
    if str_eq(verb, "ሆነ") {
        return gez_conjugate_copula(tense, slot)
    }
    if str_eq(verb, "hona") {
        return gez_conjugate_copula(tense, slot)
    }

    // hlw / ሀሎ — to exist
    if str_eq(verb, "hlw") {
        if str_eq(tense, "imperfect") { return gez_hlw_imperfect(slot) }
        return gez_hlw_perfect(slot)
    }
    if str_eq(verb, "ሀሎ") {
        if str_eq(tense, "imperfect") { return gez_hlw_imperfect(slot) }
        return gez_hlw_perfect(slot)
    }
    if str_eq(verb, "hallo") {
        if str_eq(tense, "imperfect") { return gez_hlw_imperfect(slot) }
        return gez_hlw_perfect(slot)
    }

    // hbl / ሰጠ — to give
    if str_eq(verb, "hbl") {
        if str_eq(tense, "imperfect") { return gez_hbl_imperfect(slot) }
        return gez_hbl_perfect(slot)
    }
    if str_eq(verb, "ሰጠ") {
        if str_eq(tense, "imperfect") { return gez_hbl_imperfect(slot) }
        return gez_hbl_perfect(slot)
    }
    if str_eq(verb, "sätta") {
        if str_eq(tense, "imperfect") { return gez_hbl_imperfect(slot) }
        return gez_hbl_perfect(slot)
    }

    // rʾy / አየ — to see
    if str_eq(verb, "rʾy") {
        if str_eq(tense, "imperfect") { return gez_ray_imperfect(slot) }
        return gez_ray_perfect(slot)
    }
    if str_eq(verb, "አየ") {
        if str_eq(tense, "imperfect") { return gez_ray_imperfect(slot) }
        return gez_ray_perfect(slot)
    }
    if str_eq(verb, "ʾayya") {
        if str_eq(tense, "imperfect") { return gez_ray_imperfect(slot) }
        return gez_ray_perfect(slot)
    }

    // qwl / ተናገረ — to speak
    if str_eq(verb, "qwl") {
        if str_eq(tense, "imperfect") { return gez_qwl_imperfect(slot) }
        return gez_qwl_perfect(slot)
    }
    if str_eq(verb, "ተናገረ") {
        if str_eq(tense, "imperfect") { return gez_qwl_imperfect(slot) }
        return gez_qwl_perfect(slot)
    }
    if str_eq(verb, "tänagärä") {
        if str_eq(tense, "imperfect") { return gez_qwl_imperfect(slot) }
        return gez_qwl_perfect(slot)
    }

    return ""
}

// ── Main conjugation entry point ──────────────────────────────────────────────
//
// gez_conjugate: conjugate a Ge'ez verb (G-stem / basic stem).
//
// verb:   root (e.g. "kwn", "rʾy"), Fidel citation form (e.g. "ሆነ"),
//         or transliterated 3sg perfect (e.g. "hona", "ʾayya")
// tense:  "perfect" | "imperfect"
// person: "first" | "second" | "third"
// number: "singular" | "plural"
//
// Returns:
//   - Fidel string (Unicode) for known verbs
//   - verb unchanged as safe fallback for unknown verbs

fn gez_conjugate(verb: String, tense: String, person: String, number: String) -> String {
    let slot: Int = gez_slot(person, number)

    if gez_is_copula(verb) {
        return gez_conjugate_copula(tense, slot)
    }

    let known: String = gez_known_verb(verb, tense, slot)
    if !str_eq(known, "") {
        return known
    }

    return verb
}

// ── Noun declension ────────────────────────────────────────────────────────────
//
// gez_decline: decline a Ge'ez noun for gram_case and number.
//
// Case system (simplified for this engine):
//   Nominative:  base form (unmarked — the Fidel form as given)
//   Accusative:  base + -a  (for animate masculine nouns; inanimate often same)
//   Construct:   base form (genitive/construct; detailed vowel alternations
//                are lexically irregular — simplified to base here)
//
// Plural patterns (highly irregular in Ge'ez, like Arabic broken plurals):
//   Common productive suffixes:
//     Feminine/animate: -āt  (ሀዋርያት hawāryāt — apostles)
//     Masculine:        -ān  (ነቢያን nabiyān — prophets)
//   Broken plurals: unpredictable — must come from vocabulary layer.
//   Fallback: base + "āt" (ア default)
//
// noun:      base singular form (Fidel or transliterated)
// gram_case: "nom" | "acc" | "construct"
// number:    "singular" | "plural"

fn gez_is_fidel(noun: String) -> Bool {
    // Ethiopic Unicode block starts at U+1200 (ሀ).
    // We detect by checking a set of common Fidel first characters.
    let n: Int = gez_str_len(noun)
    if n == 0 { return false }
    let first: String = str_slice(noun, 0, 1)
    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 }
    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 gez_decline(noun: String, gram_case: String, number: String) -> String {
    if str_eq(number, "plural") {
        // Plural: default suffix -āt (Fidel: append transliterated marker for
        // non-Fidel input; for Fidel input append ት as the -āt marker)
        if gez_is_fidel(noun) {
            return noun + "ዎች"   // simplified -woc plural marker (Ge'ez -āt ≈ ዎ)
        }
        return noun + "āt"
    }

    // Singular
    if str_eq(gram_case, "acc") {
        // Accusative: add -a suffix
        if gez_is_fidel(noun) {
            return noun + "ን"    // accusative object marker (simplified)
        }
        return noun + "a"
    }

    // Nominative and construct: return base form
    return noun
}

// ── Noun phrase ────────────────────────────────────────────────────────────────
//
// gez_noun_phrase: produce the surface noun phrase.
//
// Ge'ez has no definite article (unlike Amharic's suffix -u/-wa/-itu).
// Definiteness is expressed through word order and context.
// The definite parameter is accepted for interface uniformity but has no
// surface effect.
//
// noun:      base noun (Fidel string or transliteration)
// gram_case: "nom" | "acc" | "construct"
// number:    "singular" | "plural"
// definite:  "true" | "false"  (no surface effect in Ge'ez)

fn gez_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String {
    return gez_decline(noun, gram_case, number)
}

// ── Canonical verb mapping ─────────────────────────────────────────────────────
//
// gez_map_canonical: map cross-lingual English canonical verb labels to
// Ge'ez roots or citation forms.

fn gez_map_canonical(verb: String) -> String {
    if str_eq(verb, "be")    { return "kwn"      }
    if str_eq(verb, "exist") { return "hlw"      }
    if str_eq(verb, "give")  { return "hbl"      }
    if str_eq(verb, "see")   { return "rʾy"      }
    if str_eq(verb, "speak") { return "qwl"      }
    if str_eq(verb, "say")   { return "qwl"      }
    return verb
}
