// morphology-egy.el - Ancient Egyptian (Middle Egyptian) morphology for the NLG engine.
//
// Implements Middle Egyptian verb conjugation (sdm=f / sdm.n=f paradigm),
// noun number marking, suffix pronouns, and noun phrase assembly.
// Designed as a companion to morphology.el; called when language code is "egy".
//
// Language profile: code=egy, name=Ancient Egyptian, morph_type=agglutinative,
//   word_order=SVO (Middle Egyptian nominal sentences), question_strategy=particle,
//   script=hieroglyphic (transliterated here as ASCII), family=afro-asiatic-egyptian.
//
// Script note: Classical transliteration uses special characters (ꜣ ꜥ ḥ ḫ ẖ š q ṯ ḏ).
// This engine uses a safe ASCII mapping:
//   A = ꜣ (aleph/glottal stop)   a = ꜥ (ayin)
//   H = ḥ (h with dot)           x = ḫ (velar fricative)
//   X = ẖ (emphatic h)           sh = š (sh sound)
//   q = q (emphatic k)           T = ṯ (tj sound)
//   D = ḏ (dj sound)
// This mapping keeps all string literals ASCII-safe for the El runtime.
//
// Grammatical notes (Middle Egyptian, ca. 2000–1300 BCE):
//   - Aspectual system: Imperfective (sdm=f), Perfective (sdm.n=f), Prospective
//   - "tense" labels used here: "present" (imperfective), "past" (perfective),
//     "future" (prospective/sdm.xr=f), "infinitive"
//   - Two grammatical genders: masculine (unmarked) and feminine (suffix -t)
//   - Number: singular (unmarked), dual (-wy masc / -ty fem), plural (-w masc / -wt fem)
//   - No case endings — syntactic role expressed by word order and prepositions
//   - No definite/indefinite article in Middle Egyptian (Late Egyptian introduced pꜣ/tꜣ/nꜣ)
//   - Zero copula: adjectival predicates need no verb "to be" ("nfr sw" = "he is good")
//   - Suffix pronouns attach directly to the verb stem with = (e.g. sdm=f "he hears")
//
// Persons/numbers covered (suffix pronoun paradigm):
//   person:  "first" | "second" | "third"
//   gender:  "m" | "f" (relevant for 2sg, 3sg; 1sg and plurals often unmarked)
//   number:  "singular" | "dual" | "plural"
//
// Verbs covered (ASCII transliteration → gloss):
//   wnn      — to be/exist (copular auxiliary)
//   rdi / di — to give
//   mAA      — to see
//   Dd       — to say
//   Sm       — to go
//   iri      — to do / make
//   sdm      — to hear (the paradigm verb for the sdm=f construction)
//
// Canonical English → Egyptian mapping:
//   "be"    → wnn / zero copula   "give" → rdi
//   "see"   → mAA                 "say"  → Dd
//   "go"    → Sm                  "do"   → iri
//   "make"  → iri                 "hear" → sdm
//
// Depends on: morphology.el (str_eq, str_len, str_slice, str_ends_with)

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

import "morphology.el"
fn egy_str_ends(s: String, suf: String) -> Bool {
    return str_ends_with(s, suf)
}

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

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

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

// ── Person/number slot ──────────────────────────────────────────────────────────
//
// Maps person × gender × number to a 0-based index used in paradigm tables.
// Egyptian suffix pronouns distinguish gender in 2nd and 3rd person singular.
//
// Slot layout:
//   0 = 1sg         (=i)
//   1 = 2sg masc    (=k)
//   2 = 2sg fem     (=T)
//   3 = 3sg masc    (=f)
//   4 = 3sg fem     (=s)
//   5 = 1pl         (=n)
//   6 = 2pl         (=Tn)
//   7 = 3pl         (=sn)
//   8 = 1du / 2du / 3du  (=sny — simplified; dual pronouns are rare in sources)
//
// Dual falls through to slot 8 (a single dual pronoun slot for all persons).

fn egy_slot(person: String, number: String) -> Int {
    if str_eq(number, "dual") { return 8 }
    if str_eq(person, "first") {
        if str_eq(number, "plural") { return 5 }
        return 0
    }
    if str_eq(person, "second") {
        if str_eq(number, "plural") { return 6 }
        return 1
    }
    // third person
    if str_eq(number, "plural") { return 7 }
    return 3
}

// egy_slot_with_gender: slot variant that factors in gender for 2sg and 3sg.

