// morphology-enm.el - Middle English morphology for the NLG engine.
//
// Implements Middle English verb conjugation and noun declension for the
// ca. 1100-1500 CE period (Chaucerian English).  Designed as a companion to
// morphology.el and called by the engine when the language profile code is "enm".
//
// Language profile: code=enm, name=Middle English, morph_type=analytic,
//   word_order=SVO, question_strategy=inversion, script=latin, family=germanic.
//
// Verb conjugation covered:
//   Tenses:   present, past
//   Persons:  first/second/third x singular/plural (slots 0-5)
//   Classes:  weak (productive: -est 2sg, -eth 3sg, -en pl; past: -ede/-de/-te)
//   Irregulars: been/ben (be), han/haven (have), goon (go), seen (see),
//               seyn/seyen (say), comen (come), maken (make)
//   Canonical map: "be" -> "been"
//
// Noun declension covered:
//   Middle English has largely lost case endings.  This module handles:
//     - nominative (base form)
//     - genitive singular (+es)
//     - plural (+es default; irregular forms for common words)
//   Common irregulars: man->men, child->children, ox->oxen, foot->feet,
//                      tooth->teeth
//
// Article formation:
//   Definite:   "the" prepended
//   Indefinite: "a" or "an" based on the first letter of the noun phrase
//
// Depends on: morphology.el (str_ends_with, str_len, str_slice, str_eq)

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

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

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

fn enm_first_char(s: String) -> String {
    if str_len(s) == 0 { return "" }
    return str_slice(s, 0, 1)
}

// ── Person/number slot ─────────────────────────────────────────────────────────
//
// Maps person x number to a 0-based paradigm slot.
//   0 = 1st singular   (I / ich)
//   1 = 2nd singular   (thou)
//   2 = 3rd singular   (he / she / it)
//   3 = 1st plural     (we)
//   4 = 2nd plural     (ye)
//   5 = 3rd plural     (they)

fn enm_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
    if str_eq(number, "singular") { return 2 }
    return 5
}

// ── Irregular verb tables ──────────────────────────────────────────────────────
//
// Each irregular verb has a present and past paradigm of six forms (slots 0-5).
// Forms are in Middle English spelling, close to Chaucerian usage.

fn enm_been_present(slot: Int) -> String {
    if slot == 0 { return "am" }
    if slot == 1 { return "art" }
    if slot == 2 { return "is" }
    if slot == 3 { return "aren" }
    if slot == 4 { return "been" }
    return "been"
}

fn enm_been_past(slot: Int) -> String {
    if slot == 0 { return "was" }
    if slot == 1 { return "were" }
    if slot == 2 { return "was" }
    if slot == 3 { return "were" }
    if slot == 4 { return "were" }
    return "were"
}

fn enm_haven_present(slot: Int) -> String {
    if slot == 0 { return "have" }
    if slot == 1 { return "hast" }
    if slot == 2 { return "hath" }
    if slot == 3 { return "have" }
    if slot == 4 { return "have" }
    return "have"
}

fn enm_haven_past(slot: Int) -> String {
    if slot == 0 { return "hadde" }
    if slot == 1 { return "haddest" }
    if slot == 2 { return "hadde" }
    if slot == 3 { return "hadden" }
    if slot == 4 { return "hadden" }
    return "hadden"
}

fn enm_goon_present(slot: Int) -> String {
    if slot == 0 { return "go" }
    if slot == 1 { return "goost" }
    if slot == 2 { return "gooth" }
    if slot == 3 { return "goon" }
    if slot == 4 { return "goon" }
    return "goon"
}

fn enm_goon_past(slot: Int) -> String {
    if slot == 0 { return "wente" }
    if slot == 1 { return "wentest" }
    if slot == 2 { return "wente" }
    if slot == 3 { return "wenten" }
    if slot == 4 { return "wenten" }
    return "wenten"
}

fn enm_seen_present(slot: Int) -> String {
    if slot == 0 { return "see" }
    if slot == 1 { return "seest" }
    if slot == 2 { return "seeth" }
    if slot == 3 { return "seen" }
    if slot == 4 { return "seen" }
    return "seen"
}

fn enm_seen_past(slot: Int) -> String {
    if slot == 0 { return "saugh" }
    if slot == 1 { return "sawest" }
    if slot == 2 { return "saugh" }
    if slot == 3 { return "sawen" }
    if slot == 4 { return "sawen" }
    return "sawen"
}

fn enm_seyen_present(slot: Int) -> String {
    if slot == 0 { return "seye" }
    if slot == 1 { return "seyst" }
    if slot == 2 { return "seith" }
    if slot == 3 { return "seyen" }
    if slot == 4 { return "seyen" }
    return "seyen"
}

fn enm_seyen_past(slot: Int) -> String {
    if slot == 0 { return "seide" }
    if slot == 1 { return "seidest" }
    if slot == 2 { return "seide" }
    if slot == 3 { return "seiden" }
    if slot == 4 { return "seiden" }
    return "seiden"
}

