// morphology-ja.el - Japanese morphology: verb conjugation and noun particles.
//
// Japanese is SOV, agglutinative, pro-drop.  Morphology is suffix-chain based.
//
// Key facts:
//   - Nouns do not inflect; grammatical relations are marked by postpositional
//     particles attached after the noun.
//   - Verbs inflect for tense, polarity, and politeness.
//   - Two main verb groups: Ichidan (vowel-stem, Group 2) and Godan (consonant-
//     stem, Group 1), plus a small set of irregular verbs.
//   - Politeness levels: plain (dictionary/casual) and polite (masu-form).
//   - Questions are formed by appending the sentence-final particle か (ka).
//
// Depends on: (no dependencies - standalone morphology module)

// ── Verb group classification ─────────────────────────────────────────────────
//
// Returns "ichidan" | "godan" | "irregular"
//
// Irregular verbs are checked first.  Ichidan verbs end in -る and have a
// vowel immediately before the る.  Everything else is Godan.
//
// Note: this is a heuristic classifier for romanized input.  For production use
// with native kana/kanji forms, the dictionary form (辞書形) must be consulted.

fn ja_verb_group(dict_form: String) -> String {
    // Irregular verbs (exact match on dictionary form)
    if str_eq(dict_form, "する")  { return "irregular" }
    if str_eq(dict_form, "くる")  { return "irregular" }
    if str_eq(dict_form, "くる")  { return "irregular" }
    if str_eq(dict_form, "いる")  { return "irregular" }
    if str_eq(dict_form, "ある")  { return "irregular" }
    if str_eq(dict_form, "だ")    { return "irregular" }
    // Romanized irregulars
    if str_eq(dict_form, "suru")  { return "irregular" }
    if str_eq(dict_form, "kuru")  { return "irregular" }
    if str_eq(dict_form, "iru")   { return "irregular" }
    if str_eq(dict_form, "aru")   { return "irregular" }
    if str_eq(dict_form, "da")    { return "irregular" }

    // Ichidan: ends in -る (-ru) and has a vowel before it.
    // We test using native kana ending and the romanized -eru / -iru pattern.
    if str_ends_with(dict_form, "る") {
        // Any kana-form ending in る that is not in the irregular list is
        // heuristically classified as Ichidan when the preceding mora ends in
        // a vowel sound.  For the romanized path we check -eru and -iru endings.
        return "ichidan"
    }
    if str_ends_with(dict_form, "eru") { return "ichidan" }
    if str_ends_with(dict_form, "iru") { return "ichidan" }

    return "godan"
}

// ── Ichidan stem extraction ───────────────────────────────────────────────────
//
// Strip the final -る (-ru) from an Ichidan dictionary form.
// 食べる → 食べ   taberu → tabe

fn ja_ichidan_stem(dict_form: String) -> String {
    if str_ends_with(dict_form, "る") {
        let n: Int = str_len(dict_form)
        // str_slice operates on byte offsets; る is 3 UTF-8 bytes.
        // We trust the runtime to handle Unicode correctly via str_drop_last.
        return str_drop_last(dict_form, 1)
    }
    if str_ends_with(dict_form, "ru") {
        let n: Int = str_len(dict_form)
        return str_slice(dict_form, 0, n - 2)
    }
    return dict_form
}

// ── Godan stem changes ────────────────────────────────────────────────────────
//
// Godan verbs mutate their final kana to a different row before attaching a
// suffix.  The "row" parameter selects which stem form is needed:
//
//   "i"   - the i-row (連用形 ren'yōkei): for polite forms, te-form base
//   "a"   - the a-row (未然形 mizenkei):  for negative
//   "te"  - te/ta-form (special sound changes apply)
//
// Final kana → i-row: く→き  ぐ→ぎ  す→し  つ→ち  ぬ→に  ぶ→び  む→み  る→り  う→い
// Final kana → a-row: く→か  ぐ→が  す→さ  つ→た  ぬ→な  ぶ→ば  む→ま  る→ら  う→わ
// Te/ta-form: く→い  ぐ→い  す→し  つ→っ  ぬ→ん  ぶ→ん  む→ん  る→っ  う→っ