fn egy_slot_with_gender(person: String, gender: String, number: String) -> Int {
    if str_eq(number, "dual") { return 8 }
    if str_eq(person, "first") {
        if str_eq(number, "plural") { return 5 }
        return 0
    }
    if str_eq(person, "second") {
        if str_eq(number, "plural") { return 6 }
        if str_eq(gender, "f") { return 2 }
        return 1
    }
    // third person
    if str_eq(number, "plural") { return 7 }
    if str_eq(gender, "f") { return 4 }
    return 3
}

// ── Suffix pronouns ─────────────────────────────────────────────────────────────
//
// Egyptian suffix pronouns attach to verbs, nouns, and prepositions.
// Written with = before the pronoun in transliteration (e.g. =f = "his / he").
//
// Standard Middle Egyptian paradigm:
//   1sg:     =i       ("I / me / my")
//   2sg m:   =k       ("you / your" masc)
//   2sg f:   =T       ("you / your" fem, ṯ in classical)
//   3sg m:   =f       ("he / him / his")
//   3sg f:   =s       ("she / her")
//   1pl:     =n       ("we / us / our")
//   2pl:     =Tn      ("you all / your" plural)
//   3pl:     =sn      ("they / them / their")
//   dual:    =sny     (simplified dual — rare in Middle Egyptian texts)

fn egy_conjugate_pronoun(person: String, number: String) -> String {
    let slot: Int = egy_slot(person, number)
    if slot == 0 { return "=i" }
    if slot == 1 { return "=k" }
    if slot == 5 { return "=n" }
    if slot == 6 { return "=Tn" }
    if slot == 7 { return "=sn" }
    if slot == 8 { return "=sny" }
    // slots 2–4 need gender; default to masc for slot 3
    return "=f"
}

fn egy_suffix_pronoun(slot: Int) -> String {
    if slot == 0 { return "=i" }
    if slot == 1 { return "=k" }
    if slot == 2 { return "=T" }
    if slot == 3 { return "=f" }
    if slot == 4 { return "=s" }
    if slot == 5 { return "=n" }
    if slot == 6 { return "=Tn" }
    if slot == 7 { return "=sn" }
    // dual (slot 8)
    return "=sny"
}

// ── Copula detection ────────────────────────────────────────────────────────────
//
// In Middle Egyptian the verb "to be" as predicate is often omitted in the
// present (zero copula for adjective predicates).  The auxiliary wnn is used
// for existence / substantive "to be" and in subordinate clauses.
// Canonical English label "be" maps to zero copula in the present.

fn egy_is_copula(verb: String) -> Bool {
    if str_eq(verb, "wnn") { return true }
    if str_eq(verb, "be")  { return true }
    return false
}

// ── Copula conjugation ──────────────────────────────────────────────────────────
//
// Present ("imperfective"): zero copula for adjectival predicate — return "".
//   The auxiliary iw...wnn is used in certain syntactic environments but the
//   bare zero is the canonical Middle Egyptian form.
// Past ("perfective"):  wnn.n  (with perfective suffix .n)
// Future ("prospective"): wnn.xr (prospective form, simplified)

fn egy_conjugate_copula(tense: String, slot: Int) -> String {
    if str_eq(tense, "present") { return "" }
    if str_eq(tense, "past") {
        return "wnn.n" + egy_suffix_pronoun(slot)
    }
    if str_eq(tense, "future") {
        return "wnn.xr" + egy_suffix_pronoun(slot)
    }
    if str_eq(tense, "infinitive") { return "wnn" }
    // Default: zero copula
    return ""
}

// ── Irregular verb: rdi / di (to give) ─────────────────────────────────────────
//
// rdi is the full form; di is the common abbreviated written form.
// Imperfective (present): di=f (3sg m), with full pronoun for other persons.
// Perfective (past):      di.n=f
// Prospective (future):   di.xr=f
// Infinitive:             rdi

fn egy_rdi_present(slot: Int) -> String {
    return "di" + egy_suffix_pronoun(slot)
}

fn egy_rdi_past(slot: Int) -> String {
    return "di.n" + egy_suffix_pronoun(slot)
}

fn egy_rdi_future(slot: Int) -> String {
    return "di.xr" + egy_suffix_pronoun(slot)
}

// ── Irregular verb: mAA (to see) ───────────────────────────────────────────────
//
// mAA is a geminated root (m-AA).
// Present: mAA=f;  Past: mAA.n=f;  Future: mAA.xr=f

fn egy_mAA_present(slot: Int) -> String {
    return "mAA" + egy_suffix_pronoun(slot)
}

fn egy_mAA_past(slot: Int) -> String {
    return "mAA.n" + egy_suffix_pronoun(slot)
}

