// morphology-ar.el - Arabic morphology for the NLG engine.
//
// Implements Arabic verb conjugation, noun inflection (gram_case, gender, number,
// definiteness), and definite-article attachment with sun/moon letter handling.
//
// Arabic is a Semitic language with a trilateral root system: most words derive
// from 3-consonant roots by inserting vowel patterns (أوزان awzan) around the
// root consonants.  Verb conjugation is realised as prefix + stem + suffix.
//
// Strategy: the engine takes the 3ms perfect (past tense) form as the canonical
// dictionary key (e.g. كَتَبَ kataba) and applies affix patterns to derive all
// other conjugated forms for Form I (الفعل المجرد) regular verbs.  A lookup
// table covers essential irregular and hollow verbs.
//
// Verb tenses covered: "past" (perfect/الماضي), "present" (imperfect/المضارع),
//                      "future" (سَيَفْعَلُ = sa- + imperfect).
// Persons: first/second/third × masculine/feminine × singular/plural (+ dual stubs).
// Gender params: "m" (masculine) | "f" (feminine).
//
// Depends on: morphology.el (str_ends_with, str_len, str_slice, str_eq, str_drop_last concept)

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

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

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

fn ar_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 ar_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.
// Slot layout (10 cells, matching classical Arabic conjugation paradigm):
//   0  = 3ms  (he)
//   1  = 3fs  (she)
//   2  = 2ms  (you m sg)
//   3  = 2fs  (you f sg)
//   4  = 1s   (I)
//   5  = 3mp  (they m pl)
//   6  = 3fp  (they f pl)
//   7  = 2mp  (you m pl)
//   8  = 2fp  (you f pl)
//   9  = 1p   (we)

fn ar_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
    if str_eq(number, "plural") { return 9 }
    return 4
}

// ── Perfect (past) suffixes ───────────────────────────────────────────────────
//
// Form I perfect: root-past-stem (e.g. كَتَبَ kataba) + suffix.
// The 3ms form IS the base (no suffix added).  All other persons add a suffix
// that replaces or follows the final short vowel of the base.
//
// Pattern (dropping the final -a of the 3ms base, then adding):
//   3ms:  -a      (base as given)
//   3fs:  -at
//   2ms:  -ta
//   2fs:  -ti
//   1s:   -tu
//   3mp:  -uu
//   3fp:  -na
//   2mp:  -tum
//   2fp:  -tunna
//   1p:   -naa
//
// The base passed to ar_conjugate_form1 is the full 3ms form (ends in -a).
// For suffixed forms we drop the final vowel character (1 byte = the -a) then
// apply the suffix.  In Arabic script the final short vowel (fatha ـَ) on the
// last consonant of the base is part of the grapheme cluster of that consonant;
// for our stored strings the form كَتَبَ is stored with the final fatha attached
// to the ب.  The suffix strings already include the vowel that replaces it, so
// we drop 1 character from the base.
//
// For simplicity the suffixes below are given as Arabic transliteration that
// the El string system handles as UTF-8.  The actual Arabic forms are stored
// as UTF-8 Arabic script literals.
//
// Returns the suffix string (including the vowel carried on the junction
// consonant for suffixed forms).  Returns "" for 3ms (base is the full form).

fn ar_perfect_suffix(slot: Int) -> String {
    if slot == 0 { return "" }           // 3ms: base is already complete
    if slot == 1 { return "ت" }          // 3fs: -at (تْ taa saakina)
    if slot == 2 { return "تَ" }         // 2ms: -ta
    if slot == 3 { return "تِ" }         // 2fs: -ti
    if slot == 4 { return "تُ" }         // 1s:  -tu
    if slot == 5 { return "وا" }         // 3mp: -uu (واو + alif farika)
    if slot == 6 { return "نَ" }         // 3fp: -na
    if slot == 7 { return "تُمْ" }       // 2mp: -tum
    if slot == 8 { return "تُنَّ" }      // 2fp: -tunna
    return "نَا"                          // 1p:  -naa (9)
}

