// morphology-de.el - German morphology: articles, adjective endings, noun
// plurals, and verb conjugation.
//
// German is a fusional language with:
//   - 4 grammatical cases: nominative, accusative, dative, genitive
//   - 3 genders:           masculine (m), feminine (f), neuter (n)
//   - 2 numbers:           singular, plural
//   - Strong and weak verb classes
//
// Conventions used throughout:
//   gender:  "m" | "f" | "n"
//   case:    "nom" | "acc" | "dat" | "gen"
//   number:  "sg" | "pl"
//   person:  "1" | "2" | "3"
//   tense:   "present" | "past" | "future"
//   article_type: "def" | "indef" | "none"
//
// Depends on: language-profile (str_eq, str_len, str_slice, str_drop_last,
//             str_ends_with)

// ── Definite articles (der-words) ─────────────────────────────────────────────
//
//          Masc    Fem     Neut    Plural
//  Nom:    der     die     das     die
//  Acc:    den     die     das     die
//  Dat:    dem     der     dem     den
//  Gen:    des     der     des     der

import "morphology.el"
fn de_article_def(gender: String, gram_case: String, number: String) -> String {
    if str_eq(number, "pl") {
        if str_eq(gram_case, "nom") { return "die" }
        if str_eq(gram_case, "acc") { return "die" }
        if str_eq(gram_case, "dat") { return "den" }
        if str_eq(gram_case, "gen") { return "der" }
        return "die"
    }
    if str_eq(gender, "m") {
        if str_eq(gram_case, "nom") { return "der" }
        if str_eq(gram_case, "acc") { return "den" }
        if str_eq(gram_case, "dat") { return "dem" }
        if str_eq(gram_case, "gen") { return "des" }
        return "der"
    }
    if str_eq(gender, "f") {
        if str_eq(gram_case, "nom") { return "die" }
        if str_eq(gram_case, "acc") { return "die" }
        if str_eq(gram_case, "dat") { return "der" }
        if str_eq(gram_case, "gen") { return "der" }
        return "die"
    }
    // neuter
    if str_eq(gram_case, "nom") { return "das" }
    if str_eq(gram_case, "acc") { return "das" }
    if str_eq(gram_case, "dat") { return "dem" }
    if str_eq(gram_case, "gen") { return "des" }
    return "das"
}

// ── Indefinite articles (ein-words) ──────────────────────────────────────────
//
//          Masc    Fem     Neut    Plural
//  Nom:    ein     eine    ein     —
//  Acc:    einen   eine    ein     —
//  Dat:    einem   einer   einem   —
//  Gen:    eines   einer   eines   —

fn de_article_indef(gender: String, gram_case: String, number: String) -> String {
    if str_eq(number, "pl") {
        // Indefinite article has no plural form
        return ""
    }
    if str_eq(gender, "m") {
        if str_eq(gram_case, "nom") { return "ein" }
        if str_eq(gram_case, "acc") { return "einen" }
        if str_eq(gram_case, "dat") { return "einem" }
        if str_eq(gram_case, "gen") { return "eines" }
        return "ein"
    }
    if str_eq(gender, "f") {
        if str_eq(gram_case, "nom") { return "eine" }
        if str_eq(gram_case, "acc") { return "eine" }
        if str_eq(gram_case, "dat") { return "einer" }
        if str_eq(gram_case, "gen") { return "einer" }
        return "eine"
    }
    // neuter
    if str_eq(gram_case, "nom") { return "ein" }
    if str_eq(gram_case, "acc") { return "ein" }
    if str_eq(gram_case, "dat") { return "einem" }
    if str_eq(gram_case, "gen") { return "eines" }
    return "ein"
}

// de_article: unified article dispatch.
// definite: "def" | "indef" | "none"
fn de_article(gender: String, gram_case: String, number: String, definite: String) -> String {
    if str_eq(definite, "def")   { return de_article_def(gender, gram_case, number) }
    if str_eq(definite, "indef") { return de_article_indef(gender, gram_case, number) }
    return ""
}