fn egy_mAA_future(slot: Int) -> String {
    return "mAA.xr" + egy_suffix_pronoun(slot)
}

// ── Irregular verb: Dd (to say) ─────────────────────────────────────────────────
//
// Present: Dd=f;  Past: Dd.n=f;  Future: Dd.xr=f
// Infinitive: Dd

fn egy_Dd_present(slot: Int) -> String {
    return "Dd" + egy_suffix_pronoun(slot)
}

fn egy_Dd_past(slot: Int) -> String {
    return "Dd.n" + egy_suffix_pronoun(slot)
}

fn egy_Dd_future(slot: Int) -> String {
    return "Dd.xr" + egy_suffix_pronoun(slot)
}

// ── Irregular verb: Sm (to go) ─────────────────────────────────────────────────
//
// Present: Sm=f;  Past: Sm.n=f;  Future: Sm.xr=f
// (Note: the verb Smt "to go" appears in texts; Sm is the most common short form.)

fn egy_Sm_present(slot: Int) -> String {
    return "Sm" + egy_suffix_pronoun(slot)
}

fn egy_Sm_past(slot: Int) -> String {
    return "Sm.n" + egy_suffix_pronoun(slot)
}

fn egy_Sm_future(slot: Int) -> String {
    return "Sm.xr" + egy_suffix_pronoun(slot)
}

// ── Irregular verb: iri (to do / make) ─────────────────────────────────────────
//
// iri has a contracted 3-radical stem ir- before pronouns.
// Present: ir=f;  Past: ir.n=f;  Future: ir.xr=f
// Infinitive: iri

fn egy_iri_present(slot: Int) -> String {
    return "ir" + egy_suffix_pronoun(slot)
}

fn egy_iri_past(slot: Int) -> String {
    return "ir.n" + egy_suffix_pronoun(slot)
}

fn egy_iri_future(slot: Int) -> String {
    return "ir.xr" + egy_suffix_pronoun(slot)
}

// ── Regular verb: sdm (to hear) ────────────────────────────────────────────────
//
// sdm (to hear) is the paradigm verb used in grammar textbooks to illustrate
// all Egyptian verb forms.  The sdm=f construction names the imperfective suffix
// verb pattern itself.
// Present: sdm=f;  Past: sdm.n=f;  Future: sdm.xr=f
// Infinitive: sdm

fn egy_sdm_present(slot: Int) -> String {
    return "sdm" + egy_suffix_pronoun(slot)
}

fn egy_sdm_past(slot: Int) -> String {
    return "sdm.n" + egy_suffix_pronoun(slot)
}

fn egy_sdm_future(slot: Int) -> String {
    return "sdm.xr" + egy_suffix_pronoun(slot)
}

// ── Known-verb dispatcher ───────────────────────────────────────────────────────
//
// Returns the inflected form for a known verb, or "" if unknown.
// Accepts both canonical English labels and Egyptian transliterations.