// ── Imperfect (present) prefixes ──────────────────────────────────────────────
//
// Form I imperfect: prefix + middle vowel pattern + suffix.
// Prefix depends on person (and for 1s the prefix is أَ).

fn ar_imperfect_prefix(slot: Int) -> String {
    if slot == 0 { return "يَ" }    // 3ms: ya-
    if slot == 1 { return "تَ" }    // 3fs: ta-
    if slot == 2 { return "تَ" }    // 2ms: ta-
    if slot == 3 { return "تَ" }    // 2fs: ta-
    if slot == 4 { return "أَ" }    // 1s:  a-
    if slot == 5 { return "يَ" }    // 3mp: ya-
    if slot == 6 { return "يَ" }    // 3fp: ya-
    if slot == 7 { return "تَ" }    // 2mp: ta-
    if slot == 8 { return "تَ" }    // 2fp: ta-
    return "نَ"                      // 1p:  na- (9)
}

// ── Imperfect (present) suffixes ──────────────────────────────────────────────
//
// Standard Form I imperfect — yaf'ulu / yaf'alu / yaf'ilu vowel class.
// The stem vowel is encoded in the verb's imperfect stem (stored in the lookup
// table or derived from the base).  The suffix encodes number/gender/person.
//
// Suffix pattern (after the u-class stem: yaktubu):
//   3ms:  -u           (yaktub-u)
//   3fs:  -u           (taktub-u)
//   2ms:  -u           (taktub-u)
//   2fs:  -iina        (taktub-iina)
//   1s:   -u           (aktub-u)
//   3mp:  -uuna        (yaktub-uuna)
//   3fp:  -na          (yaktub-na)
//   2mp:  -uuna        (taktub-uuna)
//   2fp:  -na          (taktub-na)
//   1p:   -u           (naktub-u)

fn ar_imperfect_suffix(slot: Int) -> String {
    if slot == 0 { return "ُ" }      // 3ms: -u
    if slot == 1 { return "ُ" }      // 3fs: -u
    if slot == 2 { return "ُ" }      // 2ms: -u
    if slot == 3 { return "ِينَ" }   // 2fs: -iina
    if slot == 4 { return "ُ" }      // 1s:  -u
    if slot == 5 { return "ُونَ" }   // 3mp: -uuna
    if slot == 6 { return "نَ" }     // 3fp: -na
    if slot == 7 { return "ُونَ" }   // 2mp: -uuna
    if slot == 8 { return "نَ" }     // 2fp: -na
    return "ُ"                        // 1p:  -u (9)
}

// ── Form I conjugation ────────────────────────────────────────────────────────
//
// ar_conjugate_form1: conjugate a regular Form I verb.
//
// past_base:   the 3ms perfect form (e.g. "كَتَبَ")
// present_stem: the imperfect stem without prefix (e.g. "كْتُبُ" for yaktubu)
//               This is the middle part after stripping the prefix: for يَكْتُبُ
//               the stem = "كْتُبُ".  We strip the final -u vowel diacritic
//               (1 char) from the stem and re-add via the suffix.
// tense:       "past" | "present" | "future"
// slot:        ar_slot result

fn ar_conjugate_form1(past_base: String, present_stem: String, tense: String, slot: Int) -> String {
    if str_eq(tense, "past") {
        // 3ms: return base as-is
        if slot == 0 { return past_base }
        // All other forms: drop final character of base (the short -a vowel mark
        // on the last root consonant), then append the suffix.
        let suf: String = ar_perfect_suffix(slot)
        // Drop the last character (the fatha diacritic or final vowel-letter)
        let stem: String = ar_str_drop_last(past_base, 1)
        return stem + suf
    }

    if str_eq(tense, "present") {
        let pre: String = ar_imperfect_prefix(slot)
        let suf: String = ar_imperfect_suffix(slot)
        // present_stem already includes the medial vowel pattern (e.g. "كْتُبُ")
        // Drop its final character (the -u diacritic) before adding the suffix.
        let mid: String = ar_str_drop_last(present_stem, 1)
        return pre + mid + suf
    }

    if str_eq(tense, "future") {
        // Future = سَ (sa-) + imperfect 3ms form
        let pres_3ms: String = ar_conjugate_form1(past_base, present_stem, "present", 0)
        return "سَ" + pres_3ms
    }

    // Unknown tense: return base form
    return past_base
}