fn ja_godan_stem_change(dict_form: String, row: String) -> String {
    let n: Int = str_len(dict_form)
    if n == 0 { return dict_form }

    // i-row (polite stem / ren'yōkei)
    if str_eq(row, "i") {
        if str_ends_with(dict_form, "く")  { return str_drop_last(dict_form, 1) + "き" }
        if str_ends_with(dict_form, "ぐ")  { return str_drop_last(dict_form, 1) + "ぎ" }
        if str_ends_with(dict_form, "す")  { return str_drop_last(dict_form, 1) + "し" }
        if str_ends_with(dict_form, "つ")  { return str_drop_last(dict_form, 1) + "ち" }
        if str_ends_with(dict_form, "ぬ")  { return str_drop_last(dict_form, 1) + "に" }
        if str_ends_with(dict_form, "ぶ")  { return str_drop_last(dict_form, 1) + "び" }
        if str_ends_with(dict_form, "む")  { return str_drop_last(dict_form, 1) + "み" }
        if str_ends_with(dict_form, "る")  { return str_drop_last(dict_form, 1) + "り" }
        if str_ends_with(dict_form, "う")  { return str_drop_last(dict_form, 1) + "い" }
        // Romanized fallbacks
        if str_ends_with(dict_form, "ku")  { return str_drop_last(dict_form, 2) + "ki" }
        if str_ends_with(dict_form, "gu")  { return str_drop_last(dict_form, 2) + "gi" }
        if str_ends_with(dict_form, "su")  { return str_drop_last(dict_form, 2) + "shi" }
        if str_ends_with(dict_form, "tsu") { return str_drop_last(dict_form, 3) + "chi" }
        if str_ends_with(dict_form, "nu")  { return str_drop_last(dict_form, 2) + "ni" }
        if str_ends_with(dict_form, "bu")  { return str_drop_last(dict_form, 2) + "bi" }
        if str_ends_with(dict_form, "mu")  { return str_drop_last(dict_form, 2) + "mi" }
        if str_ends_with(dict_form, "ru")  { return str_drop_last(dict_form, 2) + "ri" }
        if str_ends_with(dict_form, "u")   { return str_drop_last(dict_form, 1) + "i" }
        return dict_form
    }

    // a-row (negative stem / mizenkei)
    if str_eq(row, "a") {
        if str_ends_with(dict_form, "く")  { return str_drop_last(dict_form, 1) + "か" }
        if str_ends_with(dict_form, "ぐ")  { return str_drop_last(dict_form, 1) + "が" }
        if str_ends_with(dict_form, "す")  { return str_drop_last(dict_form, 1) + "さ" }
        if str_ends_with(dict_form, "つ")  { return str_drop_last(dict_form, 1) + "た" }
        if str_ends_with(dict_form, "ぬ")  { return str_drop_last(dict_form, 1) + "な" }
        if str_ends_with(dict_form, "ぶ")  { return str_drop_last(dict_form, 1) + "ば" }
        if str_ends_with(dict_form, "む")  { return str_drop_last(dict_form, 1) + "ま" }
        if str_ends_with(dict_form, "る")  { return str_drop_last(dict_form, 1) + "ら" }
        if str_ends_with(dict_form, "う")  { return str_drop_last(dict_form, 1) + "わ" }
        // Romanized fallbacks
        if str_ends_with(dict_form, "ku")  { return str_drop_last(dict_form, 2) + "ka" }
        if str_ends_with(dict_form, "gu")  { return str_drop_last(dict_form, 2) + "ga" }
        if str_ends_with(dict_form, "su")  { return str_drop_last(dict_form, 2) + "sa" }
        if str_ends_with(dict_form, "tsu") { return str_drop_last(dict_form, 3) + "ta" }
        if str_ends_with(dict_form, "nu")  { return str_drop_last(dict_form, 2) + "na" }
        if str_ends_with(dict_form, "bu")  { return str_drop_last(dict_form, 2) + "ba" }
        if str_ends_with(dict_form, "mu")  { return str_drop_last(dict_form, 2) + "ma" }
        if str_ends_with(dict_form, "ru")  { return str_drop_last(dict_form, 2) + "ra" }
        if str_ends_with(dict_form, "u")   { return str_drop_last(dict_form, 1) + "wa" }
        return dict_form
    }

    // te/ta-row (te-form and plain past; special euphonic changes)
    // Sound changes: く→い, ぐ→い (voiced), す→し, つ/る/う→っ, ぬ/ぶ/む→ん
    if str_eq(row, "te") {
        if str_ends_with(dict_form, "く")  { return str_drop_last(dict_form, 1) + "い" }
        if str_ends_with(dict_form, "ぐ")  { return str_drop_last(dict_form, 1) + "い" }
        if str_ends_with(dict_form, "す")  { return str_drop_last(dict_form, 1) + "し" }
        if str_ends_with(dict_form, "つ")  { return str_drop_last(dict_form, 1) + "っ" }
        if str_ends_with(dict_form, "ぬ")  { return str_drop_last(dict_form, 1) + "ん" }
        if str_ends_with(dict_form, "ぶ")  { return str_drop_last(dict_form, 1) + "ん" }
        if str_ends_with(dict_form, "む")  { return str_drop_last(dict_form, 1) + "ん" }
        if str_ends_with(dict_form, "る")  { return str_drop_last(dict_form, 1) + "っ" }
        if str_ends_with(dict_form, "う")  { return str_drop_last(dict_form, 1) + "っ" }
        // Romanized fallbacks
        if str_ends_with(dict_form, "ku")  { return str_drop_last(dict_form, 2) + "i" }
        if str_ends_with(dict_form, "gu")  { return str_drop_last(dict_form, 2) + "i" }
        if str_ends_with(dict_form, "su")  { return str_drop_last(dict_form, 2) + "shi" }
        if str_ends_with(dict_form, "tsu") { return str_drop_last(dict_form, 3) + "tt" }
        if str_ends_with(dict_form, "nu")  { return str_drop_last(dict_form, 2) + "n" }
        if str_ends_with(dict_form, "bu")  { return str_drop_last(dict_form, 2) + "n" }
        if str_ends_with(dict_form, "mu")  { return str_drop_last(dict_form, 2) + "n" }
        if str_ends_with(dict_form, "ru")  { return str_drop_last(dict_form, 2) + "tt" }
        if str_ends_with(dict_form, "u")   { return str_drop_last(dict_form, 1) + "tt" }
        return dict_form
    }

    return dict_form
}

