// morphology-fro.el - Old French morphology for the NLG engine.
//
// Implements Old French verb conjugation, noun declension, and the definite
// article.  Designed as a companion to morphology.el and called by the engine
// when the language profile code is "fro".
//
// Language profile: code=fro, name=Old French, morph_type=fusional,
//   word_order=V2, question_strategy=inversion, script=latin,
//   family=romance.
//
// Historical note: Old French (ca. 900–1400 CE) is the ancestor of Modern
// French.  It diverged from Vulgar Latin and retained a two-case system —
// nominative (cas sujet) and oblique (cas régime) — inherited ultimately from
// Latin.  By around 1300 CE the case distinction had largely collapsed in
// spoken usage, surviving mainly in formal written registers until it
// disappeared altogether.  This file targets the core Old French period
// (ca. 1000–1300).
//
// Two-case system (masculine nouns):
//   Singular:  nominative stem + -s  (li murs = the wall [subject])
//              oblique    stem       (le mur  = the wall [object])
//   Plural:    nominative stem       (li mur  = the walls [subject])
//              oblique    stem + -s  (les murs = the walls [object])
//   Feminine nouns show no case distinction throughout.
//
// Verb conjugation covered:
//   Tenses:   present indicative, passé simple (past), future
//   Persons:  first/second/third × singular/plural (slots 0-5)
//   Conjugations:
//     1st (-er):  present -e/-es/-e/-ons/-ez/-ent
//                 passé simple -ai/-as/-a/-ames/-astes/-erent
//                 future stem+rai/ras/ra/rons/rez/ront
//     2nd (-ir):  present -is/-is/-it/-issons/-issiez/-issent
//                 passé simple -is/-is/-it/-imes/-istes/-irent
//                 future stem+rai series
//     3rd (-re):  present stem/s/t/-ons/-ez/-ent
//                 passé simple -is series (like 2nd)
//                 future stem+rai series
//   Irregulars: estre (be), avoir (have), aler (go), venir (come),
//               faire (do/make)
//   Canonical map: "be" -> "estre"
//
// Noun declension covered:
//   Masculine: two-case (nom/obl) × sg/pl as above
//   Feminine:  case-neutral, sg base / pl base + -s
//   Gender detection: -e ending -> feminine (heuristic), else masculine
//
// Article:
//   Definite masculine nom sg: li;  obl sg: le;  nom pl: li;  obl pl: les
//   Definite feminine sg: la;  pl: les
//
// Depends on: morphology.el (str_eq, str_len, str_slice, str_ends_with)

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

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

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

// ── Person/number slot ─────────────────────────────────────────────────────────
//
// Maps person × number to a 0-based paradigm index.
//   0 = 1st singular  (je)
//   1 = 2nd singular  (tu)
//   2 = 3rd singular  (il/ele)
//   3 = 1st plural    (nos)
//   4 = 2nd plural    (vos)
//   5 = 3rd plural    (il/eles)

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

// ── Canonical verb mapping ─────────────────────────────────────────────────────
//
// English semantic-layer labels are resolved to Old French dictionary infinitives
// before conjugation.

fn fro_map_canonical(verb: String) -> String {
    if str_eq(verb, "be")   { return "estre" }
    if str_eq(verb, "have") { return "avoir" }
    if str_eq(verb, "go")   { return "aler" }
    if str_eq(verb, "come") { return "venir" }
    if str_eq(verb, "do")   { return "faire" }
    if str_eq(verb, "make") { return "faire" }
    if str_eq(verb, "say")  { return "dire" }
    if str_eq(verb, "see")  { return "veoir" }
    if str_eq(verb, "want") { return "vouloir" }
    if str_eq(verb, "can")  { return "pooir" }
    return verb
}