// ── Irregular verb lookup table ───────────────────────────────────────────────
//
// Returns the inflected form for verbs that cannot be derived by Form I rules,
// or "" if the verb is not in the table.
//
// Covered verbs (by their 3ms past / dictionary key):
//   كَانَ  kaana    — to be       (hollow verb, waw-medial)
//   ذَهَبَ  dhahaba  — to go       (Form I, regular; explicit table for certainty)
//   جَاءَ  jaa'a    — to come     (hamzated + defective)
//   قَالَ  qaala    — to say      (hollow verb, waw-medial)
//   رَأَى  ra'aa    — to see      (hamzated + defective)
//   أَكَلَ  akala    — to eat      (hamzated initial)
//   شَرِبَ  shariba  — to drink    (Form I i-class)
//   عَرَفَ  arafa    — to know     (Form I a-class)
//   أَرَادَ araada   — to want     (Form IV hollow)
//   اِسْتَطَاعَ istata'a — can/be able (Form X)
//   فَعَلَ  fa'ala   — to do/act   (Form I; paradigm verb)
//   أَخَذَ  akhadha  — to take     (hamzated initial)
//   عَمِلَ  amila    — to work     (Form I i-class)
//
// For each verb: [past_3ms, past_3fs, past_2ms, past_2fs, past_1s,
//                 past_3mp, past_3fp, past_2mp, past_2fp, past_1p,
//                 pres_3ms, pres_3fs, pres_2ms, pres_2fs, pres_1s,
//                 pres_3mp, pres_3fp, pres_2mp, pres_2fp, pres_1p]

fn ar_irregular_kaana(slot: Int, tense: String) -> String {
    // كَانَ — to be
    if str_eq(tense, "past") {
        if slot == 0 { return "كَانَ" }
        if slot == 1 { return "كَانَتْ" }
        if slot == 2 { return "كُنْتَ" }
        if slot == 3 { return "كُنْتِ" }
        if slot == 4 { return "كُنْتُ" }
        if slot == 5 { return "كَانُوا" }
        if slot == 6 { return "كُنَّ" }
        if slot == 7 { return "كُنْتُمْ" }
        if slot == 8 { return "كُنْتُنَّ" }
        return "كُنَّا"
    }
    if str_eq(tense, "present") {
        if slot == 0 { return "يَكُونُ" }
        if slot == 1 { return "تَكُونُ" }
        if slot == 2 { return "تَكُونُ" }
        if slot == 3 { return "تَكُونِينَ" }
        if slot == 4 { return "أَكُونُ" }
        if slot == 5 { return "يَكُونُونَ" }
        if slot == 6 { return "يَكُنَّ" }
        if slot == 7 { return "تَكُونُونَ" }
        if slot == 8 { return "تَكُنَّ" }
        return "نَكُونُ"
    }
    if str_eq(tense, "future") {
        let pres: String = ar_irregular_kaana(slot, "present")
        return "سَ" + pres
    }
    return "كَانَ"
}

