// morphology-pi.el - Pali morphology for the NLG engine.
//
// Implements Pali verb conjugation and noun declension using standard IAST-subset
// Latin transliteration.  Pali is the liturgical language of Theravada Buddhism
// (canonical form of Middle Indo-Aryan, ca. 3rd century BCE).
//
// Language profile: code=pi, name=Pali, morph_type=fusional, word_order=SOV,
//   question_strategy=particle, script=latin-iast, family=indo-aryan.
//
// Verb conjugation covered:
//   Tenses:   present (bhū-ādi class), aorist (past), future
//   Persons:  first/second/third x singular/plural (slots 0-5)
//   Endings:  present -āmi/-asi/-ati/-āma/-atha/-anti
//             aorist  -iṃ/-i/-i/-imhā/-ittha/-iṃsu
//             future  -issāmi/-issasi/-issati/-issāma/-issatha/-issanti
//   Irregulars: atthi/hoti (be), gacchati (go), passati (see),
//               vadati (say), karoti (do)
//   Canonical map: "be" -> "hoti"
//
// Noun declension covered:
//   a-stem masculine (paradigm: "purisa" — man): 8 cases, sg + pl
//   ā-stem feminine  (paradigm: "kaññā" — girl): 8 cases, sg (pl approx.)
//   Cases: nominative, accusative, instrumental, dative, ablative,
//          genitive, locative, vocative
//
// Articles:
//   Pali has no articles.  pi_noun_phrase returns the declined noun directly.
//
// Depends on: morphology.el (str_ends_with, str_len, str_slice, str_eq)

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

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

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

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

// ── Person/number slot ─────────────────────────────────────────────────────────
//
// Maps person x number to a 0-based paradigm slot.
//   0 = 1st singular   (ahaṃ)
//   1 = 2nd singular   (tvaṃ)
//   2 = 3rd singular   (so/sā/taṃ)
//   3 = 1st plural     (mayaṃ)
//   4 = 2nd plural     (tumhe)
//   5 = 3rd plural     (te/tā/tāni)

fn pi_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
}

// ── Present tense endings (bhū-ādi class) ─────────────────────────────────────
//
// The standard present active endings for the most common Pali verb class:
//   1sg -āmi   2sg -asi   3sg -ati
//   1pl -āma   2pl -atha  3pl -anti

fn pi_present_ending(slot: Int) -> String {
    if slot == 0 { return "āmi" }
    if slot == 1 { return "asi" }
    if slot == 2 { return "ati" }
    if slot == 3 { return "āma" }
    if slot == 4 { return "atha" }
    return "anti"
}

// ── Aorist (past) tense endings ───────────────────────────────────────────────
//
// The Pali aorist is the standard simple past.  The most common set:
//   1sg -iṃ    2sg -i    3sg -i
//   1pl -imhā  2pl -ittha 3pl -iṃsu
//
// These are appended to the verb root (or a modified stem).  For regular
// weak aorists, the root is taken from the infinitive by stripping -ati.

fn pi_aorist_ending(slot: Int) -> String {
    if slot == 0 { return "iṃ" }
    if slot == 1 { return "i" }
    if slot == 2 { return "i" }
    if slot == 3 { return "imhā" }
    if slot == 4 { return "ittha" }
    return "iṃsu"
}

// ── Future tense endings ───────────────────────────────────────────────────────
//
// Future is formed with the suffix -issa- inserted between root and personal ending:
//   1sg -issāmi   2sg -issasi   3sg -issati
//   1pl -issāma   2pl -issatha  3pl -issanti

fn pi_future_ending(slot: Int) -> String {
    if slot == 0 { return "issāmi" }
    if slot == 1 { return "issasi" }
    if slot == 2 { return "issati" }
    if slot == 3 { return "issāma" }
    if slot == 4 { return "issatha" }
    return "issanti"
}

// ── Irregular verb tables ──────────────────────────────────────────────────────
//
// atthi/hoti (to be): two parallel paradigms.
// The "hoti" paradigm is used by default (canonical "be" maps here).
// "atthi" paradigm is included for the commonly seen alternative.

fn pi_hoti_present(slot: Int) -> String {
    if slot == 0 { return "homi" }
    if slot == 1 { return "hosi" }
    if slot == 2 { return "hoti" }
    if slot == 3 { return "homa" }
    if slot == 4 { return "hotha" }
    return "honti"
}