// ── Irregular verb: estre (to be) ─────────────────────────────────────────────
//
// Suppletive paradigm — one of the most irregular verbs in Old French.
//
// Present indicative:
//   1sg sui     2sg es      3sg est
//   1pl somes   2pl estes   3pl sont
//
// Passé simple (past):
//   1sg fui     2sg fus     3sg fu
//   1pl fumes   2pl fustes  3pl furent
//
// Future (periphrastic, based on ester- stem):
//   1sg esterai  2sg esteras  3sg estera
//   1pl esterons 2pl esterez  3pl esteront

fn fro_estre_present(slot: Int) -> String {
    if slot == 0 { return "sui" }
    if slot == 1 { return "es" }
    if slot == 2 { return "est" }
    if slot == 3 { return "somes" }
    if slot == 4 { return "estes" }
    return "sont"
}

fn fro_estre_past(slot: Int) -> String {
    if slot == 0 { return "fui" }
    if slot == 1 { return "fus" }
    if slot == 2 { return "fu" }
    if slot == 3 { return "fumes" }
    if slot == 4 { return "fustes" }
    return "furent"
}

fn fro_estre_future(slot: Int) -> String {
    if slot == 0 { return "esterai" }
    if slot == 1 { return "esteras" }
    if slot == 2 { return "estera" }
    if slot == 3 { return "esterons" }
    if slot == 4 { return "esterez" }
    return "esteront"
}

// ── Irregular verb: avoir (to have) ───────────────────────────────────────────
//
// Present indicative:
//   1sg ai    2sg as    3sg a
//   1pl avons 2pl avez  3pl ont
//
// Passé simple:
//   1sg oi    2sg os    3sg ot
//   1pl eumes 2pl eustes 3pl orent
//
// Future:
//   1sg avrai 2sg avras 3sg avra
//   1pl avrons 2pl avrez 3pl avront

fn fro_avoir_present(slot: Int) -> String {
    if slot == 0 { return "ai" }
    if slot == 1 { return "as" }
    if slot == 2 { return "a" }
    if slot == 3 { return "avons" }
    if slot == 4 { return "avez" }
    return "ont"
}

fn fro_avoir_past(slot: Int) -> String {
    if slot == 0 { return "oi" }
    if slot == 1 { return "os" }
    if slot == 2 { return "ot" }
    if slot == 3 { return "eumes" }
    if slot == 4 { return "eustes" }
    return "orent"
}

fn fro_avoir_future(slot: Int) -> String {
    if slot == 0 { return "avrai" }
    if slot == 1 { return "avras" }
    if slot == 2 { return "avra" }
    if slot == 3 { return "avrons" }
    if slot == 4 { return "avrez" }
    return "avront"
}

// ── Irregular verb: aler (to go) ──────────────────────────────────────────────
//
// Highly suppletive — present draws on Latin *vadere (vois- stem).
//
// Present indicative:
//   1sg vois  2sg vas   3sg va
//   1pl alons 2pl alez  3pl vont
//
// Passé simple (regular -er pattern on al-):
//   1sg alai  2sg alas  3sg ala
//   1pl alames 2pl alastes 3pl alerent
//
// Future (ir- stem, archaic):
//   1sg irai  2sg iras  3sg ira
//   1pl irons 2pl irez  3pl iront

fn fro_aler_present(slot: Int) -> String {
    if slot == 0 { return "vois" }
    if slot == 1 { return "vas" }
    if slot == 2 { return "va" }
    if slot == 3 { return "alons" }
    if slot == 4 { return "alez" }
    return "vont"
}

fn fro_aler_past(slot: Int) -> String {
    if slot == 0 { return "alai" }
    if slot == 1 { return "alas" }
    if slot == 2 { return "ala" }
    if slot == 3 { return "alames" }
    if slot == 4 { return "alastes" }
    return "alerent"
}

fn fro_aler_future(slot: Int) -> String {
    if slot == 0 { return "irai" }
    if slot == 1 { return "iras" }
    if slot == 2 { return "ira" }
    if slot == 3 { return "irons" }
    if slot == 4 { return "irez" }
    return "iront"
}

