//! JSON Lines sink — one structured row per line, constant memory.
//!
//! Suited for piping into `jq`, importing into pandas / DuckDB's
//! `read_json_auto`, or feeding downstream tooling that expects a
//! line-delimited stream rather than a single megaobject.

use std::io::{self, Write};

use serde::Serialize;

use crate::disasm::RichDisasmItem;

#[derive(Serialize)]
struct JsonRow<'a> {
    addr: u32,
    raw: u32,
    mnemonic: &'a str,
    operands: &'a str,
    disasm: &'a str,
    #[serde(skip_serializing_if = "Option::is_none")]
    ext_mnemonic: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")]
    ext_operands: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")]
    ext_disasm: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")]
    branch_target: Option<u32>,
    section: &'a str,
    #[serde(skip_serializing_if = "Option::is_none")]
    function: Option<u32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    label: Option<&'a str>,
}

/// Write each item as a single JSON object on its own line. Returns the
/// number of rows written.
pub fn write_jsonl<'a, W: Write>(
    out: &mut W,
    items: impl IntoIterator<Item = RichDisasmItem<'a>>,
) -> io::Result<u64> {
    let mut count: u64 = 0;
    for ri in items {
        let t = &ri.item.text;
        let row = JsonRow {
            addr: ri.item.addr,
            raw: ri.item.raw,
            mnemonic: &t.mnemonic,
            operands: &t.operands,
            disasm: &t.disasm,
            ext_mnemonic: t.ext_mnemonic.as_deref(),
            ext_operands: t.ext_operands.as_deref(),
            ext_disasm: t.ext_disasm.as_deref(),
            branch_target: t.branch_target,
            section: ri.section,
            function: ri.function,
            label: ri.label,
        };
        serde_json::to_writer(&mut *out, &row)?;
        out.write_all(b"\n")?;
        count += 1;
    }
    Ok(count)
}
