// morphology-es.el - Spanish morphology for the NLG engine.
//
// Implements fusional Spanish verb conjugation, noun pluralization, gender
// inference, and article agreement.  Designed as a companion to morphology.el
// and called by the engine when the language profile code is "es".
//
// Verb tenses covered: present, preterite (past), future, imperfect.
// Persons: first/second/third × singular/plural (1s 2s 3s 1p 2p 3p).
// Verb classes: -ar, -er, -ir (regular) + a core set of common irregulars.
//
// Depends on: morphology.el (str_ends, str_drop_last, str_last_char, str_last2, str_last3, is_vowel)

// ── String helpers (local, matching morphology.el conventions) ────────────────

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

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

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

fn es_str_last2(s: String) -> String {
    let n: Int = str_len(s)
    if n < 2 {
        return s
    }
    return str_slice(s, n - 2, n)
}

fn es_str_last3(s: String) -> String {
    let n: Int = str_len(s)
    if n < 3 {
        return s
    }
    return str_slice(s, n - 3, n)
}

// ── Verb class detection ──────────────────────────────────────────────────────
//
// Spanish verbs fall into three conjugation classes defined by the infinitive
// ending: -ar, -er, -ir.  The stem is the infinitive minus those two characters.

fn es_verb_class(base: String) -> String {
    if es_str_ends(base, "ar") { return "ar" }
    if es_str_ends(base, "er") { return "er" }
    if es_str_ends(base, "ir") { return "ir" }
    return "ar"
}

fn es_stem(base: String) -> String {
    return es_str_drop_last(base, 2)
}

// ── Person/number index ───────────────────────────────────────────────────────
//
// Maps person × number to a 0-based slot index used inside paradigm tables.
//   0 = 1s, 1 = 2s, 2 = 3s, 3 = 1p, 4 = 2p, 5 = 3p

fn es_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 present tense ───────────────────────────────────────────────────
//
// Returns the fully-inflected form if the verb is irregular in the present
// tense for the given person/number slot, otherwise returns "".
//
// ser:   soy, eres, es, somos, sois, son
// estar: estoy, estás, está, estamos, estáis, están
// tener: tengo, tienes, tiene, tenemos, tenéis, tienen
// hacer: hago, haces, hace, hacemos, hacéis, hacen
// ir:    voy, vas, va, vamos, vais, van
// ver:   veo, ves, ve, vemos, veis, ven
// dar:   doy, das, da, damos, dais, dan
// saber: sé, sabes, sabe, sabemos, sabéis, saben
// poder: puedo, puedes, puede, podemos, podéis, pueden
// querer: quiero, quieres, quiere, queremos, queréis, quieren
// venir: vengo, vienes, viene, venimos, venís, vienen
// decir: digo, dices, dice, decimos, decís, dicen
// haber: he, has, ha, hemos, habéis, han