// ── Irregular verb: venir (to come) ───────────────────────────────────────────
//
// Present indicative (vien-/ven- alternation):
//   1sg vieng  2sg viens  3sg vient
//   1pl venons 2pl venez  3pl vienent
//
// Passé simple:
//   1sg ving   2sg vins   3sg vint
//   1pl vinsmes 2pl vinstes 3pl vindrent
//
// Future (venr- stem):
//   1sg venrai 2sg venras 3sg venra
//   1pl venrons 2pl venrez 3pl venront

fn fro_venir_present(slot: Int) -> String {
    if slot == 0 { return "vieng" }
    if slot == 1 { return "viens" }
    if slot == 2 { return "vient" }
    if slot == 3 { return "venons" }
    if slot == 4 { return "venez" }
    return "vienent"
}

fn fro_venir_past(slot: Int) -> String {
    if slot == 0 { return "ving" }
    if slot == 1 { return "vins" }
    if slot == 2 { return "vint" }
    if slot == 3 { return "vinsmes" }
    if slot == 4 { return "vinstes" }
    return "vindrent"
}

fn fro_venir_future(slot: Int) -> String {
    if slot == 0 { return "venrai" }
    if slot == 1 { return "venras" }
    if slot == 2 { return "venra" }
    if slot == 3 { return "venrons" }
    if slot == 4 { return "venrez" }
    return "venront"
}

// ── Irregular verb: faire (to do/make) ────────────────────────────────────────
//
// Present indicative (faz/fais- alternation):
//   1sg faz    2sg fais   3sg fait
//   1pl faisons 2pl faites 3pl font
//
// Passé simple:
//   1sg fis    2sg fis    3sg fist
//   1pl fimes  2pl fistes 3pl firent
//
// Future (fer- stem):
//   1sg ferai  2sg feras  3sg fera
//   1pl ferons 2pl ferez  3pl feront

fn fro_faire_present(slot: Int) -> String {
    if slot == 0 { return "faz" }
    if slot == 1 { return "fais" }
    if slot == 2 { return "fait" }
    if slot == 3 { return "faisons" }
    if slot == 4 { return "faites" }
    return "font"
}

fn fro_faire_past(slot: Int) -> String {
    if slot == 0 { return "fis" }
    if slot == 1 { return "fis" }
    if slot == 2 { return "fist" }
    if slot == 3 { return "fimes" }
    if slot == 4 { return "fistes" }
    return "firent"
}

fn fro_faire_future(slot: Int) -> String {
    if slot == 0 { return "ferai" }
    if slot == 1 { return "feras" }
    if slot == 2 { return "fera" }
    if slot == 3 { return "ferons" }
    if slot == 4 { return "ferez" }
    return "feront"
}

// ── Conjugation class detection ────────────────────────────────────────────────
//
// Old French verbs fall into three broad conjugation classes:
//   1st conjugation: infinitive ends in -er  (chanter, donner)
//   2nd conjugation: infinitive ends in -ir  (finir, choisir)
//   3rd conjugation: infinitive ends in -re  (vendre, rendre)
//
// Returns "1", "2", or "3".

fn fro_verb_class(verb: String) -> String {
    if fro_str_ends(verb, "er") { return "1" }
    if fro_str_ends(verb, "ir") { return "2" }
    if fro_str_ends(verb, "re") { return "3" }
    return "1"
}

// fro_verb_stem: strip the infinitive suffix to expose the productive stem.
//   1st (-er): drop 2 bytes
//   2nd (-ir): drop 2 bytes
//   3rd (-re): drop 2 bytes

fn fro_verb_stem(verb: String, vclass: String) -> String {
    return fro_drop(verb, 2)
}