// ── Verb conjugation ──────────────────────────────────────────────────────────
//
// ja_conjugate(dict_form, form) -> String
//
// form values:
//   "present"     - plain non-past (dictionary form)
//   "past"        - plain past
//   "negative"    - plain negative
//   "volitional"  - plain volitional (let's …)
//   "polite"      - polite non-past (masu-form)
//   "polite-past" - polite past (mashita-form)
//   "polite-neg"  - polite negative (masen-form)
//   "te"          - te-form (connective / gerund)

fn ja_conjugate(dict_form: String, form: String) -> String {
    let group: String = ja_verb_group(dict_form)

    // ── Irregular verbs ───────────────────────────────────────────────────────
    if str_eq(group, "irregular") {
        // する / suru (to do)
        if str_eq(dict_form, "する") {
            if str_eq(form, "present")     { return "する" }
            if str_eq(form, "past")        { return "した" }
            if str_eq(form, "negative")    { return "しない" }
            if str_eq(form, "volitional")  { return "しよう" }
            if str_eq(form, "polite")      { return "します" }
            if str_eq(form, "polite-past") { return "しました" }
            if str_eq(form, "polite-neg")  { return "しません" }
            if str_eq(form, "te")          { return "して" }
            return dict_form
        }
        if str_eq(dict_form, "suru") {
            if str_eq(form, "present")     { return "suru" }
            if str_eq(form, "past")        { return "shita" }
            if str_eq(form, "negative")    { return "shinai" }
            if str_eq(form, "volitional")  { return "shiyou" }
            if str_eq(form, "polite")      { return "shimasu" }
            if str_eq(form, "polite-past") { return "shimashita" }
            if str_eq(form, "polite-neg")  { return "shimasen" }
            if str_eq(form, "te")          { return "shite" }
            return dict_form
        }

        // くる / kuru (to come)
        if str_eq(dict_form, "くる") {
            if str_eq(form, "present")     { return "くる" }
            if str_eq(form, "past")        { return "きた" }
            if str_eq(form, "negative")    { return "こない" }
            if str_eq(form, "volitional")  { return "こよう" }
            if str_eq(form, "polite")      { return "きます" }
            if str_eq(form, "polite-past") { return "きました" }
            if str_eq(form, "polite-neg")  { return "きません" }
            if str_eq(form, "te")          { return "きて" }
            return dict_form
        }
        if str_eq(dict_form, "kuru") {
            if str_eq(form, "present")     { return "kuru" }
            if str_eq(form, "past")        { return "kita" }
            if str_eq(form, "negative")    { return "konai" }
            if str_eq(form, "volitional")  { return "koyou" }
            if str_eq(form, "polite")      { return "kimasu" }
            if str_eq(form, "polite-past") { return "kimashita" }
            if str_eq(form, "polite-neg")  { return "kimasen" }
            if str_eq(form, "te")          { return "kite" }
            return dict_form
        }

        // いる / iru (to be / exist, animate)
        if str_eq(dict_form, "いる") {
            if str_eq(form, "present")     { return "いる" }
            if str_eq(form, "past")        { return "いた" }
            if str_eq(form, "negative")    { return "いない" }
            if str_eq(form, "volitional")  { return "いよう" }
            if str_eq(form, "polite")      { return "います" }
            if str_eq(form, "polite-past") { return "いました" }
            if str_eq(form, "polite-neg")  { return "いません" }
            if str_eq(form, "te")          { return "いて" }
            return dict_form
        }
        if str_eq(dict_form, "iru") {
            if str_eq(form, "present")     { return "iru" }
            if str_eq(form, "past")        { return "ita" }
            if str_eq(form, "negative")    { return "inai" }
            if str_eq(form, "volitional")  { return "iyou" }
            if str_eq(form, "polite")      { return "imasu" }
            if str_eq(form, "polite-past") { return "imashita" }
            if str_eq(form, "polite-neg")  { return "imasen" }
            if str_eq(form, "te")          { return "ite" }
            return dict_form
        }

        // ある / aru (to be / exist, inanimate)
        if str_eq(dict_form, "ある") {
            if str_eq(form, "present")     { return "ある" }
            if str_eq(form, "past")        { return "あった" }
            if str_eq(form, "negative")    { return "ない" }
            if str_eq(form, "volitional")  { return "あろう" }
            if str_eq(form, "polite")      { return "あります" }
            if str_eq(form, "polite-past") { return "ありました" }
            if str_eq(form, "polite-neg")  { return "ありません" }
            if str_eq(form, "te")          { return "あって" }
            return dict_form
        }
        if str_eq(dict_form, "aru") {
            if str_eq(form, "present")     { return "aru" }
            if str_eq(form, "past")        { return "atta" }
            if str_eq(form, "negative")    { return "nai" }
            if str_eq(form, "volitional")  { return "arou" }
            if str_eq(form, "polite")      { return "arimasu" }
            if str_eq(form, "polite-past") { return "arimashita" }
            if str_eq(form, "polite-neg")  { return "arimasen" }
            if str_eq(form, "te")          { return "atte" }
            return dict_form
        }

        // だ / da (copula)
        if str_eq(dict_form, "だ") {
            if str_eq(form, "present")     { return "だ" }
            if str_eq(form, "past")        { return "だった" }
            if str_eq(form, "negative")    { return "ではない" }
            if str_eq(form, "volitional")  { return "だろう" }
            if str_eq(form, "polite")      { return "です" }
            if str_eq(form, "polite-past") { return "でした" }
            if str_eq(form, "polite-neg")  { return "ではありません" }
            if str_eq(form, "te")          { return "で" }
            return dict_form
        }
        if str_eq(dict_form, "da") {
            if str_eq(form, "present")     { return "da" }
            if str_eq(form, "past")        { return "datta" }
            if str_eq(form, "negative")    { return "dewanai" }
            if str_eq(form, "volitional")  { return "darou" }
            if str_eq(form, "polite")      { return "desu" }
            if str_eq(form, "polite-past") { return "deshita" }
            if str_eq(form, "polite-neg")  { return "dewaarimarsen" }
            if str_eq(form, "te")          { return "de" }
            return dict_form
        }

        // Unknown irregular — fall through to base form
        return dict_form
    }

    // ── Ichidan verbs ─────────────────────────────────────────────────────────
    if str_eq(group, "ichidan") {
        let stem: String = ja_ichidan_stem(dict_form)

        if str_eq(form, "present")     { return dict_form }
        if str_eq(form, "past")        { return stem + "た" }
        if str_eq(form, "negative")    { return stem + "ない" }
        if str_eq(form, "volitional")  { return stem + "よう" }
        if str_eq(form, "polite")      { return stem + "ます" }
        if str_eq(form, "polite-past") { return stem + "ました" }
        if str_eq(form, "polite-neg")  { return stem + "ません" }
        if str_eq(form, "te")          { return stem + "て" }
        return dict_form
    }

    // ── Godan verbs ───────────────────────────────────────────────────────────
    // Godan plain present: dictionary form unchanged
    if str_eq(form, "present") { return dict_form }

    // Godan polite forms use the i-row stem + masu endings
    if str_eq(form, "polite") {
        let istem: String = ja_godan_stem_change(dict_form, "i")
        return istem + "ます"
    }
    if str_eq(form, "polite-past") {
        let istem: String = ja_godan_stem_change(dict_form, "i")
        return istem + "ました"
    }
    if str_eq(form, "polite-neg") {
        let istem: String = ja_godan_stem_change(dict_form, "i")
        return istem + "ません"
    }

    // Godan plain negative uses the a-row stem + nai
    if str_eq(form, "negative") {
        let astem: String = ja_godan_stem_change(dict_form, "a")
        return astem + "ない"
    }

    // Godan volitional: i-row + ou (う ending → おう, others → ろう via i-stem)
    if str_eq(form, "volitional") {
        // う-verbs: drop final う and add おう
        if str_ends_with(dict_form, "う") {
            return str_drop_last(dict_form, 1) + "おう"
        }
        let istem: String = ja_godan_stem_change(dict_form, "i")
        return istem + "ろう"
    }

    // Godan te-form: euphonic te-row stem + て (voiced ぐ ending → いで)
    if str_eq(form, "te") {
        let tstem: String = ja_godan_stem_change(dict_form, "te")
        // Voiced consonants (ぐ) use で instead of て
        if str_ends_with(dict_form, "ぐ") { return tstem + "いで" }
        if str_ends_with(dict_form, "gu") { return tstem + "ide" }
        // Nasal assimilation: ぬ/ぶ/む → んで
        if str_ends_with(dict_form, "ぬ") { return tstem + "んで" }
        if str_ends_with(dict_form, "ぶ") { return tstem + "んで" }
        if str_ends_with(dict_form, "む") { return tstem + "んで" }
        if str_ends_with(dict_form, "nu") { return tstem + "nde" }
        if str_ends_with(dict_form, "bu") { return tstem + "nde" }
        if str_ends_with(dict_form, "mu") { return tstem + "nde" }
        // す → して
        if str_ends_with(dict_form, "す") { return tstem + "して" }
        if str_ends_with(dict_form, "su") { return tstem + "shite" }
        // く → いて  (tstem already has い)
        if str_ends_with(dict_form, "く") { return tstem + "て" }
        if str_ends_with(dict_form, "ku") { return tstem + "te" }
        // つ/る/う → って
        return tstem + "て"
    }

    // Godan plain past: same stem changes as te-form, then た/だ
    if str_eq(form, "past") {
        let tstem: String = ja_godan_stem_change(dict_form, "te")
        if str_ends_with(dict_form, "ぐ") { return tstem + "いだ" }
        if str_ends_with(dict_form, "gu") { return tstem + "ida" }
        if str_ends_with(dict_form, "ぬ") { return tstem + "んだ" }
        if str_ends_with(dict_form, "ぶ") { return tstem + "んだ" }
        if str_ends_with(dict_form, "む") { return tstem + "んだ" }
        if str_ends_with(dict_form, "nu") { return tstem + "nda" }
        if str_ends_with(dict_form, "bu") { return tstem + "nda" }
        if str_ends_with(dict_form, "mu") { return tstem + "nda" }
        if str_ends_with(dict_form, "す") { return tstem + "した" }
        if str_ends_with(dict_form, "su") { return tstem + "shita" }
        if str_ends_with(dict_form, "く") { return tstem + "た" }
        if str_ends_with(dict_form, "ku") { return tstem + "ta" }
        return tstem + "た"
    }

    return dict_form
}