// ── Adjective endings ─────────────────────────────────────────────────────────
//
// Weak endings (after a definite article or der-word):
//
//          Masc    Fem     Neut    Plural
//  Nom:    -e      -e      -e      -en
//  Acc:    -en     -e      -e      -en
//  Dat:    -en     -en     -en     -en
//  Gen:    -en     -en     -en     -en
//
// Mixed endings (after ein-words with no marking, i.e. indef article):
//
//          Masc    Fem     Neut    Plural
//  Nom:    -er     -e      -es     -en
//  Acc:    -en     -e      -es     -en
//  Dat:    -en     -en     -en     -en
//  Gen:    -en     -en     -en     -en
//
// Strong endings (no preceding article):
//
//          Masc    Fem     Neut    Plural
//  Nom:    -er     -e      -es     -e
//  Acc:    -en     -e      -es     -e
//  Dat:    -em     -er     -em     -en
//  Gen:    -en     -er     -en     -er
//
// article_type: "def" | "indef" | "none"

fn de_adj_ending(gender: String, gram_case: String, number: String, article_type: String) -> String {
    if str_eq(article_type, "def") {
        // Weak declension
        if str_eq(number, "pl") {
            return "en"
        }
        if str_eq(gender, "m") {
            if str_eq(gram_case, "nom") { return "e" }
            return "en"
        }
        if str_eq(gender, "f") {
            if str_eq(gram_case, "nom") { return "e" }
            if str_eq(gram_case, "acc") { return "e" }
            return "en"
        }
        // neuter
        if str_eq(gram_case, "nom") { return "e" }
        if str_eq(gram_case, "acc") { return "e" }
        return "en"
    }

    if str_eq(article_type, "indef") {
        // Mixed declension
        if str_eq(number, "pl") {
            return "en"
        }
        if str_eq(gender, "m") {
            if str_eq(gram_case, "nom") { return "er" }
            return "en"
        }
        if str_eq(gender, "f") {
            if str_eq(gram_case, "nom") { return "e" }
            if str_eq(gram_case, "acc") { return "e" }
            return "en"
        }
        // neuter
        if str_eq(gram_case, "nom") { return "es" }
        if str_eq(gram_case, "acc") { return "es" }
        return "en"
    }

    // Strong declension (no article)
    if str_eq(number, "pl") {
        if str_eq(gram_case, "nom") { return "e" }
        if str_eq(gram_case, "acc") { return "e" }
        if str_eq(gram_case, "dat") { return "en" }
        if str_eq(gram_case, "gen") { return "er" }
        return "e"
    }
    if str_eq(gender, "m") {
        if str_eq(gram_case, "nom") { return "er" }
        if str_eq(gram_case, "acc") { return "en" }
        if str_eq(gram_case, "dat") { return "em" }
        if str_eq(gram_case, "gen") { return "en" }
        return "er"
    }
    if str_eq(gender, "f") {
        if str_eq(gram_case, "nom") { return "e" }
        if str_eq(gram_case, "acc") { return "e" }
        if str_eq(gram_case, "dat") { return "er" }
        if str_eq(gram_case, "gen") { return "er" }
        return "e"
    }
    // neuter
    if str_eq(gram_case, "nom") { return "es" }
    if str_eq(gram_case, "acc") { return "es" }
    if str_eq(gram_case, "dat") { return "em" }
    if str_eq(gram_case, "gen") { return "en" }
    return "es"
}

// ── Noun plural formation ─────────────────────────────────────────────────────
//
// Major patterns, keyed on lemma.  Where a noun is known irregular, the full
// plural is returned.  Otherwise a productive heuristic by gender and ending
// is applied:
//
//   Masculine hard nouns   → +e       (der Tag  → Tage)
//   Feminine nouns in -e   → +n       (die Katze → Katzen)
//   Feminine nouns         → +en      (die Frau  → Frauen)
//   Neuter nouns in -chen/-lein → ∅   (das Mädchen → Mädchen)
//   Neuter nouns in -um    → -um +en  (das Zentrum → Zentren)
//   Loanwords in -a,-o,-i  → +s       (das Auto  → Autos)
//   Default                → +e