// ── 1st conjugation (-er): regular endings ────────────────────────────────────
//
// Present indicative (stem + ending):
//   1sg -e    2sg -es   3sg -e
//   1pl -ons  2pl -ez   3pl -ent
//
// Passé simple:
//   1sg -ai   2sg -as   3sg -a
//   1pl -ames 2pl -astes 3pl -erent
//
// Future (infinitive is the base — drop -r then add endings):
//   Actually the future stem = infinitive minus final -r (chanter- -> chanterai)
//   1sg -ai   2sg -as   3sg -a
//   1pl -ons  2pl -ez   3pl -ont
//   Combined with chanterr-: chant+er+ai = chanterai; stem for future = infinitive + "a"...
//   Simpler: future base = fro_drop(verb, 1) i.e. drop final -r to keep the -e:
//   chanterai, chanteras, chantera, chanterons, chanterez, chanteront

fn fro_conj1_present(stem: String, slot: Int) -> String {
    if slot == 0 { return stem + "e" }
    if slot == 1 { return stem + "es" }
    if slot == 2 { return stem + "e" }
    if slot == 3 { return stem + "ons" }
    if slot == 4 { return stem + "ez" }
    return stem + "ent"
}

fn fro_conj1_past(stem: String, slot: Int) -> String {
    if slot == 0 { return stem + "ai" }
    if slot == 1 { return stem + "as" }
    if slot == 2 { return stem + "a" }
    if slot == 3 { return stem + "ames" }
    if slot == 4 { return stem + "astes" }
    return stem + "erent"
}

fn fro_conj1_future(verb: String, slot: Int) -> String {
    // Future base = infinitive minus final -r (retains the -e): chanter -> chante-
    let base: String = fro_drop(verb, 1)
    if slot == 0 { return base + "rai" }
    if slot == 1 { return base + "ras" }
    if slot == 2 { return base + "ra" }
    if slot == 3 { return base + "rons" }
    if slot == 4 { return base + "rez" }
    return base + "ront"
}

// ── 2nd conjugation (-ir): regular endings ────────────────────────────────────
//
// Present indicative uses an infix -iss- in pl forms (inchoative):
//   1sg stem + -is    2sg stem + -is    3sg stem + -it
//   1pl stem + -issons 2pl stem + -issiez 3pl stem + -issent
//
// Passé simple:
//   1sg stem + -is   2sg stem + -is   3sg stem + -it
//   1pl stem + -imes 2pl stem + -istes 3pl stem + -irent
//
// Future (infinitive minus final -r):
//   finir -> fini- -> finirai ...

fn fro_conj2_present(stem: String, slot: Int) -> String {
    if slot == 0 { return stem + "is" }
    if slot == 1 { return stem + "is" }
    if slot == 2 { return stem + "it" }
    if slot == 3 { return stem + "issons" }
    if slot == 4 { return stem + "issiez" }
    return stem + "issent"
}

fn fro_conj2_past(stem: String, slot: Int) -> String {
    if slot == 0 { return stem + "is" }
    if slot == 1 { return stem + "is" }
    if slot == 2 { return stem + "it" }
    if slot == 3 { return stem + "imes" }
    if slot == 4 { return stem + "istes" }
    return stem + "irent"
}

fn fro_conj2_future(verb: String, slot: Int) -> String {
    let base: String = fro_drop(verb, 1)
    if slot == 0 { return base + "rai" }
    if slot == 1 { return base + "ras" }
    if slot == 2 { return base + "ra" }
    if slot == 3 { return base + "rons" }
    if slot == 4 { return base + "rez" }
    return base + "ront"
}

// ── 3rd conjugation (-re): regular endings ────────────────────────────────────
//
// Present indicative:
//   1sg stem (no ending)  2sg stem + -s   3sg stem + -t
//   1pl stem + -ons       2pl stem + -ez  3pl stem + -ent
//
// Passé simple (same endings as 2nd conj):
//   1sg stem + -is  2sg stem + -is  3sg stem + -it
//   1pl stem + -imes 2pl stem + -istes 3pl stem + -irent
//
// Future (-re verbs drop -e before adding endings):
//   vendre -> vendr- -> vendrai ...

fn fro_conj3_present(stem: String, slot: Int) -> String {
    if slot == 0 { return stem }
    if slot == 1 { return stem + "s" }
    if slot == 2 { return stem + "t" }
    if slot == 3 { return stem + "ons" }
    if slot == 4 { return stem + "ez" }
    return stem + "ent"
}

