// realizer.el - Universal syntactic realizer: GramSpec -> surface text.
//
// The realizer is now language-agnostic.  It reads the "lang" field from the
// GramSpec to resolve a language profile, then dispatches word order, question
// formation, and morphology through the engine functions in grammar.el and
// morphology.el.
//
// English remains the default (backward compatible) when no "lang" key is set.
//
// Realization pipeline per call:
//   1. Extract lang code -> resolve profile
//   2. Extract agent, predicate, patient, location, tense, aspect, intent
//   3. Compute person/number from agent (English heuristic; other languages TBD)
//   4. Build VP: morph_conjugate with profile -> get verb and auxiliary surface
//   5. Choose question strategy from gram_question_strategy(profile)
//   6. Order constituents via gram_order_constituents(subj, verb, obj, profile)
//   7. Capitalize and terminate
//
// Depends on: morphology (morph_conjugate, agree_determiner)
//             grammar (gram_order_constituents, gram_question_strategy,
//                     gram_build_vp, build_np, build_pp, slots_get)
//             language-profile (lang_from_code, lang_get, ...)
import "language-profile.el"
import "grammar.el"

// ── Agent agreement analysis ──────────────────────────────────────────────────
//
// Person and number are inferred from English pronouns.  For other languages
// the grammatical person/number should come from the Engram vocabulary node
// for the subject; here we use a heuristic that is correct for English and
// passable for languages where the same pronoun strings are used.

fn agent_person(agent: String) -> String {
    if str_eq(agent, "I")   { return "first" }
    if str_eq(agent, "me")  { return "first" }
    if str_eq(agent, "we")  { return "first" }
    if str_eq(agent, "us")  { return "first" }
    if str_eq(agent, "you") { return "second" }
    return "third"
}

fn agent_number(agent: String) -> String {
    if str_eq(agent, "I")    { return "singular" }
    if str_eq(agent, "me")   { return "singular" }
    if str_eq(agent, "he")   { return "singular" }
    if str_eq(agent, "him")  { return "singular" }
    if str_eq(agent, "she")  { return "singular" }
    if str_eq(agent, "her")  { return "singular" }
    if str_eq(agent, "it")   { return "singular" }
    if str_eq(agent, "you")  { return "singular" }
    if str_eq(agent, "we")   { return "plural" }
    if str_eq(agent, "us")   { return "plural" }
    if str_eq(agent, "they") { return "plural" }
    if str_eq(agent, "them") { return "plural" }
    return "singular"
}

// ── NP realization ────────────────────────────────────────────────────────────

fn realize_np(referent: String, number: String) -> String {
    return referent
}

// ── VP realization ────────────────────────────────────────────────────────────
//
// Returns [main_verb_surface, aux_surface_or_empty].
// Delegates conjugation to morph_conjugate with the language profile.

fn realize_vp_lang(base_verb: String, tense: String, aspect: String, person: String, number: String, profile: [String]) -> [String] {
    let empty_aux: String = ""

    if str_eq(tense, "future") {
        // Future: modal "will" + base (English) or language-specific future marker.
        // For isolating/agglutinative languages the future marker is also the
        // base form (morph_conjugate returns base); the surface "will" only appears
        // for English because morph_conjugate("be", "future", ..., en_profile) = "will be".
        let code: String = lang_get(profile, "code")
        if str_eq(code, "en") {
            let result: [String] = native_list_empty()
            let result = native_list_append(result, base_verb)
            let result = native_list_append(result, "will")
            return result
        }
        // Other languages: conjugate normally (engine returns base form for
        // languages without loaded Engram suffix data).
        let surf: String = morph_conjugate(base_verb, tense, person, number, profile)
        let result: [String] = native_list_empty()
        let result = native_list_append(result, surf)
        let result = native_list_append(result, empty_aux)
        return result
    }

    if str_eq(aspect, "progressive") {
        let gerund: String  = morph_conjugate(base_verb, "progressive", person, number, profile)
        let be_aux: String  = morph_conjugate("be", tense, person, number, profile)
        let result: [String] = native_list_empty()
        let result = native_list_append(result, gerund)
        let result = native_list_append(result, be_aux)
        return result
    }

    if str_eq(aspect, "perfect") {
        let pp: String         = morph_conjugate(base_verb, "perfect", person, number, profile)
        let have_form: String  = morph_conjugate("have", tense, person, number, profile)
        let result: [String]   = native_list_empty()
        let result = native_list_append(result, pp)
        let result = native_list_append(result, have_form)
        return result
    }

    let surf: String = morph_conjugate(base_verb, tense, person, number, profile)
    let result: [String] = native_list_empty()
    let result = native_list_append(result, surf)
    let result = native_list_append(result, empty_aux)
    return result
}