fn pi_atthi_present(slot: Int) -> String {
    if slot == 0 { return "amhi" }
    if slot == 1 { return "asi" }
    if slot == 2 { return "atthi" }
    if slot == 3 { return "amha" }
    if slot == 4 { return "attha" }
    return "santi"
}

// Past (aorist) of hoti/atthi: āsi paradigm (a-aorist)
fn pi_hoti_aorist(slot: Int) -> String {
    if slot == 0 { return "āsiṃ" }
    if slot == 1 { return "āsi" }
    if slot == 2 { return "āsi" }
    if slot == 3 { return "āsimhā" }
    if slot == 4 { return "āsittha" }
    return "āsiṃsu"
}

// Future of hoti: regular -issa- on root "ho-"
fn pi_hoti_future(slot: Int) -> String {
    if slot == 0 { return "hossāmi" }
    if slot == 1 { return "hossasi" }
    if slot == 2 { return "hossati" }
    if slot == 3 { return "hossāma" }
    if slot == 4 { return "hossatha" }
    return "hossanti"
}

// gacchati (to go): present is suppletive; aorist uses root "gam-"/"agamā-"
fn pi_gacchati_present(slot: Int) -> String {
    if slot == 0 { return "gacchāmi" }
    if slot == 1 { return "gacchasi" }
    if slot == 2 { return "gacchati" }
    if slot == 3 { return "gacchāma" }
    if slot == 4 { return "gacchatha" }
    return "gacchanti"
}

fn pi_gacchati_aorist(slot: Int) -> String {
    if slot == 0 { return "agamāsiṃ" }
    if slot == 1 { return "agamāsi" }
    if slot == 2 { return "agamāsi" }
    if slot == 3 { return "agamāsimhā" }
    if slot == 4 { return "agamāsittha" }
    return "agamaṃsu"
}

fn pi_gacchati_future(slot: Int) -> String {
    if slot == 0 { return "gamissāmi" }
    if slot == 1 { return "gamissasi" }
    if slot == 2 { return "gamissati" }
    if slot == 3 { return "gamissāma" }
    if slot == 4 { return "gamissatha" }
    return "gamissanti"
}

// passati (to see): regular present; aorist root "dis-"/"addasā-"
fn pi_passati_present(slot: Int) -> String {
    if slot == 0 { return "passāmi" }
    if slot == 1 { return "passasi" }
    if slot == 2 { return "passati" }
    if slot == 3 { return "passāma" }
    if slot == 4 { return "passatha" }
    return "passanti"
}

fn pi_passati_aorist(slot: Int) -> String {
    if slot == 0 { return "addasāsiṃ" }
    if slot == 1 { return "addasāsi" }
    if slot == 2 { return "addasāsi" }
    if slot == 3 { return "addasāsimhā" }
    if slot == 4 { return "addasāsittha" }
    return "addasāsiṃsu"
}

fn pi_passati_future(slot: Int) -> String {
    if slot == 0 { return "dakkhissāmi" }
    if slot == 1 { return "dakkhissasi" }
    if slot == 2 { return "dakkhissati" }
    if slot == 3 { return "dakkhissāma" }
    if slot == 4 { return "dakkhissatha" }
    return "dakkhissanti"
}

// vadati (to say): regular throughout; aorist uses avadi-
fn pi_vadati_present(slot: Int) -> String {
    if slot == 0 { return "vadāmi" }
    if slot == 1 { return "vadasi" }
    if slot == 2 { return "vadati" }
    if slot == 3 { return "vadāma" }
    if slot == 4 { return "vadatha" }
    return "vadanti"
}

fn pi_vadati_aorist(slot: Int) -> String {
    if slot == 0 { return "avadāsiṃ" }
    if slot == 1 { return "avadāsi" }
    if slot == 2 { return "avadāsi" }
    if slot == 3 { return "avadāsimhā" }
    if slot == 4 { return "avadāsittha" }
    return "avadāsiṃsu"
}

fn pi_vadati_future(slot: Int) -> String {
    if slot == 0 { return "vadissāmi" }
    if slot == 1 { return "vadissasi" }
    if slot == 2 { return "vadissati" }
    if slot == 3 { return "vadissāma" }
    if slot == 4 { return "vadissatha" }
    return "vadissanti"
}