// ── Case particles ────────────────────────────────────────────────────────────
//
// Japanese nouns do not inflect; case is indicated by a postpositional particle
// placed directly after the noun.

fn ja_particle(gram_case: String) -> String {
    if str_eq(gram_case, "nominative")   { return "が" }
    if str_eq(gram_case, "accusative")   { return "を" }
    if str_eq(gram_case, "dative")       { return "に" }
    if str_eq(gram_case, "genitive")     { return "の" }
    if str_eq(gram_case, "topic")        { return "は" }
    if str_eq(gram_case, "instrumental") { return "で" }
    if str_eq(gram_case, "locative")     { return "に" }
    if str_eq(gram_case, "ablative")     { return "から" }
    if str_eq(gram_case, "direction")    { return "へ" }
    if str_eq(gram_case, "comitative")   { return "と" }
    return ""
}

// ── Noun phrase construction ──────────────────────────────────────────────────
//
// ja_noun_phrase: attach the correct case particle to a noun.
// The particle immediately follows the noun with no space.

fn ja_noun_phrase(noun: String, gram_case: String) -> String {
    let p: String = ja_particle(gram_case)
    if str_eq(p, "") {
        return noun
    }
    return noun + p
}

// ── Question particle ─────────────────────────────────────────────────────────
//
// Japanese questions are formed by appending か (ka) to the end of a sentence.

fn ja_question_particle() -> String {
    return "か"
}

// ── Sentence-final particle attachment ───────────────────────────────────────
//
// ja_make_question: append the question particle to a sentence.

fn ja_make_question(sentence: String) -> String {
    return sentence + ja_question_particle()
}