// ── Question formation ────────────────────────────────────────────────────────
//
// Strategy is resolved from gram_question_strategy(profile):
//
//   "do-support"  (en)  - insert conjugated "do" before subject; verb stays base.
//   "particle"    (ja, hi, fi) - statement order + sentence-final question particle.
//   "intonation"  (zh, es, ar, ru, sw) - statement order + "?" punctuation only.
//   "inversion"   (fr, de) - subject-verb inversion.

// realize_question_lang: build the question surface string for any language.
// Returns the complete surface string (without final punctuation).

fn realize_question_lang(predicate: String, tense: String, aspect: String, person: String, number: String, agent: String, patient: String, location: String, profile: [String]) -> String {
    let strategy: String = gram_question_strategy(profile)
    let code: String = lang_get(profile, "code")

    // ── do-support (English) ──────────────────────────────────────────────────
    if str_eq(strategy, "do-support") {
        if str_eq(aspect, "progressive") {
            let vp_pair: [String] = realize_vp_lang(predicate, tense, "progressive", person, number, profile)
            let gerund: String   = native_list_get(vp_pair, 0)
            let be_aux: String   = native_list_get(vp_pair, 1)
            let parts: [String] = native_list_empty()
            let parts = native_list_append(parts, be_aux)
            let parts = native_list_append(parts, agent)
            let parts = native_list_append(parts, gerund)
            if !str_eq(patient, "")  { let parts = native_list_append(parts, patient)  }
            if !str_eq(location, "") { let parts = native_list_append(parts, location) }
            return str_join(parts, " ")
        }

        if str_eq(aspect, "perfect") {
            let vp_pair: [String] = realize_vp_lang(predicate, tense, "perfect", person, number, profile)
            let pp: String        = native_list_get(vp_pair, 0)
            let have_aux: String  = native_list_get(vp_pair, 1)
            let parts: [String]  = native_list_empty()
            let parts = native_list_append(parts, have_aux)
            let parts = native_list_append(parts, agent)
            let parts = native_list_append(parts, pp)
            if !str_eq(patient, "")  { let parts = native_list_append(parts, patient)  }
            if !str_eq(location, "") { let parts = native_list_append(parts, location) }
            return str_join(parts, " ")
        }

        // Simple: do-support
        if str_eq(predicate, "be") {
            let be_form: String = morph_conjugate("be", tense, person, number, profile)
            let parts: [String] = native_list_empty()
            let parts = native_list_append(parts, be_form)
            let parts = native_list_append(parts, agent)
            if !str_eq(patient, "")  { let parts = native_list_append(parts, patient)  }
            if !str_eq(location, "") { let parts = native_list_append(parts, location) }
            return str_join(parts, " ")
        }
        let do_form: String = morph_conjugate("do", tense, person, number, profile)
        let parts: [String] = native_list_empty()
        let parts = native_list_append(parts, do_form)
        let parts = native_list_append(parts, agent)
        let parts = native_list_append(parts, predicate)
        if !str_eq(patient, "")  { let parts = native_list_append(parts, patient)  }
        if !str_eq(location, "") { let parts = native_list_append(parts, location) }
        return str_join(parts, " ")
    }

    // ── particle (ja, hi, fi) ─────────────────────────────────────────────────
    // Build in statement order, then append the question particle.
    if str_eq(strategy, "particle") {
        let vp_pair: [String] = realize_vp_lang(predicate, tense, aspect, person, number, profile)
        let verb_s: String = native_list_get(vp_pair, 0)
        let aux_s: String  = native_list_get(vp_pair, 1)
        let vp_str: String = gram_build_vp(verb_s, aux_s, profile)
        let core: String   = gram_order_constituents(agent, vp_str, patient, profile)
        let loc_part: String = ""
        if !str_eq(location, "") {
            let loc_part = core + " " + location
        } else {
            let loc_part = core
        }
        // Language-specific question particles
        if str_eq(code, "ja") { return loc_part + " か" }
        if str_eq(code, "hi") { return loc_part + " क्या" }
        if str_eq(code, "fi") { return loc_part + "-ko" }
        return loc_part + "?"
    }

    // ── inversion (fr, de) ────────────────────────────────────────────────────
    if str_eq(strategy, "inversion") {
        let vp_pair: [String] = realize_vp_lang(predicate, tense, aspect, person, number, profile)
        let verb_s: String = native_list_get(vp_pair, 0)
        let aux_s: String  = native_list_get(vp_pair, 1)
        // Inversion: Verb-Subject-Object order
        let parts: [String] = native_list_empty()
        if !str_eq(aux_s, "") {
            let parts = native_list_append(parts, aux_s)
        } else {
            let parts = native_list_append(parts, verb_s)
        }
        let parts = native_list_append(parts, agent)
        if !str_eq(aux_s, "") {
            let parts = native_list_append(parts, verb_s)
        }
        if !str_eq(patient,  "") { let parts = native_list_append(parts, patient)  }
        if !str_eq(location, "") { let parts = native_list_append(parts, location) }
        return str_join(parts, " ")
    }

    // ── intonation (zh, es, ar, ru, sw) — statement order, "?" added by caller ─
    let vp_pair: [String] = realize_vp_lang(predicate, tense, aspect, person, number, profile)
    let verb_s: String = native_list_get(vp_pair, 0)
    let aux_s: String  = native_list_get(vp_pair, 1)
    let vp_str: String = gram_build_vp(verb_s, aux_s, profile)
    let core: String   = gram_order_constituents(agent, vp_str, patient, profile)
    if !str_eq(location, "") {
        return core + " " + location
    }
    return core
}