fn enm_comen_present(slot: Int) -> String {
    if slot == 0 { return "come" }
    if slot == 1 { return "comest" }
    if slot == 2 { return "cometh" }
    if slot == 3 { return "comen" }
    if slot == 4 { return "comen" }
    return "comen"
}

fn enm_comen_past(slot: Int) -> String {
    if slot == 0 { return "cam" }
    if slot == 1 { return "come" }
    if slot == 2 { return "cam" }
    if slot == 3 { return "comen" }
    if slot == 4 { return "comen" }
    return "comen"
}

fn enm_maken_present(slot: Int) -> String {
    if slot == 0 { return "make" }
    if slot == 1 { return "makest" }
    if slot == 2 { return "maketh" }
    if slot == 3 { return "maken" }
    if slot == 4 { return "maken" }
    return "maken"
}

fn enm_maken_past(slot: Int) -> String {
    if slot == 0 { return "made" }
    if slot == 1 { return "madest" }
    if slot == 2 { return "made" }
    if slot == 3 { return "maden" }
    if slot == 4 { return "maden" }
    return "maden"
}

// ── Canonical verb mapping ─────────────────────────────────────────────────────
//
// Maps English semantic labels to Middle English infinitives so the semantic
// layer can request forms without knowing the target-language lexeme.

fn enm_map_canonical(verb: String) -> String {
    if str_eq(verb, "be")   { return "been" }
    if str_eq(verb, "have") { return "haven" }
    if str_eq(verb, "go")   { return "goon" }
    if str_eq(verb, "see")  { return "seen" }
    if str_eq(verb, "say")  { return "seyen" }
    if str_eq(verb, "come") { return "comen" }
    if str_eq(verb, "make") { return "maken" }
    return verb
}

// ── Weak verb stem derivation ──────────────────────────────────────────────────
//
// For weak verbs the present stem is the infinitive minus any trailing -en or -e.
// Past tense suffix: most common is -ede (after unvoiced consonants often -te,
// after voiced -de).  This module uses -ede as the default productive past suffix.
//
//   Present:
//     slot 0: stem           (I love)
//     slot 1: stem + est     (thou lovest)
//     slot 2: stem + eth     (he loveth)
//     slot 3: stem + en      (we loven)
//     slot 4: stem + en      (ye loven)
//     slot 5: stem + en      (they loven)
//
//   Past:
//     slot 0: stem + ede     (I lovede)
//     slot 1: stem + edest   (thou lovedest)
//     slot 2: stem + ede     (he lovede)
//     slot 3..5: stem + eden (we loveden)

fn enm_weak_stem(verb: String) -> String {
    if enm_str_ends(verb, "en") { return enm_drop(verb, 2) }
    if enm_str_ends(verb, "e")  { return enm_drop(verb, 1) }
    return verb
}

fn enm_weak_present(stem: String, slot: Int) -> String {
    if slot == 0 { return stem + "e" }
    if slot == 1 { return stem + "est" }
    if slot == 2 { return stem + "eth" }
    if slot == 3 { return stem + "en" }
    if slot == 4 { return stem + "en" }
    return stem + "en"
}

fn enm_weak_past(stem: String, slot: Int) -> String {
    if slot == 0 { return stem + "ede" }
    if slot == 1 { return stem + "edest" }
    if slot == 2 { return stem + "ede" }
    if slot == 3 { return stem + "eden" }
    if slot == 4 { return stem + "eden" }
    return stem + "eden"
}

// ── enm_conjugate: main conjugation entry point ───────────────────────────────
//
// verb:   Middle English infinitive (e.g. "loven", "been") or English canonical
// tense:  "present" | "past"
// person: "first" | "second" | "third"
// number: "singular" | "plural"
//
// Returns the inflected form.  Unknown tenses fall back to the infinitive rather
// than crashing.

fn enm_conjugate(verb: String, tense: String, person: String, number: String) -> String {
    let v: String = enm_map_canonical(verb)
    let slot: Int = enm_slot(person, number)

    // ── Irregulars ────────────────────────────────────────────────────────────

    if str_eq(v, "been") {
        if str_eq(tense, "present") { return enm_been_present(slot) }
        if str_eq(tense, "past")    { return enm_been_past(slot) }
        return v
    }

    if str_eq(v, "haven") {
        if str_eq(tense, "present") { return enm_haven_present(slot) }
        if str_eq(tense, "past")    { return enm_haven_past(slot) }
        return v
    }

    if str_eq(v, "goon") {
        if str_eq(tense, "present") { return enm_goon_present(slot) }
        if str_eq(tense, "past")    { return enm_goon_past(slot) }
        return v
    }

    if str_eq(v, "seen") {
        if str_eq(tense, "present") { return enm_seen_present(slot) }
        if str_eq(tense, "past")    { return enm_seen_past(slot) }
        return v
    }

    if str_eq(v, "seyen") {
        if str_eq(tense, "present") { return enm_seyen_present(slot) }
        if str_eq(tense, "past")    { return enm_seyen_past(slot) }
        return v
    }

    if str_eq(v, "comen") {
        if str_eq(tense, "present") { return enm_comen_present(slot) }
        if str_eq(tense, "past")    { return enm_comen_past(slot) }
        return v
    }

    if str_eq(v, "maken") {
        if str_eq(tense, "present") { return enm_maken_present(slot) }
        if str_eq(tense, "past")    { return enm_maken_past(slot) }
        return v
    }

    // ── Regular weak verb ─────────────────────────────────────────────────────

    let stem: String = enm_weak_stem(v)
    if str_eq(tense, "present") { return enm_weak_present(stem, slot) }
    if str_eq(tense, "past")    { return enm_weak_past(stem, slot) }

    // Unknown tense: return infinitive unchanged
    return v
}

