// morphology-non.el - Old Norse morphology for the NLG engine.
//
// Implements Old Norse verb conjugation and noun declension for the ca. 700-1100 CE
// period.  Designed as a companion to morphology.el and called by the engine when
// the language profile code is "non".
//
// Language profile: code=non, name=Old Norse, morph_type=fusional, word_order=V2,
//   question_strategy=inversion, script=latin, family=germanic.
//
// Verb conjugation covered:
//   Tenses:   present, past
//   Persons:  first/second/third x singular/plural (slots 0-5)
//   Classes:  weak (-a infinitive: -aði past), and a set of common strong/irregular verbs
//   Irregulars: vera (be), hafa (have), ganga (go), sjá (see), segja (say),
//               koma (come)
//   Canonical map: "be" -> "vera"
//
// Noun declension covered:
//   Strong masculine a-stem (like "armr")
//   Strong feminine ō-stem  (like "gör")
//   Strong neuter a-stem    (like "land")
//   Cases: nominative, accusative, genitive, dative
//   Numbers: singular, plural
//   Definite suffix: appended to the declined form (masc -inn/-ins/-inum, neut -it)
//
// Depends on: morphology.el (str_ends_with, str_len, str_slice, str_eq)

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

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

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

fn non_last(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   (ek)
//   1 = 2nd singular   (þú)
//   2 = 3rd singular   (hann/hon/þat)
//   3 = 1st plural     (vér)
//   4 = 2nd plural     (þér)
//   5 = 3rd plural     (þeir/þær/þau)

fn non_slot(person: String, number: String) -> Int {
    if str_eq(person, "first") {
        if str_eq(number, "singular") { return 0 }
        return 3
    }
    if str_eq(person, "second") {
        if str_eq(number, "singular") { return 1 }
        return 4
    }
    // third
    if str_eq(number, "singular") { return 2 }
    return 5
}

// ── Irregular verb tables ──────────────────────────────────────────────────────
//
// Each irregular verb has a present and past paradigm of six forms (slots 0-5).

fn non_vera_present(slot: Int) -> String {
    if slot == 0 { return "em" }
    if slot == 1 { return "ert" }
    if slot == 2 { return "er" }
    if slot == 3 { return "erum" }
    if slot == 4 { return "eruð" }
    return "eru"
}

fn non_vera_past(slot: Int) -> String {
    if slot == 0 { return "var" }
    if slot == 1 { return "vart" }
    if slot == 2 { return "var" }
    if slot == 3 { return "vórum" }
    if slot == 4 { return "vóruð" }
    return "vóru"
}

fn non_hafa_present(slot: Int) -> String {
    if slot == 0 { return "hefi" }
    if slot == 1 { return "hefr" }
    if slot == 2 { return "hefr" }
    if slot == 3 { return "höfum" }
    if slot == 4 { return "hafið" }
    return "hafa"
}

fn non_hafa_past(slot: Int) -> String {
    if slot == 0 { return "hafða" }
    if slot == 1 { return "hafðir" }
    if slot == 2 { return "hafði" }
    if slot == 3 { return "höfðum" }
    if slot == 4 { return "höfðuð" }
    return "höfðu"
}

fn non_ganga_present(slot: Int) -> String {
    if slot == 0 { return "geng" }
    if slot == 1 { return "gengr" }
    if slot == 2 { return "gengr" }
    if slot == 3 { return "göngum" }
    if slot == 4 { return "gangið" }
    return "ganga"
}

fn non_ganga_past(slot: Int) -> String {
    if slot == 0 { return "gekk" }
    if slot == 1 { return "gekkt" }
    if slot == 2 { return "gekk" }
    if slot == 3 { return "gengum" }
    if slot == 4 { return "genguð" }
    return "gengu"
}

fn non_sja_present(slot: Int) -> String {
    if slot == 0 { return "sé" }
    if slot == 1 { return "sér" }
    if slot == 2 { return "sér" }
    if slot == 3 { return "séum" }
    if slot == 4 { return "séið" }
    return "sjá"
}

fn non_sja_past(slot: Int) -> String {
    if slot == 0 { return "sá" }
    if slot == 1 { return "sást" }
    if slot == 2 { return "sá" }
    if slot == 3 { return "sám" }
    if slot == 4 { return "sáð" }
    return "sáu"
}

fn non_segja_present(slot: Int) -> String {
    if slot == 0 { return "segi" }
    if slot == 1 { return "segir" }
    if slot == 2 { return "segir" }
    if slot == 3 { return "segjum" }
    if slot == 4 { return "segið" }
    return "segja"
}

fn non_segja_past(slot: Int) -> String {
    if slot == 0 { return "sagði" }
    if slot == 1 { return "sagðir" }
    if slot == 2 { return "sagði" }
    if slot == 3 { return "sögðum" }
    if slot == 4 { return "sögðuð" }
    return "sögðu"
}

fn non_koma_present(slot: Int) -> String {
    if slot == 0 { return "kem" }
    if slot == 1 { return "kemr" }
    if slot == 2 { return "kemr" }
    if slot == 3 { return "komum" }
    if slot == 4 { return "komið" }
    return "koma"
}

fn non_koma_past(slot: Int) -> String {
    if slot == 0 { return "kom" }
    if slot == 1 { return "komt" }
    if slot == 2 { return "kom" }
    if slot == 3 { return "komum" }
    if slot == 4 { return "komuð" }
    return "komu"
}

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

fn non_map_canonical(verb: String) -> String {
    if str_eq(verb, "be")   { return "vera" }
    if str_eq(verb, "have") { return "hafa" }
    if str_eq(verb, "go")   { return "ganga" }
    if str_eq(verb, "see")  { return "sjá" }
    if str_eq(verb, "say")  { return "segja" }
    if str_eq(verb, "come") { return "koma" }
    return verb
}

// ── Weak verb conjugation ──────────────────────────────────────────────────────
//
// Weak verbs (infinitive ending in -a) form the productive conjugation class.
//
// Present tense (stem = drop final -a from infinitive):
//   Sg:  1st stem + -a    2nd stem + -ar   3rd stem + -ar
//   Pl:  1st stem + -um   2nd stem + -ið   3rd stem + -a
//
// Past tense (suffix -aði- inserted after stem):
//   Sg:  1st stem + -aði   2nd stem + -aðir   3rd stem + -aði
//   Pl:  1st stem + -uðum  2nd stem + -uðuð   3rd stem + -uðu

fn non_weak_present(stem: String, slot: Int) -> String {
    if slot == 0 { return stem + "a" }
    if slot == 1 { return stem + "ar" }
    if slot == 2 { return stem + "ar" }
    if slot == 3 { return stem + "um" }
    if slot == 4 { return stem + "ið" }
    return stem + "a"
}

fn non_weak_past(stem: String, slot: Int) -> String {
    if slot == 0 { return stem + "aði" }
    if slot == 1 { return stem + "aðir" }
    if slot == 2 { return stem + "aði" }
    if slot == 3 { return stem + "uðum" }
    if slot == 4 { return stem + "uðuð" }
    return stem + "uðu"
}

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

fn non_conjugate(verb: String, tense: String, person: String, number: String) -> String {
    let v: String = non_map_canonical(verb)
    let slot: Int = non_slot(person, number)

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

    if str_eq(v, "vera") {
        if str_eq(tense, "present") { return non_vera_present(slot) }
        if str_eq(tense, "past")    { return non_vera_past(slot) }
        return v
    }

    if str_eq(v, "hafa") {
        if str_eq(tense, "present") { return non_hafa_present(slot) }
        if str_eq(tense, "past")    { return non_hafa_past(slot) }
        return v
    }

    if str_eq(v, "ganga") {
        if str_eq(tense, "present") { return non_ganga_present(slot) }
        if str_eq(tense, "past")    { return non_ganga_past(slot) }
        return v
    }

    if str_eq(v, "sjá") {
        if str_eq(tense, "present") { return non_sja_present(slot) }
        if str_eq(tense, "past")    { return non_sja_past(slot) }
        return v
    }

    if str_eq(v, "segja") {
        if str_eq(tense, "present") { return non_segja_present(slot) }
        if str_eq(tense, "past")    { return non_segja_past(slot) }
        return v
    }

    if str_eq(v, "koma") {
        if str_eq(tense, "present") { return non_koma_present(slot) }
        if str_eq(tense, "past")    { return non_koma_past(slot) }
        return v
    }

    // ── Regular weak verb (-a infinitive) ────────────────────────────────────
    //
    // If the verb ends in -a, strip it to get the stem and apply weak endings.
    // Otherwise fall back to returning the base form unchanged.

    if non_str_ends(v, "a") {
        let stem: String = non_drop(v, 1)
        if str_eq(tense, "present") { return non_weak_present(stem, slot) }
        if str_eq(tense, "past")    { return non_weak_past(stem, slot) }
        return v
    }

    // Unknown verb form: return the infinitive unchanged
    return v
}

// ── Strong masculine a-stem declension ("armr" — arm) ─────────────────────────
//
// The paradigm below uses "armr" as the exemplar.  The caller passes the full
// nominative singular (including the -r ending); the oblique stem is derived
// by stripping -r (or -ur) from the nominative.
//
// Singular:  nom armr   acc arm    gen arms   dat armi
// Plural:    nom armar  acc arma   gen arma   dat örmum
//
// The dative plural -örmum involves u-umlaut of the root vowel.  Because umlaut
// depends on the root vowel in complex ways, the module stores the dative plural
// stem separately: for "armr" it is "örm".  For unknown nouns we approximatehere
// by returning the nominative plural (armar) rather than crashing.

fn non_decline_masc(noun: String, gram_case: String, number: String) -> String {
    // Derive oblique stem by dropping the nominative -r ending if present.
    let stem: String = noun
    if non_str_ends(noun, "r") {
        let stem = non_drop(noun, 1)
    }

    // Hard-code the known exemplar "armr" fully, including the umlauted dat pl.
    if str_eq(noun, "armr") {
        if str_eq(number, "singular") {
            if str_eq(gram_case, "nominative") { return "armr" }
            if str_eq(gram_case, "accusative") { return "arm" }
            if str_eq(gram_case, "genitive")   { return "arms" }
            if str_eq(gram_case, "dative")     { return "armi" }
            return "armr"
        }
        if str_eq(gram_case, "nominative") { return "armar" }
        if str_eq(gram_case, "accusative") { return "arma" }
        if str_eq(gram_case, "genitive")   { return "arma" }
        if str_eq(gram_case, "dative")     { return "örmum" }
        return "armar"
    }

    // Generic strong masculine a-stem: use stripped stem + endings.
    // Dative plural umlaut is approximated as nominative plural (safe fallback).
    if str_eq(number, "singular") {
        if str_eq(gram_case, "nominative") { return stem + "r" }
        if str_eq(gram_case, "accusative") { return stem }
        if str_eq(gram_case, "genitive")   { return stem + "s" }
        if str_eq(gram_case, "dative")     { return stem + "i" }
        return stem + "r"
    }
    if str_eq(gram_case, "nominative") { return stem + "ar" }
    if str_eq(gram_case, "accusative") { return stem + "a" }
    if str_eq(gram_case, "genitive")   { return stem + "a" }
    if str_eq(gram_case, "dative")     { return stem + "um" }
    return stem + "ar"
}

// ── Strong feminine ō-stem declension ("gör" — gear) ─────────────────────────
//
// ō-stem feminines have a distinct set of endings.  The stem is the nominative
// singular form itself (no case suffix in nom sg for this class, though some
// nouns add -ar in nom/acc pl).
//
// Singular:  nom gör     acc görvar   gen görvar   dat görvi
// Plural:    nom görvar  acc görvar   gen görva    dat görvum

fn non_decline_fem(noun: String, gram_case: String, number: String) -> String {
    // Use "gör" as the fully specified exemplar.
    if str_eq(noun, "gör") {
        if str_eq(number, "singular") {
            if str_eq(gram_case, "nominative") { return "gör" }
            if str_eq(gram_case, "accusative") { return "görvar" }
            if str_eq(gram_case, "genitive")   { return "görvar" }
            if str_eq(gram_case, "dative")     { return "görvi" }
            return "gör"
        }
        if str_eq(gram_case, "nominative") { return "görvar" }
        if str_eq(gram_case, "accusative") { return "görvar" }
        if str_eq(gram_case, "genitive")   { return "görva" }
        if str_eq(gram_case, "dative")     { return "görvum" }
        return "görvar"
    }

    // Generic ō-stem feminine: noun base + endings (approximate).
    if str_eq(number, "singular") {
        if str_eq(gram_case, "nominative") { return noun }
        if str_eq(gram_case, "accusative") { return noun + "var" }
        if str_eq(gram_case, "genitive")   { return noun + "var" }
        if str_eq(gram_case, "dative")     { return noun + "vi" }
        return noun
    }
    if str_eq(gram_case, "nominative") { return noun + "var" }
    if str_eq(gram_case, "accusative") { return noun + "var" }
    if str_eq(gram_case, "genitive")   { return noun + "va" }
    if str_eq(gram_case, "dative")     { return noun + "vum" }
    return noun + "var"
}

// ── Strong neuter a-stem declension ("land" — land) ──────────────────────────
//
// Neuter a-stems show no ending in nom/acc sg and u-umlaut in the dative plural.
//
// Singular:  nom land   acc land   gen lands   dat landi
// Plural:    nom lönd   acc lönd   gen landa   dat löndum

fn non_decline_neut(noun: String, gram_case: String, number: String) -> String {
    if str_eq(noun, "land") {
        if str_eq(number, "singular") {
            if str_eq(gram_case, "nominative") { return "land" }
            if str_eq(gram_case, "accusative") { return "land" }
            if str_eq(gram_case, "genitive")   { return "lands" }
            if str_eq(gram_case, "dative")     { return "landi" }
            return "land"
        }
        if str_eq(gram_case, "nominative") { return "lönd" }
        if str_eq(gram_case, "accusative") { return "lönd" }
        if str_eq(gram_case, "genitive")   { return "landa" }
        if str_eq(gram_case, "dative")     { return "löndum" }
        return "lönd"
    }

    // Generic strong neuter a-stem (no umlaut approximated — falls back to base).
    if str_eq(number, "singular") {
        if str_eq(gram_case, "nominative") { return noun }
        if str_eq(gram_case, "accusative") { return noun }
        if str_eq(gram_case, "genitive")   { return noun + "s" }
        if str_eq(gram_case, "dative")     { return noun + "i" }
        return noun
    }
    if str_eq(gram_case, "nominative") { return noun }
    if str_eq(gram_case, "accusative") { return noun }
    if str_eq(gram_case, "genitive")   { return noun + "a" }
    if str_eq(gram_case, "dative")     { return noun + "um" }
    return noun
}

// ── Gender detection heuristic ─────────────────────────────────────────────────
//
// Old Norse gender must ideally be supplied by the lexicon.  As a heuristic:
//   ends in -r (after removing) and root looks consonant-final -> masculine
//   ends in no case suffix (just the root vowel) -> try feminine
//   monosyllabic root without final r -> neuter
//
// The module uses a simplified approach: known exemplars are routed to their
// specific paradigm; everything else defaults to strong masculine.

fn non_detect_gender(noun: String) -> String {
    if str_eq(noun, "land") { return "neuter" }
    if str_eq(noun, "gör")  { return "feminine" }
    // Default: masculine
    return "masculine"
}

// ── non_decline: main declension entry point ──────────────────────────────────
//
// noun:      nominative singular Old Norse noun (e.g. "armr", "land", "gör")
// gram_case: "nominative" | "accusative" | "genitive" | "dative"
// number:    "singular" | "plural"
//
// Returns the inflected form.  Falls back to nominative singular on unknown input.

fn non_decline(noun: String, gram_case: String, number: String) -> String {
    let gender: String = non_detect_gender(noun)

    if str_eq(gender, "masculine")  { return non_decline_masc(noun, gram_case, number) }
    if str_eq(gender, "feminine")   { return non_decline_fem(noun, gram_case, number) }
    if str_eq(gender, "neuter")     { return non_decline_neut(noun, gram_case, number) }

    // Fallback
    return noun
}

// ── Definite suffix table ──────────────────────────────────────────────────────
//
// Old Norse expresses definiteness via a suffix enclitic attached to the end of
// the inflected noun form (not a separate article).  The suffix agrees with gender
// and case.
//
// Masculine singular: nom -inn  gen -ins  dat -inum  acc -inn
// Neuter singular:    nom -it   gen -ins  dat -inu   acc -it
// Feminine singular:  nom -in   gen -innar dat -inni acc -ina
// Plural (all genders): nom/acc -inir (masc), -in (neut), -inar (fem)
//   — simplified to -in for plural in this module.

fn non_def_suffix_masc(gram_case: String, number: String) -> String {
    if str_eq(number, "singular") {
        if str_eq(gram_case, "nominative") { return "inn" }
        if str_eq(gram_case, "genitive")   { return "ins" }
        if str_eq(gram_case, "dative")     { return "inum" }
        if str_eq(gram_case, "accusative") { return "inn" }
        return "inn"
    }
    // plural
    if str_eq(gram_case, "nominative") { return "inir" }
    if str_eq(gram_case, "accusative") { return "ina" }
    if str_eq(gram_case, "genitive")   { return "anna" }
    if str_eq(gram_case, "dative")     { return "unum" }
    return "inir"
}

fn non_def_suffix_neut(gram_case: String, number: String) -> String {
    if str_eq(number, "singular") {
        if str_eq(gram_case, "nominative") { return "it" }
        if str_eq(gram_case, "genitive")   { return "ins" }
        if str_eq(gram_case, "dative")     { return "inu" }
        if str_eq(gram_case, "accusative") { return "it" }
        return "it"
    }
    // plural
    if str_eq(gram_case, "nominative") { return "in" }
    if str_eq(gram_case, "accusative") { return "in" }
    if str_eq(gram_case, "genitive")   { return "anna" }
    if str_eq(gram_case, "dative")     { return "unum" }
    return "in"
}

fn non_def_suffix_fem(gram_case: String, number: String) -> String {
    if str_eq(number, "singular") {
        if str_eq(gram_case, "nominative") { return "in" }
        if str_eq(gram_case, "genitive")   { return "innar" }
        if str_eq(gram_case, "dative")     { return "inni" }
        if str_eq(gram_case, "accusative") { return "ina" }
        return "in"
    }
    // plural
    if str_eq(gram_case, "nominative") { return "inar" }
    if str_eq(gram_case, "accusative") { return "inar" }
    if str_eq(gram_case, "genitive")   { return "anna" }
    if str_eq(gram_case, "dative")     { return "innar" }
    return "inar"
}

// ── non_noun_phrase: noun phrase builder ──────────────────────────────────────
//
// Old Norse definiteness is expressed through a suffix enclitic, not a separate
// article.  For indefinite nouns the declined form is returned as-is.
//
// noun:      nominative singular Old Norse noun (e.g. "armr", "land")
// gram_case: "nominative" | "accusative" | "genitive" | "dative"
// number:    "singular" | "plural"
// definite:  "true" | "false"  (string comparison)
//
// Returns the complete noun phrase string.

fn non_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String {
    let base: String = non_decline(noun, gram_case, number)

    if !str_eq(definite, "true") { return base }

    // Append the appropriate definite suffix.
    let gender: String = non_detect_gender(noun)

    if str_eq(gender, "masculine") {
        return base + non_def_suffix_masc(gram_case, number)
    }
    if str_eq(gender, "neuter") {
        return base + non_def_suffix_neut(gram_case, number)
    }
    if str_eq(gender, "feminine") {
        return base + non_def_suffix_fem(gram_case, number)
    }

    // Fallback: append generic -inn
    return base + "inn"
}