fn egy_known_verb(verb: String, tense: String, slot: Int) -> String {
    // ── rdi / di — to give ───────────────────────────────────────────────────────
    if str_eq(verb, "rdi") {
        if str_eq(tense, "present")    { return egy_rdi_present(slot) }
        if str_eq(tense, "past")       { return egy_rdi_past(slot) }
        if str_eq(tense, "future")     { return egy_rdi_future(slot) }
        if str_eq(tense, "infinitive") { return "rdi" }
        return egy_rdi_present(slot)
    }
    if str_eq(verb, "di") {
        if str_eq(tense, "present")    { return egy_rdi_present(slot) }
        if str_eq(tense, "past")       { return egy_rdi_past(slot) }
        if str_eq(tense, "future")     { return egy_rdi_future(slot) }
        if str_eq(tense, "infinitive") { return "rdi" }
        return egy_rdi_present(slot)
    }
    if str_eq(verb, "give") {
        if str_eq(tense, "present")    { return egy_rdi_present(slot) }
        if str_eq(tense, "past")       { return egy_rdi_past(slot) }
        if str_eq(tense, "future")     { return egy_rdi_future(slot) }
        if str_eq(tense, "infinitive") { return "rdi" }
        return egy_rdi_present(slot)
    }

    // ── mAA — to see ─────────────────────────────────────────────────────────────
    if str_eq(verb, "mAA") {
        if str_eq(tense, "present")    { return egy_mAA_present(slot) }
        if str_eq(tense, "past")       { return egy_mAA_past(slot) }
        if str_eq(tense, "future")     { return egy_mAA_future(slot) }
        if str_eq(tense, "infinitive") { return "mAA" }
        return egy_mAA_present(slot)
    }
    if str_eq(verb, "see") {
        if str_eq(tense, "present")    { return egy_mAA_present(slot) }
        if str_eq(tense, "past")       { return egy_mAA_past(slot) }
        if str_eq(tense, "future")     { return egy_mAA_future(slot) }
        if str_eq(tense, "infinitive") { return "mAA" }
        return egy_mAA_present(slot)
    }

    // ── Dd — to say ──────────────────────────────────────────────────────────────
    if str_eq(verb, "Dd") {
        if str_eq(tense, "present")    { return egy_Dd_present(slot) }
        if str_eq(tense, "past")       { return egy_Dd_past(slot) }
        if str_eq(tense, "future")     { return egy_Dd_future(slot) }
        if str_eq(tense, "infinitive") { return "Dd" }
        return egy_Dd_present(slot)
    }
    if str_eq(verb, "say") {
        if str_eq(tense, "present")    { return egy_Dd_present(slot) }
        if str_eq(tense, "past")       { return egy_Dd_past(slot) }
        if str_eq(tense, "future")     { return egy_Dd_future(slot) }
        if str_eq(tense, "infinitive") { return "Dd" }
        return egy_Dd_present(slot)
    }

    // ── Sm — to go ───────────────────────────────────────────────────────────────
    if str_eq(verb, "Sm") {
        if str_eq(tense, "present")    { return egy_Sm_present(slot) }
        if str_eq(tense, "past")       { return egy_Sm_past(slot) }
        if str_eq(tense, "future")     { return egy_Sm_future(slot) }
        if str_eq(tense, "infinitive") { return "Sm" }
        return egy_Sm_present(slot)
    }
    if str_eq(verb, "go") {
        if str_eq(tense, "present")    { return egy_Sm_present(slot) }
        if str_eq(tense, "past")       { return egy_Sm_past(slot) }
        if str_eq(tense, "future")     { return egy_Sm_future(slot) }
        if str_eq(tense, "infinitive") { return "Sm" }
        return egy_Sm_present(slot)
    }

    // ── iri — to do / make ───────────────────────────────────────────────────────
    if str_eq(verb, "iri") {
        if str_eq(tense, "present")    { return egy_iri_present(slot) }
        if str_eq(tense, "past")       { return egy_iri_past(slot) }
        if str_eq(tense, "future")     { return egy_iri_future(slot) }
        if str_eq(tense, "infinitive") { return "iri" }
        return egy_iri_present(slot)
    }
    if str_eq(verb, "do") {
        if str_eq(tense, "present")    { return egy_iri_present(slot) }
        if str_eq(tense, "past")       { return egy_iri_past(slot) }
        if str_eq(tense, "future")     { return egy_iri_future(slot) }
        if str_eq(tense, "infinitive") { return "iri" }
        return egy_iri_present(slot)
    }
    if str_eq(verb, "make") {
        if str_eq(tense, "present")    { return egy_iri_present(slot) }
        if str_eq(tense, "past")       { return egy_iri_past(slot) }
        if str_eq(tense, "future")     { return egy_iri_future(slot) }
        if str_eq(tense, "infinitive") { return "iri" }
        return egy_iri_present(slot)
    }

    // ── sdm — to hear ────────────────────────────────────────────────────────────
    if str_eq(verb, "sdm") {
        if str_eq(tense, "present")    { return egy_sdm_present(slot) }
        if str_eq(tense, "past")       { return egy_sdm_past(slot) }
        if str_eq(tense, "future")     { return egy_sdm_future(slot) }
        if str_eq(tense, "infinitive") { return "sdm" }
        return egy_sdm_present(slot)
    }
    if str_eq(verb, "hear") {
        if str_eq(tense, "present")    { return egy_sdm_present(slot) }
        if str_eq(tense, "past")       { return egy_sdm_past(slot) }
        if str_eq(tense, "future")     { return egy_sdm_future(slot) }
        if str_eq(tense, "infinitive") { return "sdm" }
        return egy_sdm_present(slot)
    }

    // Verb not in table
    return ""
}

// ── Regular verb conjugation ────────────────────────────────────────────────────
//
// For verbs not in the explicit table, apply the productive suffix-verb pattern:
//   Present (imperfective sdm=f):    stem + pronoun suffix
//   Past    (perfective sdm.n=f):    stem + ".n" + pronoun suffix
//   Future  (prospective sdm.xr=f):  stem + ".xr" + pronoun suffix
//   Infinitive:                       stem unchanged
//
// This covers the vast majority of strong (sound) verb roots.

fn egy_regular_present(stem: String, slot: Int) -> String {
    return stem + egy_suffix_pronoun(slot)
}