// karoti (to do/make): karo- present stem; kāri-/akāsi aorist
fn pi_karoti_present(slot: Int) -> String {
    if slot == 0 { return "karomi" }
    if slot == 1 { return "karosi" }
    if slot == 2 { return "karoti" }
    if slot == 3 { return "karoma" }
    if slot == 4 { return "karotha" }
    return "karonti"
}

fn pi_karoti_aorist(slot: Int) -> String {
    if slot == 0 { return "akāsiṃ" }
    if slot == 1 { return "akāsi" }
    if slot == 2 { return "akāsi" }
    if slot == 3 { return "akāsimhā" }
    if slot == 4 { return "akāsittha" }
    return "akāsiṃsu"
}

fn pi_karoti_future(slot: Int) -> String {
    if slot == 0 { return "karissāmi" }
    if slot == 1 { return "karissasi" }
    if slot == 2 { return "karissati" }
    if slot == 3 { return "karissāma" }
    if slot == 4 { return "karissatha" }
    return "karissanti"
}

// ── Canonical verb mapping ─────────────────────────────────────────────────────
//
// Maps English semantic labels to Pali verb citation forms (3rd sg present).

fn pi_map_canonical(verb: String) -> String {
    if str_eq(verb, "be")   { return "hoti" }
    if str_eq(verb, "go")   { return "gacchati" }
    if str_eq(verb, "see")  { return "passati" }
    if str_eq(verb, "say")  { return "vadati" }
    if str_eq(verb, "do")   { return "karoti" }
    if str_eq(verb, "make") { return "karoti" }
    return verb
}

// ── Regular verb stem derivation ───────────────────────────────────────────────
//
// For bhū-ādi class verbs, the present stem is derived by stripping -ati from
// the 3sg present form (the citation form), then appending the appropriate ending.
// The same root (without -ati) is used for the aorist and future.
//
// e.g. "bhavati" -> root "bhava" -> present "bhavāmi", future "bhavissāmi"
//                                -> aorist root = "bhavi" -> "bhaviṃ"

fn pi_regular_root(verb: String) -> String {
    // Strip -ati if present to get the thematic stem
    if pi_str_ends(verb, "ati") { return pi_drop(verb, 3) }
    // Some forms end in -eti (e-class verbs)
    if pi_str_ends(verb, "eti") { return pi_drop(verb, 3) }
    // Otherwise treat the whole form as the root
    return verb
}

// ── pi_conjugate: main conjugation entry point ────────────────────────────────
//
// verb:   Pali 3sg present (citation form, e.g. "bhavati", "hoti") or English
//         canonical label
// tense:  "present" | "past" | "future"
// person: "first" | "second" | "third"
// number: "singular" | "plural"
//
// Returns the inflected form.  Falls back to the citation form on unknown input.

fn pi_conjugate(verb: String, tense: String, person: String, number: String) -> String {
    let v: String = pi_map_canonical(verb)
    let slot: Int = pi_slot(person, number)

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

    if str_eq(v, "hoti") {
        if str_eq(tense, "present") { return pi_hoti_present(slot) }
        if str_eq(tense, "past")    { return pi_hoti_aorist(slot) }
        if str_eq(tense, "future")  { return pi_hoti_future(slot) }
        return v
    }

    if str_eq(v, "atthi") {
        if str_eq(tense, "present") { return pi_atthi_present(slot) }
        if str_eq(tense, "past")    { return pi_hoti_aorist(slot) }
        if str_eq(tense, "future")  { return pi_hoti_future(slot) }
        return v
    }

    if str_eq(v, "gacchati") {
        if str_eq(tense, "present") { return pi_gacchati_present(slot) }
        if str_eq(tense, "past")    { return pi_gacchati_aorist(slot) }
        if str_eq(tense, "future")  { return pi_gacchati_future(slot) }
        return v
    }

    if str_eq(v, "passati") {
        if str_eq(tense, "present") { return pi_passati_present(slot) }
        if str_eq(tense, "past")    { return pi_passati_aorist(slot) }
        if str_eq(tense, "future")  { return pi_passati_future(slot) }
        return v
    }

    if str_eq(v, "vadati") {
        if str_eq(tense, "present") { return pi_vadati_present(slot) }
        if str_eq(tense, "past")    { return pi_vadati_aorist(slot) }
        if str_eq(tense, "future")  { return pi_vadati_future(slot) }
        return v
    }

    if str_eq(v, "karoti") {
        if str_eq(tense, "present") { return pi_karoti_present(slot) }
        if str_eq(tense, "past")    { return pi_karoti_aorist(slot) }
        if str_eq(tense, "future")  { return pi_karoti_future(slot) }
        return v
    }

    // ── Regular bhū-ādi class verb ────────────────────────────────────────────

    let root: String = pi_regular_root(v)

    if str_eq(tense, "present") {
        return root + pi_present_ending(slot)
    }

    if str_eq(tense, "past") {
        // Aorist: root + i-aorist ending
        return root + pi_aorist_ending(slot)
    }

    if str_eq(tense, "future") {
        return root + pi_future_ending(slot)
    }

    // Unknown tense: return citation form unchanged
    return v
}