fn es_irregular_present(verb: String, person: String, number: String) -> String {
    let slot: Int = es_slot(person, number)

    if str_eq(verb, "ser") {
        if slot == 0 { return "soy" }
        if slot == 1 { return "eres" }
        if slot == 2 { return "es" }
        if slot == 3 { return "somos" }
        if slot == 4 { return "sois" }
        return "son"
    }

    if str_eq(verb, "estar") {
        if slot == 0 { return "estoy" }
        if slot == 1 { return "estás" }
        if slot == 2 { return "está" }
        if slot == 3 { return "estamos" }
        if slot == 4 { return "estáis" }
        return "están"
    }

    if str_eq(verb, "tener") {
        if slot == 0 { return "tengo" }
        if slot == 1 { return "tienes" }
        if slot == 2 { return "tiene" }
        if slot == 3 { return "tenemos" }
        if slot == 4 { return "tenéis" }
        return "tienen"
    }

    if str_eq(verb, "hacer") {
        if slot == 0 { return "hago" }
        if slot == 1 { return "haces" }
        if slot == 2 { return "hace" }
        if slot == 3 { return "hacemos" }
        if slot == 4 { return "hacéis" }
        return "hacen"
    }

    if str_eq(verb, "ir") {
        if slot == 0 { return "voy" }
        if slot == 1 { return "vas" }
        if slot == 2 { return "va" }
        if slot == 3 { return "vamos" }
        if slot == 4 { return "vais" }
        return "van"
    }

    if str_eq(verb, "ver") {
        if slot == 0 { return "veo" }
        if slot == 1 { return "ves" }
        if slot == 2 { return "ve" }
        if slot == 3 { return "vemos" }
        if slot == 4 { return "veis" }
        return "ven"
    }

    if str_eq(verb, "dar") {
        if slot == 0 { return "doy" }
        if slot == 1 { return "das" }
        if slot == 2 { return "da" }
        if slot == 3 { return "damos" }
        if slot == 4 { return "dais" }
        return "dan"
    }

    if str_eq(verb, "saber") {
        if slot == 0 { return "sé" }
        if slot == 1 { return "sabes" }
        if slot == 2 { return "sabe" }
        if slot == 3 { return "sabemos" }
        if slot == 4 { return "sabéis" }
        return "saben"
    }

    if str_eq(verb, "poder") {
        if slot == 0 { return "puedo" }
        if slot == 1 { return "puedes" }
        if slot == 2 { return "puede" }
        if slot == 3 { return "podemos" }
        if slot == 4 { return "podéis" }
        return "pueden"
    }

    if str_eq(verb, "querer") {
        if slot == 0 { return "quiero" }
        if slot == 1 { return "quieres" }
        if slot == 2 { return "quiere" }
        if slot == 3 { return "queremos" }
        if slot == 4 { return "queréis" }
        return "quieren"
    }

    if str_eq(verb, "venir") {
        if slot == 0 { return "vengo" }
        if slot == 1 { return "vienes" }
        if slot == 2 { return "viene" }
        if slot == 3 { return "venimos" }
        if slot == 4 { return "venís" }
        return "vienen"
    }

    if str_eq(verb, "decir") {
        if slot == 0 { return "digo" }
        if slot == 1 { return "dices" }
        if slot == 2 { return "dice" }
        if slot == 3 { return "decimos" }
        if slot == 4 { return "decís" }
        return "dicen"
    }

    if str_eq(verb, "haber") {
        if slot == 0 { return "he" }
        if slot == 1 { return "has" }
        if slot == 2 { return "ha" }
        if slot == 3 { return "hemos" }
        if slot == 4 { return "habéis" }
        return "han"
    }

    return ""
}

// ── Irregular preterite tense ─────────────────────────────────────────────────
//
// Returns the inflected preterite form for irregular verbs, or "" if regular.
//
// ser/ir (same preterite): fui, fuiste, fue, fuimos, fuisteis, fueron
// tener:  tuve, tuviste, tuvo, tuvimos, tuvisteis, tuvieron
// hacer:  hice, hiciste, hizo, hicimos, hicisteis, hicieron
// estar:  estuve, estuviste, estuvo, estuvimos, estuvisteis, estuvieron
// dar:    di, diste, dio, dimos, disteis, dieron
// saber:  supe, supiste, supo, supimos, supisteis, supieron
// poder:  pude, pudiste, pudo, pudimos, pudisteis, pudieron
// querer: quise, quisiste, quiso, quisimos, quisisteis, quisieron
// venir:  vine, viniste, vino, vinimos, vinisteis, vinieron
// decir:  dije, dijiste, dijo, dijimos, dijisteis, dijeron
// haber:  hube, hubiste, hubo, hubimos, hubisteis, hubieron
// ver:    vi, viste, vio, vimos, visteis, vieron