fn de_noun_plural(noun: String, gender: String) -> String {
    // ── Lexical irregulars ──────────────────────────────────────────────────
    if str_eq(noun, "Mann")        { return "Männer" }
    if str_eq(noun, "Kind")        { return "Kinder" }
    if str_eq(noun, "Haus")        { return "Häuser" }
    if str_eq(noun, "Buch")        { return "Bücher" }
    if str_eq(noun, "Mutter")      { return "Mütter" }
    if str_eq(noun, "Vater")       { return "Väter" }
    if str_eq(noun, "Bruder")      { return "Brüder" }
    if str_eq(noun, "Tochter")     { return "Töchter" }
    if str_eq(noun, "Nacht")       { return "Nächte" }
    if str_eq(noun, "Stadt")       { return "Städte" }
    if str_eq(noun, "Wort")        { return "Wörter" }
    if str_eq(noun, "Gott")        { return "Götter" }
    if str_eq(noun, "Wald")        { return "Wälder" }
    if str_eq(noun, "Band")        { return "Bände" }
    if str_eq(noun, "Hund")        { return "Hunde" }
    if str_eq(noun, "Baum")        { return "Bäume" }
    if str_eq(noun, "Raum")        { return "Räume" }
    if str_eq(noun, "Traum")       { return "Träume" }
    if str_eq(noun, "Zug")         { return "Züge" }
    if str_eq(noun, "Flug")        { return "Flüge" }
    if str_eq(noun, "Fuß")         { return "Füße" }
    if str_eq(noun, "Gruß")        { return "Grüße" }
    if str_eq(noun, "Geist")       { return "Geister" }
    if str_eq(noun, "Schwanz")     { return "Schwänze" }
    if str_eq(noun, "Stuhl")       { return "Stühle" }
    if str_eq(noun, "Stuhl")       { return "Stühle" }
    if str_eq(noun, "Sohn")        { return "Söhne" }
    if str_eq(noun, "Ton")         { return "Töne" }
    if str_eq(noun, "Fluss")       { return "Flüsse" }
    if str_eq(noun, "Frau")        { return "Frauen" }
    if str_eq(noun, "Straße")      { return "Straßen" }
    if str_eq(noun, "Schule")      { return "Schulen" }
    if str_eq(noun, "Blume")       { return "Blumen" }
    if str_eq(noun, "Katze")       { return "Katzen" }
    if str_eq(noun, "Sprache")     { return "Sprachen" }
    if str_eq(noun, "Kirche")      { return "Kirchen" }
    if str_eq(noun, "Tür")         { return "Türen" }
    if str_eq(noun, "Uhr")         { return "Uhren" }
    if str_eq(noun, "Zahl")        { return "Zahlen" }
    if str_eq(noun, "Wahl")        { return "Wahlen" }
    if str_eq(noun, "Bahn")        { return "Bahnen" }
    if str_eq(noun, "Zahn")        { return "Zähne" }
    if str_eq(noun, "Nase")        { return "Nasen" }
    if str_eq(noun, "Maus")        { return "Mäuse" }
    if str_eq(noun, "Mädchen")     { return "Mädchen" }
    if str_eq(noun, "Messer")      { return "Messer" }
    if str_eq(noun, "Fenster")     { return "Fenster" }
    if str_eq(noun, "Zimmer")      { return "Zimmer" }
    if str_eq(noun, "Wasser")      { return "Wasser" }
    if str_eq(noun, "Bett")        { return "Betten" }
    if str_eq(noun, "Auto")        { return "Autos" }
    if str_eq(noun, "Kino")        { return "Kinos" }
    if str_eq(noun, "Radio")       { return "Radios" }
    if str_eq(noun, "Foto")        { return "Fotos" }
    if str_eq(noun, "Cafe")        { return "Cafes" }
    if str_eq(noun, "Zentrum")     { return "Zentren" }
    if str_eq(noun, "Museum")      { return "Museen" }
    if str_eq(noun, "Gymnasium")   { return "Gymnasien" }
    if str_eq(noun, "Studium")     { return "Studien" }
    if str_eq(noun, "Datum")       { return "Daten" }

    // ── Productive heuristics ───────────────────────────────────────────────

    // Nouns ending in -chen or -lein: no change (diminutives)
    if str_ends_with(noun, "chen") { return noun }
    if str_ends_with(noun, "lein") { return noun }

    // Nouns ending in -um: replace with -en
    if str_ends_with(noun, "um") {
        return str_drop_last(noun, 2) + "en"
    }

    // Loanwords ending in vowel or -s: add -s
    if str_ends_with(noun, "a") { return noun + "s" }
    if str_ends_with(noun, "o") { return noun + "s" }
    if str_ends_with(noun, "i") { return noun + "s" }
    if str_ends_with(noun, "u") { return noun + "s" }
    if str_ends_with(noun, "y") { return noun + "s" }

    // Feminine nouns ending in -e: add -n
    if str_eq(gender, "f") {
        if str_ends_with(noun, "e") {
            return noun + "n"
        }
        // Feminine nouns ending in -in: add -nen
        if str_ends_with(noun, "in") {
            return noun + "nen"
        }
        // Most other feminines: add -en
        return noun + "en"
    }

    // Neuter and masculine: default to +e
    return noun + "e"
}

