// semantics.el - Semantic layer: SemFrame -> GramSpec (slot map for realizer).
//
// Bridges from intent/meaning representation to the grammar layer.
// A SemFrame is a slot map ([String] key-value list) with these keys:
//
//   "intent"    - "assert" | "query" | "describe" | "greet"
//   "subject"   - subject referent (pronoun or noun phrase)
//   "object"    - object referent (optional, "" if absent)
//   "modifiers" - semicolon-separated modifier strings (e.g. "in the park;quickly")
//   "lang"      - ISO 639-1 language code (optional, defaults to "en")
//
// sem_to_spec converts a SemFrame into a realizer slot map ready for realize().
// sem_realize is the end-to-end shortcut: frame -> realized text.
//
// All existing function signatures are preserved; new *_lang variants add an
// explicit lang_code parameter.
//
// Depends on: grammar (slots_*, realize), language-profile (lang_from_code)

// ── SemFrame constructors ─────────────────────────────────────────────────────

// Build a SemFrame with all four core fields.  Language defaults to "en".
fn sem_frame(intent: String, subject: String, obj: String, modifiers: String) -> [String] {
    let r: [String] = native_list_empty()
    let r = native_list_append(r, "intent")
    let r = native_list_append(r, intent)
    let r = native_list_append(r, "subject")
    let r = native_list_append(r, subject)
    let r = native_list_append(r, "object")
    let r = native_list_append(r, obj)
    let r = native_list_append(r, "modifiers")
    let r = native_list_append(r, modifiers)
    let r = native_list_append(r, "lang")
    let r = native_list_append(r, "en")
    return r
}

// Build a SemFrame with an explicit language code.
fn sem_frame_lang(intent: String, subject: String, obj: String, modifiers: String, lang_code: String) -> [String] {
    let r: [String] = native_list_empty()
    let r = native_list_append(r, "intent")
    let r = native_list_append(r, intent)
    let r = native_list_append(r, "subject")
    let r = native_list_append(r, subject)
    let r = native_list_append(r, "object")
    let r = native_list_append(r, obj)
    let r = native_list_append(r, "modifiers")
    let r = native_list_append(r, modifiers)
    let r = native_list_append(r, "lang")
    let r = native_list_append(r, lang_code)
    return r
}

// Convenience: no object, no modifiers, English.
fn sem_frame_simple(intent: String, subject: String) -> [String] {
    return sem_frame(intent, subject, "", "")
}

// Convenience: with object, no modifiers, English.
fn sem_frame_obj(intent: String, subject: String, obj: String) -> [String] {
    return sem_frame(intent, subject, obj, "")
}

// ── SemFrame field accessors ──────────────────────────────────────────────────

fn sem_intent(frame: [String]) -> String {
    return slots_get(frame, "intent")
}

fn sem_subject(frame: [String]) -> String {
    return slots_get(frame, "subject")
}

fn sem_object(frame: [String]) -> String {
    return slots_get(frame, "object")
}

fn sem_modifiers(frame: [String]) -> String {
    return slots_get(frame, "modifiers")
}

fn sem_lang(frame: [String]) -> String {
    let code: String = slots_get(frame, "lang")
    if str_eq(code, "") {
        return "en"
    }
    return code
}

// ── Modifier helpers ──────────────────────────────────────────────────────────

fn sem_first_modifier(mods: String) -> String {
    let n: Int = str_len(mods)
    if n == 0 {
        return ""
    }
    let i: Int = 0
    let running: Bool = true
    while running {
        if i >= n {
            let running = false
        } else {
            let c: String = str_slice(mods, i, i + 1)
            if str_eq(c, ";") {
                let running = false
            } else {
                let i = i + 1
            }
        }
    }
    return str_slice(mods, 0, i)
}

// ── Intent mapping ────────────────────────────────────────────────────────────

fn sem_intent_to_realize(intent: String) -> String {
    if str_eq(intent, "assert")   { return "assert" }
    if str_eq(intent, "query")    { return "question" }
    if str_eq(intent, "describe") { return "assert" }
    if str_eq(intent, "greet")    { return "greet" }
    return "assert"
}

// ── sem_to_spec: SemFrame -> realizer slot map ────────────────────────────────
//
// The "lang" key from the SemFrame is forwarded into the GramSpec so that
// realize() can resolve the correct language profile.