fn es_irregular_preterite(verb: String, person: String, number: String) -> String {
    let slot: Int = es_slot(person, number)

    if str_eq(verb, "ser") {
        if slot == 0 { return "fui" }
        if slot == 1 { return "fuiste" }
        if slot == 2 { return "fue" }
        if slot == 3 { return "fuimos" }
        if slot == 4 { return "fuisteis" }
        return "fueron"
    }

    if str_eq(verb, "ir") {
        if slot == 0 { return "fui" }
        if slot == 1 { return "fuiste" }
        if slot == 2 { return "fue" }
        if slot == 3 { return "fuimos" }
        if slot == 4 { return "fuisteis" }
        return "fueron"
    }

    if str_eq(verb, "tener") {
        if slot == 0 { return "tuve" }
        if slot == 1 { return "tuviste" }
        if slot == 2 { return "tuvo" }
        if slot == 3 { return "tuvimos" }
        if slot == 4 { return "tuvisteis" }
        return "tuvieron"
    }

    if str_eq(verb, "hacer") {
        if slot == 0 { return "hice" }
        if slot == 1 { return "hiciste" }
        if slot == 2 { return "hizo" }
        if slot == 3 { return "hicimos" }
        if slot == 4 { return "hicisteis" }
        return "hicieron"
    }

    if str_eq(verb, "estar") {
        if slot == 0 { return "estuve" }
        if slot == 1 { return "estuviste" }
        if slot == 2 { return "estuvo" }
        if slot == 3 { return "estuvimos" }
        if slot == 4 { return "estuvisteis" }
        return "estuvieron"
    }

    if str_eq(verb, "dar") {
        if slot == 0 { return "di" }
        if slot == 1 { return "diste" }
        if slot == 2 { return "dio" }
        if slot == 3 { return "dimos" }
        if slot == 4 { return "disteis" }
        return "dieron"
    }

    if str_eq(verb, "saber") {
        if slot == 0 { return "supe" }
        if slot == 1 { return "supiste" }
        if slot == 2 { return "supo" }
        if slot == 3 { return "supimos" }
        if slot == 4 { return "supisteis" }
        return "supieron"
    }

    if str_eq(verb, "poder") {
        if slot == 0 { return "pude" }
        if slot == 1 { return "pudiste" }
        if slot == 2 { return "pudo" }
        if slot == 3 { return "pudimos" }
        if slot == 4 { return "pudisteis" }
        return "pudieron"
    }

    if str_eq(verb, "querer") {
        if slot == 0 { return "quise" }
        if slot == 1 { return "quisiste" }
        if slot == 2 { return "quiso" }
        if slot == 3 { return "quisimos" }
        if slot == 4 { return "quisisteis" }
        return "quisieron"
    }

    if str_eq(verb, "venir") {
        if slot == 0 { return "vine" }
        if slot == 1 { return "viniste" }
        if slot == 2 { return "vino" }
        if slot == 3 { return "vinimos" }
        if slot == 4 { return "vinisteis" }
        return "vinieron"
    }

    if str_eq(verb, "decir") {
        if slot == 0 { return "dije" }
        if slot == 1 { return "dijiste" }
        if slot == 2 { return "dijo" }
        if slot == 3 { return "dijimos" }
        if slot == 4 { return "dijisteis" }
        return "dijeron"
    }

    if str_eq(verb, "haber") {
        if slot == 0 { return "hube" }
        if slot == 1 { return "hubiste" }
        if slot == 2 { return "hubo" }
        if slot == 3 { return "hubimos" }
        if slot == 4 { return "hubisteis" }
        return "hubieron"
    }

    if str_eq(verb, "ver") {
        if slot == 0 { return "vi" }
        if slot == 1 { return "viste" }
        if slot == 2 { return "vio" }
        if slot == 3 { return "vimos" }
        if slot == 4 { return "visteis" }
        return "vieron"
    }

    return ""
}

// ── Irregular imperfect tense ─────────────────────────────────────────────────
//
// Only three verbs are truly irregular in the imperfect:
// ser:  era, eras, era, éramos, erais, eran
// ir:   iba, ibas, iba, íbamos, ibais, iban
// ver:  veía, veías, veía, veíamos, veíais, veían

fn es_irregular_imperfect(verb: String, person: String, number: String) -> String {
    let slot: Int = es_slot(person, number)

    if str_eq(verb, "ser") {
        if slot == 0 { return "era" }
        if slot == 1 { return "eras" }
        if slot == 2 { return "era" }
        if slot == 3 { return "éramos" }
        if slot == 4 { return "erais" }
        return "eran"
    }

    if str_eq(verb, "ir") {
        if slot == 0 { return "iba" }
        if slot == 1 { return "ibas" }
        if slot == 2 { return "iba" }
        if slot == 3 { return "íbamos" }
        if slot == 4 { return "ibais" }
        return "iban"
    }

    if str_eq(verb, "ver") {
        if slot == 0 { return "veía" }
        if slot == 1 { return "veías" }
        if slot == 2 { return "veía" }
        if slot == 3 { return "veíamos" }
        if slot == 4 { return "veíais" }
        return "veían"
    }

    return ""
}