// ── Capitalization and punctuation ────────────────────────────────────────────

fn capitalize_first(s: String) -> String {
    let n: Int = str_len(s)
    if n == 0 {
        return s
    }
    let first: String = str_slice(s, 0, 1)
    let rest: String  = str_slice(s, 1, n)
    return str_to_upper(first) + rest
}

fn add_punct(s: String, intent: String) -> String {
    if str_eq(intent, "question") { return s + "?" }
    return s + "."
}

// ── Main realization entry point ──────────────────────────────────────────────

fn realize_lang(form: [String], profile: [String]) -> String {
    let intent: String    = slots_get(form, "intent")
    let agent: String     = slots_get(form, "agent")
    let predicate: String = slots_get(form, "predicate")
    let patient: String   = slots_get(form, "patient")
    let location: String  = slots_get(form, "location")
    let tense_raw: String = slots_get(form, "tense")
    let aspect_raw: String= slots_get(form, "aspect")

    let tense: String  = tense_raw
    if str_eq(tense, "") { let tense = "present" }
    let aspect: String = aspect_raw
    if str_eq(aspect, "") { let aspect = "simple" }

    let person: String = agent_person(agent)
    let number: String = agent_number(agent)

    // ── Command (imperative) ──────────────────────────────────────────────────
    if str_eq(intent, "command") {
        let parts: [String] = native_list_empty()
        let parts = native_list_append(parts, predicate)
        if !str_eq(patient,  "") { let parts = native_list_append(parts, patient)  }
        if !str_eq(location, "") { let parts = native_list_append(parts, location) }
        let sentence: String = str_join(parts, " ")
        return add_punct(capitalize_first(sentence), "command")
    }

    // ── Question ──────────────────────────────────────────────────────────────
    if str_eq(intent, "question") {
        let surface: String = realize_question_lang(predicate, tense, aspect, person, number, agent, patient, location, profile)
        return add_punct(capitalize_first(surface), "question")
    }

    // ── Assertion (declarative) ───────────────────────────────────────────────
    let vp_pair: [String] = realize_vp_lang(predicate, tense, aspect, person, number, profile)
    let verb_surf: String = native_list_get(vp_pair, 0)
    let aux_surf: String  = native_list_get(vp_pair, 1)

    let vp_str: String = gram_build_vp(verb_surf, aux_surf, profile)
    let core: String   = gram_order_constituents(agent, vp_str, patient, profile)

    let parts: [String] = native_list_empty()
    let parts = native_list_append(parts, core)
    if !str_eq(location, "") {
        let parts = native_list_append(parts, location)
    }
    let sentence: String = str_join(parts, " ")
    return add_punct(capitalize_first(sentence), "assert")
}

// realize: backward-compatible English entry point (original signature).
fn realize(form: [String]) -> String {
    let lang_code: String = slots_get(form, "lang")
    if str_eq(lang_code, "") {
        return realize_lang(form, lang_default())
    }
    return realize_lang(form, lang_from_code(lang_code))
}