fn ar_irregular_qaala(slot: Int, tense: String) -> String {
    // قَالَ — to say (hollow waw-medial)
    if str_eq(tense, "past") {
        if slot == 0 { return "قَالَ" }
        if slot == 1 { return "قَالَتْ" }
        if slot == 2 { return "قُلْتَ" }
        if slot == 3 { return "قُلْتِ" }
        if slot == 4 { return "قُلْتُ" }
        if slot == 5 { return "قَالُوا" }
        if slot == 6 { return "قُلْنَ" }
        if slot == 7 { return "قُلْتُمْ" }
        if slot == 8 { return "قُلْتُنَّ" }
        return "قُلْنَا"
    }
    if str_eq(tense, "present") {
        if slot == 0 { return "يَقُولُ" }
        if slot == 1 { return "تَقُولُ" }
        if slot == 2 { return "تَقُولُ" }
        if slot == 3 { return "تَقُولِينَ" }
        if slot == 4 { return "أَقُولُ" }
        if slot == 5 { return "يَقُولُونَ" }
        if slot == 6 { return "يَقُلْنَ" }
        if slot == 7 { return "تَقُولُونَ" }
        if slot == 8 { return "تَقُلْنَ" }
        return "نَقُولُ"
    }
    if str_eq(tense, "future") {
        let pres: String = ar_irregular_qaala(slot, "present")
        return "سَ" + pres
    }
    return "قَالَ"
}

fn ar_irregular_jaa(slot: Int, tense: String) -> String {
    // جَاءَ — to come (hamzated defective)
    if str_eq(tense, "past") {
        if slot == 0 { return "جَاءَ" }
        if slot == 1 { return "جَاءَتْ" }
        if slot == 2 { return "جِئْتَ" }
        if slot == 3 { return "جِئْتِ" }
        if slot == 4 { return "جِئْتُ" }
        if slot == 5 { return "جَاءُوا" }
        if slot == 6 { return "جِئْنَ" }
        if slot == 7 { return "جِئْتُمْ" }
        if slot == 8 { return "جِئْتُنَّ" }
        return "جِئْنَا"
    }
    if str_eq(tense, "present") {
        if slot == 0 { return "يَجِيءُ" }
        if slot == 1 { return "تَجِيءُ" }
        if slot == 2 { return "تَجِيءُ" }
        if slot == 3 { return "تَجِيئِينَ" }
        if slot == 4 { return "أَجِيءُ" }
        if slot == 5 { return "يَجِيئُونَ" }
        if slot == 6 { return "يَجِئْنَ" }
        if slot == 7 { return "تَجِيئُونَ" }
        if slot == 8 { return "تَجِئْنَ" }
        return "نَجِيءُ"
    }
    if str_eq(tense, "future") {
        let pres: String = ar_irregular_jaa(slot, "present")
        return "سَ" + pres
    }
    return "جَاءَ"
}

fn ar_irregular_raaa(slot: Int, tense: String) -> String {
    // رَأَى — to see (hamzated defective)
    if str_eq(tense, "past") {
        if slot == 0 { return "رَأَى" }
        if slot == 1 { return "رَأَتْ" }
        if slot == 2 { return "رَأَيْتَ" }
        if slot == 3 { return "رَأَيْتِ" }
        if slot == 4 { return "رَأَيْتُ" }
        if slot == 5 { return "رَأَوْا" }
        if slot == 6 { return "رَأَيْنَ" }
        if slot == 7 { return "رَأَيْتُمْ" }
        if slot == 8 { return "رَأَيْتُنَّ" }
        return "رَأَيْنَا"
    }
    if str_eq(tense, "present") {
        if slot == 0 { return "يَرَى" }
        if slot == 1 { return "تَرَى" }
        if slot == 2 { return "تَرَى" }
        if slot == 3 { return "تَرَيْنَ" }
        if slot == 4 { return "أَرَى" }
        if slot == 5 { return "يَرَوْنَ" }
        if slot == 6 { return "يَرَيْنَ" }
        if slot == 7 { return "تَرَوْنَ" }
        if slot == 8 { return "تَرَيْنَ" }
        return "نَرَى"
    }
    if str_eq(tense, "future") {
        let pres: String = ar_irregular_raaa(slot, "present")
        return "سَ" + pres
    }
    return "رَأَى"
}