// ── Noun case endings ─────────────────────────────────────────────────────────
//
// In German, noun case inflection is mostly carried by the article and
// adjective.  The noun itself only changes in two regular situations:
//   - Genitive singular masculine/neuter: -(e)s
//   - Dative plural: -n (if not already ending in -n or -s)
//
// Irregular genitive forms (e.g. N-declension: Herr → Herrn) are
// handled per-lemma in de_case_ending.

fn de_case_ending(noun: String, gender: String, gram_case: String, number: String) -> String {
    // N-declension masculines (weak nouns): all non-nominative singular forms + all plural add -(e)n
    if str_eq(noun, "Herr") {
        if str_eq(number, "sg") {
            if str_eq(gram_case, "nom") { return "Herr" }
            return "Herrn"
        }
        return "Herren"
    }
    if str_eq(noun, "Mensch") {
        if str_eq(number, "sg") {
            if str_eq(gram_case, "nom") { return "Mensch" }
            return "Menschen"
        }
        return "Menschen"
    }
    if str_eq(noun, "Student") {
        if str_eq(number, "sg") {
            if str_eq(gram_case, "nom") { return "Student" }
            return "Studenten"
        }
        return "Studenten"
    }
    if str_eq(noun, "Kollege") {
        if str_eq(number, "sg") {
            if str_eq(gram_case, "nom") { return "Kollege" }
            return "Kollegen"
        }
        return "Kollegen"
    }
    if str_eq(noun, "Name") {
        if str_eq(number, "sg") {
            if str_eq(gram_case, "nom") { return "Name" }
            if str_eq(gram_case, "gen") { return "Namens" }
            return "Namen"
        }
        return "Namen"
    }

    // Regular masculine/neuter: genitive singular gets -(e)s
    if str_eq(number, "sg") {
        if str_eq(gram_case, "gen") {
            if str_eq(gender, "m") {
                if str_ends_with(noun, "s")  { return noun + "es" }
                if str_ends_with(noun, "x")  { return noun + "es" }
                if str_ends_with(noun, "z")  { return noun + "es" }
                if str_ends_with(noun, "sch") { return noun + "es" }
                return noun + "s"
            }
            if str_eq(gender, "n") {
                if str_ends_with(noun, "s")  { return noun + "es" }
                if str_ends_with(noun, "x")  { return noun + "es" }
                if str_ends_with(noun, "z")  { return noun + "es" }
                return noun + "s"
            }
        }
        // All other singular cases: noun unchanged
        return noun
    }

    // Plural dative: add -n unless already ending in -n or -s
    if str_eq(gram_case, "dat") {
        let pl: String = de_noun_plural(noun, gender)
        if str_ends_with(pl, "n") { return pl }
        if str_ends_with(pl, "s") { return pl }
        return pl + "n"
    }

    // All other plural cases: return the standard plural form
    return de_noun_plural(noun, gender)
}

// ── Weak verb conjugation ─────────────────────────────────────────────────────
//
// Model: machen (mach-)
//
// Present:
//   1sg ich   mache       2sg du    machst      3sg er/sie/es macht
//   1pl wir   machen      2pl ihr   macht       3pl sie       machen
//
// Past (Präteritum):
//   1sg ich   machte      2sg du    machtest    3sg er/sie/es machte
//   1pl wir   machten     2pl ihr   machtet     3pl sie       machten