// ── Noun plural irregulars ─────────────────────────────────────────────────────
//
// Returns the suppletive plural form for nouns with non-productive plurals, or ""
// if the noun takes the regular -es plural.
//
// Covered: man, woman, child, ox, foot, tooth, goose, mouse, louse
// These mirror patterns still visible in Modern English, present in ME too.

fn enm_irregular_plural(noun: String) -> String {
    if str_eq(noun, "man")   { return "men" }
    if str_eq(noun, "woman") { return "wommen" }
    if str_eq(noun, "child") { return "children" }
    if str_eq(noun, "ox")    { return "oxen" }
    if str_eq(noun, "foot")  { return "feet" }
    if str_eq(noun, "tooth") { return "teeth" }
    if str_eq(noun, "goose") { return "gees" }
    if str_eq(noun, "mouse") { return "mees" }
    if str_eq(noun, "louse") { return "lees" }
    return ""
}

// ── Regular plural formation ───────────────────────────────────────────────────
//
// Default: append -es.  For nouns already ending in -e, append just -s.
// For nouns ending in -s, -x, -sh, -ch: the -es is still appropriate but
// in ME spelling the forms vary; we use the simple +es rule uniformly.

fn enm_make_plural(noun: String) -> String {
    // Check suppletive irregular first
    let irreg: String = enm_irregular_plural(noun)
    if !str_eq(irreg, "") { return irreg }

    // Noun ends in -e: just add -s to avoid double vowel
    if enm_str_ends(noun, "e") { return noun + "s" }

    // Default: +es
    return noun + "es"
}

// ── enm_decline: main declension entry point ──────────────────────────────────
//
// Middle English has largely lost case morphology.  This function handles the
// three practically relevant categories:
//   nominative  — base form (used also for accusative and dative)
//   genitive    — base form + es (possessive)
//   plural      — irregular or base + es
//
// noun:      base nominative form (e.g. "knyght", "man", "lond")
// gram_case: "nominative" | "accusative" | "dative" | "genitive" | "plural"
//            ("accusative" and "dative" return the nominative form)
// number:    "singular" | "plural"
//
// Returns the inflected form.

fn enm_decline(noun: String, gram_case: String, number: String) -> String {
    // Plural number overrides gram_case for the plural form
    if str_eq(number, "plural") {
        return enm_make_plural(noun)
    }

    // Singular
    if str_eq(gram_case, "genitive") {
        // Genitive singular: +es (even after -e: "the kinges court")
        return noun + "es"
    }

    // Nominative, accusative, dative — all the same in ME
    return noun
}

// ── Article selection ──────────────────────────────────────────────────────────
//
// Middle English uses "the" (definite) and "a" / "an" (indefinite).
// The indefinite article is "an" before a vowel-initial word, "a" otherwise.
// Vowel check is on the first character of the noun phrase word.

fn enm_is_vowel_initial(s: String) -> Bool {
    let c: String = enm_first_char(s)
    if str_eq(c, "a") { return true }
    if str_eq(c, "e") { return true }
    if str_eq(c, "i") { return true }
    if str_eq(c, "o") { return true }
    if str_eq(c, "u") { return true }
    // ME also treated initial h as effectively silent in some dialects;
    // we conservatively treat h-initial as consonant-initial.
    return false
}

fn enm_indef_article(noun_phrase: String) -> String {
    if enm_is_vowel_initial(noun_phrase) { return "an" }
    return "a"
}

// ── enm_noun_phrase: noun phrase builder ─────────────────────────────────────
//
// Constructs a full noun phrase with the appropriate article.
//
// noun:      base nominative singular form (e.g. "knyght", "man", "lond")
// gram_case: "nominative" | "accusative" | "dative" | "genitive" | "plural"
// number:    "singular" | "plural"
// definite:  "true" | "false"  (string comparison)
//
// Returns the complete noun phrase string (article + declined noun).

fn enm_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String {
    let form: String = enm_decline(noun, gram_case, number)

    if str_eq(definite, "true") {
        return "the " + form
    }

    // Indefinite article only makes sense for singular; plural takes no article
    if str_eq(number, "plural") {
        return form
    }

    let art: String = enm_indef_article(form)
    return art + " " + form
}