fn ar_irregular_araada(slot: Int, tense: String) -> String {
    // أَرَادَ — to want (Form IV hollow)
    if str_eq(tense, "past") {
        if slot == 0 { return "أَرَادَ" }
        if slot == 1 { return "أَرَادَتْ" }
        if slot == 2 { return "أَرَدْتَ" }
        if slot == 3 { return "أَرَدْتِ" }
        if slot == 4 { return "أَرَدْتُ" }
        if slot == 5 { return "أَرَادُوا" }
        if slot == 6 { return "أَرَدْنَ" }
        if slot == 7 { return "أَرَدْتُمْ" }
        if slot == 8 { return "أَرَدْتُنَّ" }
        return "أَرَدْنَا"
    }
    if str_eq(tense, "present") {
        if slot == 0 { return "يُرِيدُ" }
        if slot == 1 { return "تُرِيدُ" }
        if slot == 2 { return "تُرِيدُ" }
        if slot == 3 { return "تُرِيدِينَ" }
        if slot == 4 { return "أُرِيدُ" }
        if slot == 5 { return "يُرِيدُونَ" }
        if slot == 6 { return "يُرِدْنَ" }
        if slot == 7 { return "تُرِيدُونَ" }
        if slot == 8 { return "تُرِدْنَ" }
        return "نُرِيدُ"
    }
    if str_eq(tense, "future") {
        let pres: String = ar_irregular_araada(slot, "present")
        return "سَ" + pres
    }
    return "أَرَادَ"
}

fn ar_irregular_istata(slot: Int, tense: String) -> String {
    // اِسْتَطَاعَ — can / be able (Form X hollow)
    if str_eq(tense, "past") {
        if slot == 0 { return "اِسْتَطَاعَ" }
        if slot == 1 { return "اِسْتَطَاعَتْ" }
        if slot == 2 { return "اِسْتَطَعْتَ" }
        if slot == 3 { return "اِسْتَطَعْتِ" }
        if slot == 4 { return "اِسْتَطَعْتُ" }
        if slot == 5 { return "اِسْتَطَاعُوا" }
        if slot == 6 { return "اِسْتَطَعْنَ" }
        if slot == 7 { return "اِسْتَطَعْتُمْ" }
        if slot == 8 { return "اِسْتَطَعْتُنَّ" }
        return "اِسْتَطَعْنَا"
    }
    if str_eq(tense, "present") {
        if slot == 0 { return "يَسْتَطِيعُ" }
        if slot == 1 { return "تَسْتَطِيعُ" }
        if slot == 2 { return "تَسْتَطِيعُ" }
        if slot == 3 { return "تَسْتَطِيعِينَ" }
        if slot == 4 { return "أَسْتَطِيعُ" }
        if slot == 5 { return "يَسْتَطِيعُونَ" }
        if slot == 6 { return "يَسْتَطِعْنَ" }
        if slot == 7 { return "تَسْتَطِيعُونَ" }
        if slot == 8 { return "تَسْتَطِعْنَ" }
        return "نَسْتَطِيعُ"
    }
    if str_eq(tense, "future") {
        let pres: String = ar_irregular_istata(slot, "present")
        return "سَ" + pres
    }
    return "اِسْتَطَاعَ"
}

// ── Irregular verb dispatcher ─────────────────────────────────────────────────
//
// ar_irregular: returns the inflected form if verb is in the lookup table,
// or "" if not found (caller should use Form I rules).
//
// verb:  3ms past form (dictionary key) as Arabic string
// tense: "past" | "present" | "future"
// slot:  ar_slot result