fn fro_conj3_past(stem: String, slot: Int) -> String {
    if slot == 0 { return stem + "is" }
    if slot == 1 { return stem + "is" }
    if slot == 2 { return stem + "it" }
    if slot == 3 { return stem + "imes" }
    if slot == 4 { return stem + "istes" }
    return stem + "irent"
}

fn fro_conj3_future(verb: String, slot: Int) -> String {
    // Drop -re (2 bytes) to get consonant-final stem, then add -rai etc.
    let base: String = fro_drop(verb, 2)
    if slot == 0 { return base + "rai" }
    if slot == 1 { return base + "ras" }
    if slot == 2 { return base + "ra" }
    if slot == 3 { return base + "rons" }
    if slot == 4 { return base + "rez" }
    return base + "ront"
}

// ── fro_conjugate: main conjugation entry point ───────────────────────────────
//
// verb:   Old French infinitive (e.g. "chanter", "finir", "vendre")
//         or English canonical label ("be", "go", "have", ...)
// tense:  "present" | "past" | "future"
// person: "first" | "second" | "third"
// number: "singular" | "plural"
//
// Returns the inflected form.  Unknown tenses fall back to the infinitive.

fn fro_conjugate(verb: String, tense: String, person: String, number: String) -> String {
    let v: String = fro_map_canonical(verb)
    let slot: Int = fro_slot(person, number)

    // ── Irregular: estre (to be) ──────────────────────────────────────────────
    if str_eq(v, "estre") {
        if str_eq(tense, "present") { return fro_estre_present(slot) }
        if str_eq(tense, "past")    { return fro_estre_past(slot) }
        if str_eq(tense, "future")  { return fro_estre_future(slot) }
        return v
    }

    // ── Irregular: avoir (to have) ────────────────────────────────────────────
    if str_eq(v, "avoir") {
        if str_eq(tense, "present") { return fro_avoir_present(slot) }
        if str_eq(tense, "past")    { return fro_avoir_past(slot) }
        if str_eq(tense, "future")  { return fro_avoir_future(slot) }
        return v
    }

    // ── Irregular: aler (to go) ───────────────────────────────────────────────
    if str_eq(v, "aler") {
        if str_eq(tense, "present") { return fro_aler_present(slot) }
        if str_eq(tense, "past")    { return fro_aler_past(slot) }
        if str_eq(tense, "future")  { return fro_aler_future(slot) }
        return v
    }

    // ── Irregular: venir (to come) ────────────────────────────────────────────
    if str_eq(v, "venir") {
        if str_eq(tense, "present") { return fro_venir_present(slot) }
        if str_eq(tense, "past")    { return fro_venir_past(slot) }
        if str_eq(tense, "future")  { return fro_venir_future(slot) }
        return v
    }

    // ── Irregular: faire (to do/make) ─────────────────────────────────────────
    if str_eq(v, "faire") {
        if str_eq(tense, "present") { return fro_faire_present(slot) }
        if str_eq(tense, "past")    { return fro_faire_past(slot) }
        if str_eq(tense, "future")  { return fro_faire_future(slot) }
        return v
    }

    // ── Regular conjugations ──────────────────────────────────────────────────
    let vclass: String = fro_verb_class(v)
    let stem: String = fro_verb_stem(v, vclass)

    if str_eq(vclass, "1") {
        if str_eq(tense, "present") { return fro_conj1_present(stem, slot) }
        if str_eq(tense, "past")    { return fro_conj1_past(stem, slot) }
        if str_eq(tense, "future")  { return fro_conj1_future(v, slot) }
        return v
    }

    if str_eq(vclass, "2") {
        if str_eq(tense, "present") { return fro_conj2_present(stem, slot) }
        if str_eq(tense, "past")    { return fro_conj2_past(stem, slot) }
        if str_eq(tense, "future")  { return fro_conj2_future(v, slot) }
        return v
    }

    if str_eq(vclass, "3") {
        if str_eq(tense, "present") { return fro_conj3_present(stem, slot) }
        if str_eq(tense, "past")    { return fro_conj3_past(stem, slot) }
        if str_eq(tense, "future")  { return fro_conj3_future(v, slot) }
        return v
    }

    // Final fallback: return the infinitive
    return v
}