// ── a-stem masculine declension ("purisa" — man) ─────────────────────────────
//
// The a-stem masculine is the most frequent Pali declension class.
// Paradigm based on "puriso" (nominative singular).
//
// Eight cases: nominative, accusative, instrumental, dative, ablative,
//              genitive, locative, vocative.
//
// Singular:
//   nom  puriso     acc  purisaṃ    instr purisena    dat  purisāya (or purissā)
//   abl  purisā     gen  purisassa  loc   purisasmiṃ  voc  purisa
//
// Plural:
//   nom  purisā     acc  purise     instr purisehi    dat  purisānaṃ
//   abl  purisānaṃ  gen  purisānaṃ  loc   purisesu    voc  purisā
//
// The caller passes the stem (without final vowel), e.g. "purisa".
// Detection: strip the final -o (nom sg) or use the stem directly.

fn pi_decline_a_masc_sg(stem: String, gram_case: String) -> String {
    if str_eq(gram_case, "nominative")    { return stem + "o" }
    if str_eq(gram_case, "accusative")    { return stem + "ṃ" }
    if str_eq(gram_case, "instrumental")  { return stem + "ena" }
    if str_eq(gram_case, "dative")        { return stem + "āya" }
    if str_eq(gram_case, "ablative")      { return stem + "ā" }
    if str_eq(gram_case, "genitive")      { return stem + "ssa" }
    if str_eq(gram_case, "locative")      { return stem + "smiṃ" }
    if str_eq(gram_case, "vocative")      { return stem }
    // Default: nominative
    return stem + "o"
}

fn pi_decline_a_masc_pl(stem: String, gram_case: String) -> String {
    if str_eq(gram_case, "nominative")    { return stem + "ā" }
    if str_eq(gram_case, "accusative")    { return stem + "e" }
    if str_eq(gram_case, "instrumental")  { return stem + "ehi" }
    if str_eq(gram_case, "dative")        { return stem + "ānaṃ" }
    if str_eq(gram_case, "ablative")      { return stem + "ānaṃ" }
    if str_eq(gram_case, "genitive")      { return stem + "ānaṃ" }
    if str_eq(gram_case, "locative")      { return stem + "esu" }
    if str_eq(gram_case, "vocative")      { return stem + "ā" }
    return stem + "ā"
}

// ── ā-stem feminine declension ("kaññā" — girl) ───────────────────────────────
//
// ā-stem feminines are the second most common class.  Paradigm based on "kaññā".
//
// Singular:
//   nom  kaññā      acc  kaññaṃ     instr kaññāya    dat  kaññāya
//   abl  kaññāya    gen  kaññāya    loc   kaññāyaṃ   voc  kaññe
//
// Plural (approximated from standard tables; many forms merge):
//   nom  kaññā      acc  kaññā      instr kaññāhi    dat  kaññānaṃ
//   abl  kaññānaṃ   gen  kaññānaṃ   loc   kaññāsu    voc  kaññā
//
// The caller passes the stem without the final ā, e.g. "kaññ".