// ── Regular present conjugation ───────────────────────────────────────────────
//
// -ar: -o, -as, -a, -amos, -áis, -an
// -er: -o, -es, -e, -emos, -éis, -en
// -ir: -o, -es, -e, -imos, -ís, -en

fn es_regular_present(stem: String, vclass: String, slot: Int) -> String {
    if str_eq(vclass, "ar") {
        if slot == 0 { return stem + "o" }
        if slot == 1 { return stem + "as" }
        if slot == 2 { return stem + "a" }
        if slot == 3 { return stem + "amos" }
        if slot == 4 { return stem + "áis" }
        return stem + "an"
    }
    if str_eq(vclass, "er") {
        if slot == 0 { return stem + "o" }
        if slot == 1 { return stem + "es" }
        if slot == 2 { return stem + "e" }
        if slot == 3 { return stem + "emos" }
        if slot == 4 { return stem + "éis" }
        return stem + "en"
    }
    // -ir
    if slot == 0 { return stem + "o" }
    if slot == 1 { return stem + "es" }
    if slot == 2 { return stem + "e" }
    if slot == 3 { return stem + "imos" }
    if slot == 4 { return stem + "ís" }
    return stem + "en"
}

// ── Regular preterite conjugation ─────────────────────────────────────────────
//
// -ar: -é, -aste, -ó, -amos, -asteis, -aron
// -er: -í, -iste, -ió, -imos, -isteis, -ieron
// -ir: -í, -iste, -ió, -imos, -isteis, -ieron

fn es_regular_preterite(stem: String, vclass: String, slot: Int) -> String {
    if str_eq(vclass, "ar") {
        if slot == 0 { return stem + "é" }
        if slot == 1 { return stem + "aste" }
        if slot == 2 { return stem + "ó" }
        if slot == 3 { return stem + "amos" }
        if slot == 4 { return stem + "asteis" }
        return stem + "aron"
    }
    // -er and -ir share the same preterite endings
    if slot == 0 { return stem + "í" }
    if slot == 1 { return stem + "iste" }
    if slot == 2 { return stem + "ió" }
    if slot == 3 { return stem + "imos" }
    if slot == 4 { return stem + "isteis" }
    return stem + "ieron"
}

// ── Regular future conjugation ────────────────────────────────────────────────
//
// Future is formed from the full infinitive + endings (all classes):
// -é, -ás, -á, -emos, -éis, -án
//
// No stem change; the infinitive is the future stem.

fn es_regular_future(base: String, slot: Int) -> String {
    if slot == 0 { return base + "é" }
    if slot == 1 { return base + "ás" }
    if slot == 2 { return base + "á" }
    if slot == 3 { return base + "emos" }
    if slot == 4 { return base + "éis" }
    return base + "án"
}

// ── Irregular future stems ────────────────────────────────────────────────────
//
// Some verbs contract or alter their infinitive for the future stem.
// Returns the irregular future stem, or "" if the verb uses the regular stem.

fn es_irregular_future_stem(verb: String) -> String {
    if str_eq(verb, "tener") { return "tendr" }
    if str_eq(verb, "hacer") { return "har" }
    if str_eq(verb, "poder") { return "podr" }
    if str_eq(verb, "querer") { return "querr" }
    if str_eq(verb, "venir") { return "vendr" }
    if str_eq(verb, "decir") { return "dir" }
    if str_eq(verb, "haber") { return "habr" }
    if str_eq(verb, "saber") { return "sabr" }
    if str_eq(verb, "salir") { return "saldr" }
    if str_eq(verb, "poner") { return "pondr" }
    return ""
}

// ── Regular imperfect conjugation ─────────────────────────────────────────────
//
// -ar: -aba, -abas, -aba, -ábamos, -abais, -aban
// -er/-ir: -ía, -ías, -ía, -íamos, -íais, -ían