fn de_conjugate_weak(stem: String, tense: String, person: String, number: String) -> String {
    if str_eq(tense, "present") {
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return stem + "e" }
            if str_eq(person, "2") {
                // Stems ending in -t or -d insert -e- before -st
                if str_ends_with(stem, "t") { return stem + "est" }
                if str_ends_with(stem, "d") { return stem + "est" }
                return stem + "st"
            }
            // 3sg
            if str_ends_with(stem, "t") { return stem + "et" }
            if str_ends_with(stem, "d") { return stem + "et" }
            return stem + "t"
        }
        // plural
        if str_eq(person, "1") { return stem + "en" }
        if str_eq(person, "2") {
            if str_ends_with(stem, "t") { return stem + "et" }
            if str_ends_with(stem, "d") { return stem + "et" }
            return stem + "t"
        }
        // 3pl
        return stem + "en"
    }

    if str_eq(tense, "past") {
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return stem + "te" }
            if str_eq(person, "2") { return stem + "test" }
            return stem + "te"
        }
        if str_eq(person, "1") { return stem + "ten" }
        if str_eq(person, "2") { return stem + "tet" }
        return stem + "ten"
    }

    // Future: werden + infinitive — caller must prepend the auxiliary
    return stem + "en"
}

// ── Strong / irregular verb present-tense forms ───────────────────────────────
//
// Returns the correct surface form if the verb is irregular, or "" if unknown.
// Only present-tense irregulars are encoded here because past tense for strong
// verbs is stored as a separate stem (Ablaut) — see de_conjugate.

fn de_irregular_present(verb: String, person: String, number: String) -> String {
    // sein — fully irregular
    if str_eq(verb, "sein") {
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return "bin" }
            if str_eq(person, "2") { return "bist" }
            return "ist"
        }
        if str_eq(person, "1") { return "sind" }
        if str_eq(person, "2") { return "seid" }
        return "sind"
    }

    // haben
    if str_eq(verb, "haben") {
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return "habe" }
            if str_eq(person, "2") { return "hast" }
            return "hat"
        }
        if str_eq(person, "1") { return "haben" }
        if str_eq(person, "2") { return "habt" }
        return "haben"
    }

    // werden
    if str_eq(verb, "werden") {
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return "werde" }
            if str_eq(person, "2") { return "wirst" }
            return "wird"
        }
        if str_eq(person, "1") { return "werden" }
        if str_eq(person, "2") { return "werdet" }
        return "werden"
    }

    // gehen
    if str_eq(verb, "gehen") {
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return "gehe" }
            if str_eq(person, "2") { return "gehst" }
            return "geht"
        }
        if str_eq(person, "1") { return "gehen" }
        if str_eq(person, "2") { return "geht" }
        return "gehen"
    }

    // kommen
    if str_eq(verb, "kommen") {
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return "komme" }
            if str_eq(person, "2") { return "kommst" }
            return "kommt"
        }
        if str_eq(person, "1") { return "kommen" }
        if str_eq(person, "2") { return "kommt" }
        return "kommen"
    }

    // sehen — vowel change e→ie in 2sg/3sg
    if str_eq(verb, "sehen") {
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return "sehe" }
            if str_eq(person, "2") { return "siehst" }
            return "sieht"
        }
        if str_eq(person, "1") { return "sehen" }
        if str_eq(person, "2") { return "seht" }
        return "sehen"
    }

    // essen — vowel change e→i in 2sg/3sg
    if str_eq(verb, "essen") {
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return "esse" }
            if str_eq(person, "2") { return "isst" }
            return "isst"
        }
        if str_eq(person, "1") { return "essen" }
        if str_eq(person, "2") { return "esst" }
        return "essen"
    }

    // geben — vowel change e→i in 2sg/3sg
    if str_eq(verb, "geben") {
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return "gebe" }
            if str_eq(person, "2") { return "gibst" }
            return "gibt"
        }
        if str_eq(person, "1") { return "geben" }
        if str_eq(person, "2") { return "gebt" }
        return "geben"
    }

    // nehmen — vowel change e→i + consonant change in 2sg/3sg
    if str_eq(verb, "nehmen") {
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return "nehme" }
            if str_eq(person, "2") { return "nimmst" }
            return "nimmt"
        }
        if str_eq(person, "1") { return "nehmen" }
        if str_eq(person, "2") { return "nehmt" }
        return "nehmen"
    }

    // fahren — vowel change a→ä in 2sg/3sg
    if str_eq(verb, "fahren") {
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return "fahre" }
            if str_eq(person, "2") { return "fährst" }
            return "fährt"
        }
        if str_eq(person, "1") { return "fahren" }
        if str_eq(person, "2") { return "fahrt" }
        return "fahren"
    }

    // laufen — vowel change au→äu in 2sg/3sg
    if str_eq(verb, "laufen") {
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return "laufe" }
            if str_eq(person, "2") { return "läufst" }
            return "läuft"
        }
        if str_eq(person, "1") { return "laufen" }
        if str_eq(person, "2") { return "lauft" }
        return "laufen"
    }

    // wissen — irregular throughout
    if str_eq(verb, "wissen") {
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return "weiß" }
            if str_eq(person, "2") { return "weißt" }
            return "weiß"
        }
        if str_eq(person, "1") { return "wissen" }
        if str_eq(person, "2") { return "wisst" }
        return "wissen"
    }

    // können — modal
    if str_eq(verb, "können") {
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return "kann" }
            if str_eq(person, "2") { return "kannst" }
            return "kann"
        }
        if str_eq(person, "1") { return "können" }
        if str_eq(person, "2") { return "könnt" }
        return "können"
    }

    // müssen — modal
    if str_eq(verb, "müssen") {
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return "muss" }
            if str_eq(person, "2") { return "musst" }
            return "muss"
        }
        if str_eq(person, "1") { return "müssen" }
        if str_eq(person, "2") { return "müsst" }
        return "müssen"
    }

    // wollen — modal
    if str_eq(verb, "wollen") {
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return "will" }
            if str_eq(person, "2") { return "willst" }
            return "will"
        }
        if str_eq(person, "1") { return "wollen" }
        if str_eq(person, "2") { return "wollt" }
        return "wollen"
    }

    // Unknown: signal caller to fall through to weak conjugation
    return ""
}