// ── Gender detection ───────────────────────────────────────────────────────────
//
// Heuristic gender detection from the citation form (nominative singular).
// Old French gender was inherited from Latin with only two genders surviving:
// masculine and feminine (neuter collapsed into masculine/feminine by Vulgar Latin).
//
// Heuristic: citation form ending in -e -> feminine; otherwise -> masculine.
// This is imperfect but covers the majority of common nouns.

fn fro_gender(noun: String) -> String {
    if fro_str_ends(noun, "e") { return "fem" }
    return "masc"
}

// ── Noun declension ────────────────────────────────────────────────────────────
//
// Old French two-case system:
//
// Masculine (e.g. mur — wall, stem = mur):
//   Singular nominative (cas sujet):  murs   (stem + -s)
//   Singular oblique (cas régime):    mur    (stem)
//   Plural nominative:                mur    (stem)
//   Plural oblique:                   murs   (stem + -s)
//
// This pattern means nominative markers invert relative to Latin:
// the nominative takes -s in singular but loses it in plural,
// while the oblique works the other way round.
//
// Feminine (e.g. dame — lady):
//   No case distinction throughout.
//   Singular: dame  (citation form)
//   Plural:   dames (citation + -s)
//
// gram_case: "nominative" | "oblique"
// number:    "singular" | "plural"

fn fro_decline_masc(noun: String, gram_case: String, number: String) -> String {
    if str_eq(number, "singular") {
        if str_eq(gram_case, "nominative") { return noun + "s" }
        // oblique singular: bare stem
        return noun
    }
    // plural
    if str_eq(gram_case, "nominative") { return noun }
    return noun + "s"
}

fn fro_decline_fem(noun: String, number: String) -> String {
    if str_eq(number, "singular") { return noun }
    return noun + "s"
}

// fro_decline: main declension entry point.
//
// noun:      citation form (nominative/oblique singular — typically the bare stem)
// gram_case: "nominative" | "oblique"
// number:    "singular" | "plural"

fn fro_decline(noun: String, gram_case: String, number: String) -> String {
    let gender: String = fro_gender(noun)
    if str_eq(gender, "masc") {
        return fro_decline_masc(noun, gram_case, number)
    }
    return fro_decline_fem(noun, number)
}

// ── Definite article ──────────────────────────────────────────────────────────
//
// Old French definite articles are case- and gender-sensitive:
//
// Masculine:
//   nom sg: li    obl sg: le
//   nom pl: li    obl pl: les
//
// Feminine:
//   sg: la         pl: les
//
// gender:    "masc" | "fem"
// gram_case: "nominative" | "oblique"
// number:    "singular" | "plural"

fn fro_article(gender: String, gram_case: String, number: String) -> String {
    if str_eq(gender, "masc") {
        if str_eq(number, "plural") { return "les" }
        if str_eq(gram_case, "nominative") { return "li" }
        return "le"
    }
    // feminine
    if str_eq(number, "plural") { return "les" }
    return "la"
}

// ── fro_noun_phrase: noun phrase builder ──────────────────────────────────────
//
// Assembles a declined noun with an optional definite article.
//
// noun:      citation form (nominative/oblique singular stem)
// gram_case: "nominative" | "oblique"
// number:    "singular" | "plural"
// definite:  "true" to prepend the definite article; any other value omits it

fn fro_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String {
    let gender: String = fro_gender(noun)
    let declined: String = fro_decline(noun, gram_case, number)

    if str_eq(definite, "true") {
        let art: String = fro_article(gender, gram_case, number)
        return art + " " + declined
    }

    return declined
}