fn sem_to_spec(frame: [String]) -> [String] {
    let intent: String   = sem_intent(frame)
    let subject: String  = sem_subject(frame)
    let obj: String      = sem_object(frame)
    let mods: String     = sem_modifiers(frame)
    let lang_code: String = sem_lang(frame)
    let location: String = sem_first_modifier(mods)

    if str_eq(intent, "greet") {
        let spec: [String] = native_list_empty()
        let spec = native_list_append(spec, "intent")
        let spec = native_list_append(spec, "greet")
        let spec = native_list_append(spec, "agent")
        let spec = native_list_append(spec, subject)
        let spec = native_list_append(spec, "predicate")
        let spec = native_list_append(spec, "")
        let spec = native_list_append(spec, "patient")
        let spec = native_list_append(spec, "")
        let spec = native_list_append(spec, "location")
        let spec = native_list_append(spec, "")
        let spec = native_list_append(spec, "tense")
        let spec = native_list_append(spec, "present")
        let spec = native_list_append(spec, "aspect")
        let spec = native_list_append(spec, "simple")
        let spec = native_list_append(spec, "lang")
        let spec = native_list_append(spec, lang_code)
        return spec
    }

    if str_eq(intent, "describe") {
        let spec: [String] = native_list_empty()
        let spec = native_list_append(spec, "intent")
        let spec = native_list_append(spec, "assert")
        let spec = native_list_append(spec, "agent")
        let spec = native_list_append(spec, subject)
        let spec = native_list_append(spec, "predicate")
        let spec = native_list_append(spec, "be")
        let spec = native_list_append(spec, "patient")
        let spec = native_list_append(spec, obj)
        let spec = native_list_append(spec, "location")
        let spec = native_list_append(spec, location)
        let spec = native_list_append(spec, "tense")
        let spec = native_list_append(spec, "present")
        let spec = native_list_append(spec, "aspect")
        let spec = native_list_append(spec, "simple")
        let spec = native_list_append(spec, "lang")
        let spec = native_list_append(spec, lang_code)
        return spec
    }

    let realize_intent: String = sem_intent_to_realize(intent)
    let spec: [String] = native_list_empty()
    let spec = native_list_append(spec, "intent")
    let spec = native_list_append(spec, realize_intent)
    let spec = native_list_append(spec, "agent")
    let spec = native_list_append(spec, subject)
    let spec = native_list_append(spec, "predicate")
    let spec = native_list_append(spec, obj)
    let spec = native_list_append(spec, "patient")
    let spec = native_list_append(spec, "")
    let spec = native_list_append(spec, "location")
    let spec = native_list_append(spec, location)
    let spec = native_list_append(spec, "tense")
    let spec = native_list_append(spec, "present")
    let spec = native_list_append(spec, "aspect")
    let spec = native_list_append(spec, "simple")
    let spec = native_list_append(spec, "lang")
    let spec = native_list_append(spec, lang_code)
    return spec
}

// ── sem_to_spec_full ──────────────────────────────────────────────────────────

fn sem_to_spec_full(frame: [String], verb: String, tense: String, aspect: String) -> [String] {
    let intent: String    = sem_intent(frame)
    let subject: String   = sem_subject(frame)
    let obj: String       = sem_object(frame)
    let mods: String      = sem_modifiers(frame)
    let lang_code: String = sem_lang(frame)
    let location: String  = sem_first_modifier(mods)

    if str_eq(intent, "greet") {
        return sem_to_spec(frame)
    }

    if str_eq(intent, "describe") {
        let spec: [String] = native_list_empty()
        let spec = native_list_append(spec, "intent")
        let spec = native_list_append(spec, "assert")
        let spec = native_list_append(spec, "agent")
        let spec = native_list_append(spec, subject)
        let spec = native_list_append(spec, "predicate")
        let spec = native_list_append(spec, "be")
        let spec = native_list_append(spec, "patient")
        let spec = native_list_append(spec, obj)
        let spec = native_list_append(spec, "location")
        let spec = native_list_append(spec, location)
        let spec = native_list_append(spec, "tense")
        let spec = native_list_append(spec, tense)
        let spec = native_list_append(spec, "aspect")
        let spec = native_list_append(spec, aspect)
        let spec = native_list_append(spec, "lang")
        let spec = native_list_append(spec, lang_code)
        return spec
    }

    let realize_intent: String = sem_intent_to_realize(intent)
    let spec: [String] = native_list_empty()
    let spec = native_list_append(spec, "intent")
    let spec = native_list_append(spec, realize_intent)
    let spec = native_list_append(spec, "agent")
    let spec = native_list_append(spec, subject)
    let spec = native_list_append(spec, "predicate")
    let spec = native_list_append(spec, verb)
    let spec = native_list_append(spec, "patient")
    let spec = native_list_append(spec, obj)
    let spec = native_list_append(spec, "location")
    let spec = native_list_append(spec, location)
    let spec = native_list_append(spec, "tense")
    let spec = native_list_append(spec, tense)
    let spec = native_list_append(spec, "aspect")
    let spec = native_list_append(spec, aspect)
    let spec = native_list_append(spec, "lang")
    let spec = native_list_append(spec, lang_code)
    return spec
}

// ── Greet realization helper ──────────────────────────────────────────────────

fn sem_realize_greet(subject: String) -> String {
    if str_eq(subject, "") {
        return "Hello."
    }
    return "Hello, " + subject + "."
}

// ── sem_realize: SemFrame -> text ─────────────────────────────────────────────

fn sem_realize(frame: [String]) -> String {
    let intent: String = sem_intent(frame)

    if str_eq(intent, "greet") {
        return sem_realize_greet(sem_subject(frame))
    }

    let spec: [String] = sem_to_spec(frame)
    return realize(spec)
}

// ── sem_realize_full ──────────────────────────────────────────────────────────

fn sem_realize_full(frame: [String], verb: String, tense: String, aspect: String) -> String {
    let intent: String = sem_intent(frame)

    if str_eq(intent, "greet") {
        return sem_realize_greet(sem_subject(frame))
    }

    let spec: [String] = sem_to_spec_full(frame, verb, tense, aspect)
    return realize(spec)
}

// ── sem_realize_lang: realize in an explicitly specified language ──────────────
//
// Convenience for callers that want to specify the output language without
// constructing a full SemFrame.  The lang_code overrides whatever "lang" is
// set in the frame.

fn sem_realize_lang(frame: [String], lang_code: String) -> String {
    let intent: String = sem_intent(frame)

    if str_eq(intent, "greet") {
        return sem_realize_greet(sem_subject(frame))
    }

    // Inject the lang_code into the frame before converting to spec.
    let patched: [String] = slots_set(frame, "lang", lang_code)
    let spec: [String] = sem_to_spec(patched)
    return realize(spec)
}