// ── Strong verb past-tense (Präteritum) Ablaut stems ─────────────────────────
//
// Returns the past stem for strong verbs (Ablaut form), or "" if unknown/weak.
// The past-tense endings for strong verbs differ from weak:
//   1sg/3sg: bare stem (no ending)
//   2sg:     stem + -st
//   1pl/3pl: stem + -en
//   2pl:     stem + -t

fn de_strong_past_stem(verb: String) -> String {
    if str_eq(verb, "gehen")   { return "ging" }
    if str_eq(verb, "kommen")  { return "kam" }
    if str_eq(verb, "sehen")   { return "sah" }
    if str_eq(verb, "geben")   { return "gab" }
    if str_eq(verb, "nehmen")  { return "nahm" }
    if str_eq(verb, "fahren")  { return "fuhr" }
    if str_eq(verb, "laufen")  { return "lief" }
    if str_eq(verb, "schreiben") { return "schrieb" }
    if str_eq(verb, "bleiben") { return "blieb" }
    if str_eq(verb, "steigen") { return "stieg" }
    if str_eq(verb, "lesen")   { return "las" }
    if str_eq(verb, "sprechen") { return "sprach" }
    if str_eq(verb, "treffen") { return "traf" }
    if str_eq(verb, "essen")   { return "aß" }
    if str_eq(verb, "trinken") { return "trank" }
    if str_eq(verb, "finden")  { return "fand" }
    if str_eq(verb, "denken")  { return "dachte" }
    if str_eq(verb, "bringen") { return "brachte" }
    if str_eq(verb, "stehen")  { return "stand" }
    if str_eq(verb, "liegen")  { return "lag" }
    if str_eq(verb, "sitzen")  { return "saß" }
    if str_eq(verb, "fallen")  { return "fiel" }
    if str_eq(verb, "halten")  { return "hielt" }
    if str_eq(verb, "rufen")   { return "rief" }
    if str_eq(verb, "tragen")  { return "trug" }
    if str_eq(verb, "schlagen") { return "schlug" }
    if str_eq(verb, "ziehen")  { return "zog" }
    if str_eq(verb, "wachsen") { return "wuchs" }
    if str_eq(verb, "helfen")  { return "half" }
    if str_eq(verb, "werfen")  { return "warf" }
    return ""
}