fn ar_irregular(verb: String, tense: String, slot: Int) -> String {
    if str_eq(verb, "كَانَ")       { return ar_irregular_kaana(slot, tense) }
    if str_eq(verb, "قَالَ")       { return ar_irregular_qaala(slot, tense) }
    if str_eq(verb, "جَاءَ")       { return ar_irregular_jaa(slot, tense) }
    if str_eq(verb, "رَأَى")       { return ar_irregular_raaa(slot, tense) }
    if str_eq(verb, "أَرَادَ")     { return ar_irregular_araada(slot, tense) }
    if str_eq(verb, "اِسْتَطَاعَ") { return ar_irregular_istata(slot, tense) }
    return ""
}

// ── Regular Form I verb table ─────────────────────────────────────────────────
//
// For regular Form I verbs that would be correctly generated by ar_conjugate_form1
// but whose imperfect stem must be looked up (Arabic verbs have three vowel
// classes for the imperfect medial vowel: a, i, u — فَعَلَ/يَفْعَلُ,
// فَعِلَ/يَفْعَلُ, فَعَلَ/يَفْعُلُ).  We store the present stem for each.
//
// Returns present_stem (the imperfect without prefix, e.g. "كْتُبُ" for yaktubu),
// or "" if not in table.

fn ar_present_stem(verb: String) -> String {
    if str_eq(verb, "كَتَبَ")   { return "كْتُبُ" }   // kataba  -> yaktubu  (u-class)
    if str_eq(verb, "ذَهَبَ")   { return "ذْهَبُ" }   // dhahaba -> yadhhabu (a-class)
    if str_eq(verb, "أَكَلَ")   { return "أْكُلُ" }   // akala   -> yaakulu  (u-class)
    if str_eq(verb, "شَرِبَ")   { return "شْرَبُ" }   // shariba -> yashrabu (a-class)
    if str_eq(verb, "عَرَفَ")   { return "عْرِفُ" }   // arafa   -> yarifu   (i-class)
    if str_eq(verb, "فَعَلَ")   { return "فْعَلُ" }   // fa'ala  -> yaf'alu  (a-class)
    if str_eq(verb, "أَخَذَ")   { return "أْخُذُ" }   // akhadha -> yaakhudhu (u-class)
    if str_eq(verb, "عَمِلَ")   { return "عْمَلُ" }   // amila   -> ya'malu  (a-class)
    if str_eq(verb, "دَرَسَ")   { return "دْرُسُ" }   // darasa  -> yadrusu  (u-class)
    if str_eq(verb, "فَهِمَ")   { return "فْهَمُ" }   // fahima  -> yafhamu  (a-class)
    if str_eq(verb, "سَمِعَ")   { return "سْمَعُ" }   // sami'a  -> yasma'u  (a-class)
    if str_eq(verb, "جَلَسَ")   { return "جْلِسُ" }   // jalasa  -> yajlisu  (i-class)
    if str_eq(verb, "فَتَحَ")   { return "فْتَحُ" }   // fataha  -> yaftahu  (a-class)
    if str_eq(verb, "خَرَجَ")   { return "خْرُجُ" }   // kharaja -> yakhruju (u-class)
    if str_eq(verb, "دَخَلَ")   { return "دْخُلُ" }   // dakhala -> yadkhulu (u-class)
    if str_eq(verb, "وَجَدَ")   { return "جِدُ" }     // wajada  -> yajidu   (i-class, waw-initial)
    if str_eq(verb, "صَنَعَ")   { return "صْنَعُ" }   // sana'a  -> yasna'u  (a-class)
    if str_eq(verb, "رَجَعَ")   { return "رْجِعُ" }   // raja'a  -> yarji'u  (i-class)
    if str_eq(verb, "وَقَفَ")   { return "قِفُ" }     // waqafa  -> yaqifu   (i-class, waw-initial)
    if str_eq(verb, "قَرَأَ")   { return "قْرَأُ" }   // qara'a  -> yaqra'u  (a-class)
    if str_eq(verb, "كَذَبَ")   { return "كْذِبُ" }   // kadhaba -> yakdhibu (i-class)
    return ""
}