fn es_regular_imperfect(stem: String, vclass: String, slot: Int) -> String {
    if str_eq(vclass, "ar") {
        if slot == 0 { return stem + "aba" }
        if slot == 1 { return stem + "abas" }
        if slot == 2 { return stem + "aba" }
        if slot == 3 { return stem + "ábamos" }
        if slot == 4 { return stem + "abais" }
        return stem + "aban"
    }
    // -er and -ir
    if slot == 0 { return stem + "ía" }
    if slot == 1 { return stem + "ías" }
    if slot == 2 { return stem + "ía" }
    if slot == 3 { return stem + "íamos" }
    if slot == 4 { return stem + "íais" }
    return stem + "ían"
}

// ── Full conjugation entry point ──────────────────────────────────────────────
//
// es_conjugate: conjugate a Spanish verb.
//
// verb:   Spanish infinitive (e.g. "hablar", "ser", "tener")
// tense:  "present" | "past" | "future" | "imperfect"
//         (note: "past" maps to the preterite/indefinite past)
// person: "first" | "second" | "third"
// number: "singular" | "plural"

fn es_conjugate(verb: String, tense: String, person: String, number: String) -> String {
    let slot: Int = es_slot(person, number)

    if str_eq(tense, "present") {
        let irreg: String = es_irregular_present(verb, person, number)
        if !str_eq(irreg, "") {
            return irreg
        }
        let vclass: String = es_verb_class(verb)
        let stem: String = es_stem(verb)
        return es_regular_present(stem, vclass, slot)
    }

    if str_eq(tense, "past") {
        let irreg: String = es_irregular_preterite(verb, person, number)
        if !str_eq(irreg, "") {
            return irreg
        }
        let vclass: String = es_verb_class(verb)
        let stem: String = es_stem(verb)
        return es_regular_preterite(stem, vclass, slot)
    }

    if str_eq(tense, "future") {
        let irreg_stem: String = es_irregular_future_stem(verb)
        if !str_eq(irreg_stem, "") {
            return es_regular_future(irreg_stem, slot)
        }
        return es_regular_future(verb, slot)
    }

    if str_eq(tense, "imperfect") {
        let irreg: String = es_irregular_imperfect(verb, person, number)
        if !str_eq(irreg, "") {
            return irreg
        }
        let vclass: String = es_verb_class(verb)
        let stem: String = es_stem(verb)
        return es_regular_imperfect(stem, vclass, slot)
    }

    // Unknown tense: return infinitive unchanged
    return verb
}

// ── Noun gender inference ─────────────────────────────────────────────────────
//
// Returns "m" (masculine), "f" (feminine), or "unknown".
//
// Heuristics (not exhaustive — cover most common patterns):
//   ends in -o        -> masculine (libro, gato, niño)
//   ends in -a        -> feminine  (casa, mesa, niña)
//   ends in -ión      -> feminine  (canción, nación)
//   ends in -dad/-tad -> feminine  (ciudad, libertad)
//   ends in -umbre    -> feminine  (costumbre)
//   ends in -sis      -> feminine  (crisis, tesis)
//   ends in -ema/-ama -> masculine (problema, programa, tema, idioma)
//   ends in -or       -> masculine (color, amor, señor)
//   ends in -aje      -> masculine (viaje, paisaje)
//   ends in -án/-ón   -> masculine (avión → check -ión first)
//   otherwise         -> unknown

fn es_gender(noun: String) -> String {
    // -ión before -o so "avión" → feminine (it ends -ión, not just -on)
    if es_str_ends(noun, "ión")    { return "f" }
    if es_str_ends(noun, "dad")    { return "f" }
    if es_str_ends(noun, "tad")    { return "f" }
    if es_str_ends(noun, "umbre")  { return "f" }
    if es_str_ends(noun, "sis")    { return "f" }
    if es_str_ends(noun, "ema")    { return "m" }
    if es_str_ends(noun, "ama")    { return "m" }
    if es_str_ends(noun, "aje")    { return "m" }
    if es_str_ends(noun, "or")     { return "m" }
    if es_str_ends(noun, "o")      { return "m" }
    if es_str_ends(noun, "a")      { return "f" }
    return "unknown"
}