fn pi_decline_a_fem_sg(stem: String, gram_case: String) -> String {
    if str_eq(gram_case, "nominative")    { return stem + "ā" }
    if str_eq(gram_case, "accusative")    { return stem + "aṃ" }
    if str_eq(gram_case, "instrumental")  { return stem + "āya" }
    if str_eq(gram_case, "dative")        { return stem + "āya" }
    if str_eq(gram_case, "ablative")      { return stem + "āya" }
    if str_eq(gram_case, "genitive")      { return stem + "āya" }
    if str_eq(gram_case, "locative")      { return stem + "āyaṃ" }
    if str_eq(gram_case, "vocative")      { return stem + "e" }
    return stem + "ā"
}

fn pi_decline_a_fem_pl(stem: String, gram_case: String) -> String {
    if str_eq(gram_case, "nominative")    { return stem + "ā" }
    if str_eq(gram_case, "accusative")    { return stem + "ā" }
    if str_eq(gram_case, "instrumental")  { return stem + "āhi" }
    if str_eq(gram_case, "dative")        { return stem + "ānaṃ" }
    if str_eq(gram_case, "ablative")      { return stem + "ānaṃ" }
    if str_eq(gram_case, "genitive")      { return stem + "ānaṃ" }
    if str_eq(gram_case, "locative")      { return stem + "āsu" }
    if str_eq(gram_case, "vocative")      { return stem + "ā" }
    return stem + "ā"
}

// ── Declension class detection ─────────────────────────────────────────────────
//
// Detect whether a noun is an a-stem masculine or ā-stem feminine based on its
// citation form (nominative singular).
//
//   ends in -o -> a-stem masculine (puriso, devo, loko)
//   ends in -ā -> ā-stem feminine  (kaññā, mātu[?], nadī)
//   ends in -a -> treat as a-stem masculine stem (some words cited without -o)
//
// For other stems the module falls back to a-stem masculine as the safest default.

fn pi_detect_class(noun: String) -> String {
    if pi_str_ends(noun, "o") { return "a_masc" }
    if pi_str_ends(noun, "ā") { return "a_fem" }
    // Some a-masc nouns may be cited as stems ending in -a
    if pi_str_ends(noun, "a") { return "a_masc" }
    // Default to a-stem masculine
    return "a_masc"
}

// ── pi_decline: main declension entry point ───────────────────────────────────
//
// noun:      Pali nominative singular (citation form, e.g. "puriso", "kaññā")
// gram_case: "nominative" | "accusative" | "instrumental" | "dative" |
//            "ablative" | "genitive" | "locative" | "vocative"
// number:    "singular" | "plural"
//
// Returns the inflected form.  Falls back to the citation form on unknown input.

fn pi_decline(noun: String, gram_case: String, number: String) -> String {
    let nclass: String = pi_detect_class(noun)

    if str_eq(nclass, "a_masc") {
        // Derive stem: strip final -o or -a to get the consonant stem
        let stem: String = noun
        if pi_str_ends(noun, "o") {
            let stem = pi_drop(noun, 1)
        }
        if pi_str_ends(noun, "a") {
            let stem = pi_drop(noun, 1)
        }
        if str_eq(number, "singular") { return pi_decline_a_masc_sg(stem, gram_case) }
        return pi_decline_a_masc_pl(stem, gram_case)
    }

    if str_eq(nclass, "a_fem") {
        // Derive stem: strip final -ā
        let stem: String = noun
        if pi_str_ends(noun, "ā") {
            let stem = pi_drop(noun, 1)
        }
        if str_eq(number, "singular") { return pi_decline_a_fem_sg(stem, gram_case) }
        return pi_decline_a_fem_pl(stem, gram_case)
    }

    // Unknown class: return citation form unchanged
    return noun
}

// ── pi_noun_phrase: noun phrase builder ──────────────────────────────────────
//
// Pali has no articles (definite or indefinite).  The declined form is the
// complete noun phrase.  The definite parameter is accepted for interface
// compatibility with other language modules but has no effect.
//
// noun:      nominative singular Pali noun (e.g. "puriso", "kaññā")
// gram_case: "nominative" | "accusative" | "instrumental" | "dative" |
//            "ablative" | "genitive" | "locative" | "vocative"
// number:    "singular" | "plural"
// definite:  ignored (Pali has no articles)
//
// Returns the inflected noun form.

fn pi_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String {
    return pi_decline(noun, gram_case, number)
}