// ── Main conjugation dispatcher ───────────────────────────────────────────────
//
// ar_conjugate: conjugate an Arabic verb.
//
// verb:   3ms perfect form (dictionary key), e.g. "كَتَبَ"
// tense:  "past" | "present" | "future"
// person: "first" | "second" | "third"
// gender: "m" | "f"
// number: "singular" | "plural"

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

    // 1. Check irregular table
    let irreg: String = ar_irregular(verb, tense, slot)
    if !str_eq(irreg, "") {
        return irreg
    }

    // 2. Look up present stem for regular Form I
    let present_stem: String = ar_present_stem(verb)
    if !str_eq(present_stem, "") {
        return ar_conjugate_form1(verb, present_stem, tense, slot)
    }

    // 3. Fallback: return base form (3ms past) — unknown verb
    return verb
}

// ── Definite article ──────────────────────────────────────────────────────────
//
// ar_definite_article: prefix ال (al-) to a noun with sun/moon letter handling.
//
// Sun letters (الحروف الشمسية) cause the lam of the article to assimilate to
// the first letter of the noun.  Moon letters (الحروف القمرية) do not.
//
// Sun letters (Unicode Arabic code points):
//   ت ث د ذ ر ز س ش ص ض ط ظ ل ن
//
// Moon letters (all others):
//   أ ب ج ح خ ع غ ف ق ك م ه و ي
//
// In Arabic orthography the assimilation is shown with a shadda on the sun letter.
// Here we return "ال" (al-) for moon letters and the assimilated form for sun
// letters.  The noun is prefixed with the article; the article lam is replaced
// by a shadda on the sun consonant.

fn ar_is_sun_letter(c: String) -> Bool {
    if str_eq(c, "ت") { return true }
    if str_eq(c, "ث") { return true }
    if str_eq(c, "د") { return true }
    if str_eq(c, "ذ") { return true }
    if str_eq(c, "ر") { return true }
    if str_eq(c, "ز") { return true }
    if str_eq(c, "س") { return true }
    if str_eq(c, "ش") { return true }
    if str_eq(c, "ص") { return true }
    if str_eq(c, "ض") { return true }
    if str_eq(c, "ط") { return true }
    if str_eq(c, "ظ") { return true }
    if str_eq(c, "ل") { return true }
    if str_eq(c, "ن") { return true }
    return false
}

fn ar_definite_article(noun: String) -> String {
    // Extract first character to determine sun/moon
    let n: Int = ar_str_len(noun)
    if n == 0 {
        return noun
    }
    let first: String = str_slice(noun, 0, 1)
    if ar_is_sun_letter(first) {
        // Sun letter: article lam assimilates -> الـ + shadda on first letter
        // Written as: أَلْ + first + shadda + rest
        // We represent this as "ال" + first_with_shadda + rest_of_noun
        // The shadda diacritic (U+0651) attaches to the sun letter.
        let shadda: String = "ّ"
        let rest: String = str_slice(noun, 1, n)
        return "ال" + first + shadda + rest
    }
    // Moon letter: simple al- prefix
    return "ال" + noun
}

// ── Case endings ──────────────────────────────────────────────────────────────
//
// ar_case_ending: return the short vowel ending for a noun given its gram_case
// and definiteness.
//
// case:     "nom" | "acc" | "gen"
// definite: "true" | "false"
//
// Indefinite endings carry nunation (tanwin):
//   nom: -un (ٌ)
//   acc: -an (ً)
//   gen: -in (ٍ)
//
// Definite endings are single short vowels:
//   nom: -u (ُ)
//   acc: -a (َ)
//   gen: -i (ِ)

fn ar_case_ending(kase: String, definite: String) -> String {
    let is_def: Bool = str_eq(definite, "true")
    if str_eq(kase, "nom") {
        if is_def { return "ُ" }
        return "ٌ"
    }
    if str_eq(kase, "acc") {
        if is_def { return "َ" }
        return "ً"
    }
    if str_eq(kase, "gen") {
        if is_def { return "ِ" }
        return "ٍ"
    }
    return ""
}