// ── Noun pluralization ────────────────────────────────────────────────────────
//
// Rules (applied in order):
//   ends in vowel (a e i o u) -> add -s
//   ends in consonant          -> add -es
//   ends in -z                 -> replace -z with -ces
//   ends in -s (unstressed)    -> unchanged (e.g. "el lunes" -> "los lunes")
//
// Note: nouns ending in stressed vowel + s (e.g. "el autobús" → "los autobuses")
// are handled by the consonant rule since -s is a consonant ending for pluralization
// purposes; but "el lunes" (days of week ending in -s) stay unchanged — this is
// an irregular class.  The table below handles common invariant nouns.

fn es_invariant_plural(noun: String) -> String {
    if str_eq(noun, "lunes")     { return "lunes" }
    if str_eq(noun, "martes")    { return "martes" }
    if str_eq(noun, "miércoles") { return "miércoles" }
    if str_eq(noun, "jueves")    { return "jueves" }
    if str_eq(noun, "viernes")   { return "viernes" }
    if str_eq(noun, "crisis")    { return "crisis" }
    if str_eq(noun, "tesis")     { return "tesis" }
    if str_eq(noun, "análisis")  { return "análisis" }
    if str_eq(noun, "dosis")     { return "dosis" }
    if str_eq(noun, "virus")     { return "virus" }
    return ""
}

fn es_pluralize(noun: String) -> String {
    let inv: String = es_invariant_plural(noun)
    if !str_eq(inv, "") {
        return inv
    }
    let last: String = es_str_last_char(noun)
    // Ends in -z: replace with -ces
    if str_eq(last, "z") {
        return es_str_drop_last(noun, 1) + "ces"
    }
    // Ends in a vowel: add -s
    if str_eq(last, "a") { return noun + "s" }
    if str_eq(last, "e") { return noun + "s" }
    if str_eq(last, "i") { return noun + "s" }
    if str_eq(last, "o") { return noun + "s" }
    if str_eq(last, "u") { return noun + "s" }
    // Ends in consonant (including -s for stressed words like autobús): add -es
    return noun + "es"
}

// ── Article agreement ─────────────────────────────────────────────────────────
//
// es_agree_article: return the correct Spanish article for a noun.
//
// noun:     the noun (used for gender and number inference)
// definite: "true" for definite (el/la/los/las), "false" for indefinite (un/una/unos/unas)
// number:   "singular" | "plural"
//
// Special case: feminine nouns beginning with stressed "a-" or "ha-" take
// masculine singular definite article: "el agua", "el hacha".
// This is handled by checking the noun's first character when gender is feminine.

fn es_starts_with_stressed_a(noun: String) -> Bool {
    // Approximate: check if noun starts with "a" or "ha" (covers most cases)
    // The accent on the first syllable is not detectable orthographically in
    // general, so we apply the rule broadly for any feminine noun starting with
    // "a" or "ha" in singular.
    let n: Int = str_len(noun)
    if n == 0 {
        return false
    }
    let c0: String = str_slice(noun, 0, 1)
    if str_eq(c0, "a") { return true }
    if n >= 2 {
        let c1: String = str_slice(noun, 1, 2)
        if str_eq(c0, "h") {
            if str_eq(c1, "a") { return true }
        }
    }
    return false
}

fn es_agree_article(noun: String, definite: String, number: String) -> String {
    let gender: String = es_gender(noun)
    let is_plural: Bool = str_eq(number, "plural")
    let is_def: Bool = str_eq(definite, "true")

    if is_def {
        if is_plural {
            if str_eq(gender, "f") { return "las" }
            return "los"
        }
        // singular
        if str_eq(gender, "f") {
            // el agua rule: feminine singular nouns starting with stressed "a"
            if es_starts_with_stressed_a(noun) { return "el" }
            return "la"
        }
        return "el"
    }

    // indefinite
    if is_plural {
        if str_eq(gender, "f") { return "unas" }
        return "unos"
    }
    if str_eq(gender, "f") { return "una" }
    return "un"
}