fn egy_regular_past(stem: String, slot: Int) -> String {
    return stem + ".n" + egy_suffix_pronoun(slot)
}

fn egy_regular_future(stem: String, slot: Int) -> String {
    return stem + ".xr" + egy_suffix_pronoun(slot)
}

// ── egy_conjugate: main conjugation entry point ─────────────────────────────────
//
// verb:   Egyptian verb (ASCII transliteration) or English canonical label
// tense:  "present" | "past" | "future" | "infinitive"
// person: "first" | "second" | "third"
// number: "singular" | "dual" | "plural"
//
// Returns:
//   - "" for present copula (zero copula — caller omits the verb)
//   - inflected form (stem + .n + suffix, etc.) for all other cases
//   - verb + regular suffix for unknown verbs (productive fallback)

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

    // Handle copula (wnn / "be")
    if egy_is_copula(verb) {
        return egy_conjugate_copula(tense, slot)
    }

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

    // Infinitive: return unchanged
    if str_eq(tense, "infinitive") { return verb }

    // Regular verb: apply productive sdm=f / sdm.n=f pattern
    if str_eq(tense, "present") { return egy_regular_present(verb, slot) }
    if str_eq(tense, "past")    { return egy_regular_past(verb, slot) }
    if str_eq(tense, "future")  { return egy_regular_future(verb, slot) }

    // Unknown tense: return verb unchanged as safe fallback
    return verb
}

// ── Noun number marking ─────────────────────────────────────────────────────────
//
// Middle Egyptian nouns are invariant for case — syntactic role is expressed by
// word order and prepositions, not noun endings.  Number is marked by suffix:
//
//   Singular:  base form (no suffix)
//   Dual:      masc + wy  /  fem + ty  (wy and ty in ASCII transliteration)
//   Plural:    masc + w   /  fem + wt
//
// Many common nouns have suppletive or irregular plurals (recorded in the
// vocabulary layer).  This function implements the productive regular pattern.
//
// gram_case: accepted for API symmetry but has no effect (Egyptian is caseless).

fn egy_decline(noun: String, gram_case: String, number: String) -> String {
    if str_eq(number, "singular") { return noun }
    if str_eq(number, "dual") {
        // Feminine dual: if noun ends in t (feminine marker), replace with ty
        if egy_str_ends(noun, "t") {
            let stem: String = egy_drop(noun, 1)
            return stem + "ty"
        }
        return noun + "wy"
    }
    // Plural
    if egy_str_ends(noun, "t") {
        // Feminine noun: add wt
        return noun + "wt"
    }
    // Masculine noun: add w
    return noun + "w"
}

// ── Feminine derivation ─────────────────────────────────────────────────────────
//
// egy_fem: derive the feminine form of a noun or adjective by appending -t.
//
// In Middle Egyptian, the feminine gender marker is the suffix -t (written with
// the bread-loaf hieroglyph, Gardiner X1).  If the base already ends in -t the
// form is returned unchanged to avoid double-suffixing.

fn egy_fem(noun: String) -> String {
    if egy_str_ends(noun, "t") { return noun }
    return noun + "t"
}

// ── Noun phrase assembly ────────────────────────────────────────────────────────
//
// egy_noun_phrase: return the surface form of a noun phrase.
//
// noun:     base noun (ASCII transliteration)
// gram_case: passed for API symmetry; has no effect (Egyptian is caseless)
// number:   "singular" | "dual" | "plural"
// definite: "true" | "false" — Middle Egyptian has no article; parameter accepted
//           for API symmetry.  Late Egyptian pꜣ/tꜣ/nꜣ articles are not implemented
//           here (they would require knowing the gender of each noun).
//
// Returns the noun in its correct number form.

fn egy_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String {
    return egy_decline(noun, gram_case, number)
}

// ── Canonical verb mapping ──────────────────────────────────────────────────────
//
// egy_map_canonical: map cross-lingual English canonical verb labels to their
// Middle Egyptian equivalents before dispatching to egy_conjugate.

fn egy_map_canonical(verb: String) -> String {
    if str_eq(verb, "be")    { return "wnn" }
    if str_eq(verb, "give")  { return "rdi" }
    if str_eq(verb, "see")   { return "mAA" }
    if str_eq(verb, "say")   { return "Dd" }
    if str_eq(verb, "go")    { return "Sm" }
    if str_eq(verb, "do")    { return "iri" }
    if str_eq(verb, "make")  { return "iri" }
    if str_eq(verb, "hear")  { return "sdm" }
    // Unknown: return as-is; egy_conjugate will apply the regular pattern
    return verb
}