// ── Gender inference ──────────────────────────────────────────────────────────
//
// ar_gender: infer gender from noun form.
// Returns "f" for nouns ending in taa marbuta (ة or ـة), otherwise "m".
// This covers the most reliable heuristic; broken plurals and loanwords may
// vary but are handled by explicit lookup in the Engram.

fn ar_gender(noun: String) -> String {
    if ar_str_ends(noun, "ة")  { return "f" }
    if ar_str_ends(noun, "ـة") { return "f" }
    return "m"
}

// ── Sound plurals ─────────────────────────────────────────────────────────────
//
// ar_sound_plural: form the sound masculine or feminine plural.
//
// Sound masculine plural (جمع المذكر السالم):
//   nom:  -uuna (ونَ)
//   acc/gen: -iina (ينَ)
//
// Sound feminine plural (جمع المؤنث السالم):
//   Remove final ة (taa marbuta) if present, then add -aat (اتٌ/اتُ).
//
// This function returns the base plural form (without case ending) suitable
// for passing to ar_noun_form.  For masculine plural case variation, callers
// should use ar_masc_pl_ending.

fn ar_masc_pl_ending(kase: String) -> String {
    if str_eq(kase, "nom") { return "ونَ" }
    // acc and gen both use -iina in sound masculine plural
    return "ينَ"
}

fn ar_sound_plural(noun: String, gender: String) -> String {
    if str_eq(gender, "f") {
        // Feminine sound plural: drop ة, add ات
        if ar_str_ends(noun, "ة") {
            let base: String = ar_str_drop_last(noun, 1)
            return base + "ات"
        }
        return noun + "ات"
    }
    // Masculine sound plural (nominative form as default): -uuna
    return noun + "ون"
}

// ── Full noun inflection ──────────────────────────────────────────────────────
//
// ar_noun_form: produce the inflected noun form.
//
// noun:     base (singular) noun string
// gender:   "m" | "f" (pass "" to infer from noun ending)
// kase:     "nom" | "acc" | "gen" | "" (no case ending added)
// number:   "singular" | "plural"
// definite: "true" | "false"
//
// For plurals, the function applies the sound plural (broken plurals are
// language-external and must be supplied via Engram vocabulary nodes).

fn ar_noun_form(noun: String, gender: String, kase: String, number: String, definite: String) -> String {
    // Resolve gender
    let g: String = gender
    if str_eq(g, "") {
        let g = ar_gender(noun)
    }

    // Build the stem (with definiteness and number)
    let stem: String = noun
    if str_eq(number, "plural") {
        if str_eq(g, "m") {
            // Masculine sound plural: stem + case-dependent ending
            let pl_suf: String = ar_masc_pl_ending(kase)
            if str_eq(definite, "true") {
                let def_stem: String = ar_definite_article(noun)
                return def_stem + pl_suf
            }
            return noun + pl_suf
        }
        // Feminine plural: drop ة, add ات + case ending
        let fem_pl: String = ar_sound_plural(noun, "f")
        let case_end: String = ar_case_ending(kase, definite)
        if str_eq(definite, "true") {
            return ar_definite_article(fem_pl) + case_end
        }
        return fem_pl + case_end
    }

    // Singular
    let case_end: String = ar_case_ending(kase, definite)
    if str_eq(definite, "true") {
        let def_stem: String = ar_definite_article(noun)
        return def_stem + case_end
    }
    return noun + case_end
}

// ── Convenience: verb inflect entry point ─────────────────────────────────────
//
// ar_verb_form: thin wrapper matching the signature style of the main engine.
// Accepts gender as part of person encoding: "third_m" | "third_f" | "first" | "second_m" | "second_f".
// Alternatively accepts explicit gender param.

fn ar_verb_form(verb: String, tense: String, person: String, number: String) -> String {
    // Default gender to masculine
    return ar_conjugate(verb, tense, person, "m", number)
}