// ── Normalization helpers ─────────────────────────────────────────────────────
//
// The realizer sends long-form labels ("singular", "first").
// German morphology uses short forms ("sg", "1").  Normalize on entry.

fn de_norm_number(number: String) -> String {
    if str_eq(number, "singular") { return "sg" }
    if str_eq(number, "plural")   { return "pl" }
    return number
}

fn de_norm_person(person: String) -> String {
    if str_eq(person, "first")  { return "1" }
    if str_eq(person, "second") { return "2" }
    if str_eq(person, "third")  { return "3" }
    return person
}

// ── Unified German verb conjugation ──────────────────────────────────────────
//
// tense:  "present" | "past" | "future"
// person: "1" | "2" | "3"  (also accepts "first" | "second" | "third")
// number: "sg" | "pl"      (also accepts "singular" | "plural")

fn de_conjugate(verb: String, tense: String, person: String, number: String) -> String {
    let number = de_norm_number(number)
    let person = de_norm_person(person)
    // Future tense: werden (conjugated) + infinitive
    if str_eq(tense, "future") {
        let aux: String = de_irregular_present("werden", person, number)
        return aux + " " + verb
    }

    // sein — past is also fully irregular
    if str_eq(verb, "sein") {
        if str_eq(tense, "present") {
            return de_irregular_present("sein", person, number)
        }
        // Past (war)
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return "war" }
            if str_eq(person, "2") { return "warst" }
            return "war"
        }
        if str_eq(person, "1") { return "waren" }
        if str_eq(person, "2") { return "wart" }
        return "waren"
    }

    // haben — past: hatte
    if str_eq(verb, "haben") {
        if str_eq(tense, "present") {
            return de_irregular_present("haben", person, number)
        }
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return "hatte" }
            if str_eq(person, "2") { return "hattest" }
            return "hatte"
        }
        if str_eq(person, "1") { return "hatten" }
        if str_eq(person, "2") { return "hattet" }
        return "hatten"
    }

    // wissen — past: wusste (mixed/irregular)
    if str_eq(verb, "wissen") {
        if str_eq(tense, "present") {
            return de_irregular_present("wissen", person, number)
        }
        if str_eq(number, "sg") {
            if str_eq(person, "1") { return "wusste" }
            if str_eq(person, "2") { return "wusstest" }
            return "wusste"
        }
        if str_eq(person, "1") { return "wussten" }
        if str_eq(person, "2") { return "wusstet" }
        return "wussten"
    }

    // Modals: können, müssen, wollen — past uses weak -te suffix on preterite stem
    if str_eq(verb, "können") {
        if str_eq(tense, "present") {
            return de_irregular_present("können", person, number)
        }
        return de_conjugate_weak("konnt", "past", person, number)
    }
    if str_eq(verb, "müssen") {
        if str_eq(tense, "present") {
            return de_irregular_present("müssen", person, number)
        }
        return de_conjugate_weak("musst", "past", person, number)
    }
    if str_eq(verb, "wollen") {
        if str_eq(tense, "present") {
            return de_irregular_present("wollen", person, number)
        }
        return de_conjugate_weak("wollt", "past", person, number)
    }

    // Present: try irregular table first
    if str_eq(tense, "present") {
        let irr: String = de_irregular_present(verb, person, number)
        if !str_eq(irr, "") {
            return irr
        }
        // Fall through to weak conjugation using infinitive stem (drop -en)
        let stem: String = str_drop_last(verb, 2)
        return de_conjugate_weak(stem, "present", person, number)
    }

    // Past: try strong Ablaut first
    if str_eq(tense, "past") {
        let ps: String = de_strong_past_stem(verb)
        if !str_eq(ps, "") {
            // Strong past endings: 1sg/3sg bare, 2sg+st, 1pl/3pl+en, 2pl+t
            if str_eq(number, "sg") {
                if str_eq(person, "1") { return ps }
                if str_eq(person, "2") { return ps + "st" }
                return ps
            }
            if str_eq(person, "1") { return ps + "en" }
            if str_eq(person, "2") { return ps + "t" }
            return ps + "en"
        }
        // Weak past
        let stem: String = str_drop_last(verb, 2)
        return de_conjugate_weak(stem, "past", person, number)
    }

    // Fallback: return infinitive
    return verb
}
