// serializer.el — Export graph as SVG string or portable JSON.
//
// Public API:
//   graph_to_svg(graph_json, width, height) -> String
//     graph_json: { "nodes": [...], "edges": [...] }
//     Full pipeline: parse -> layout -> render -> SVG string.
//
//   graph_to_json(nodes_json, edges_json, positions_json) -> String
//     Portable export combining node data with computed positions.
//     Useful for saving layouts to disk or sending to other tools.

// ── graph_to_svg ──────────────────────────────────────────────────────────────
//
// Convenience wrapper: accepts a combined graph JSON object and returns SVG.

fn graph_to_svg(graph_json: String, width: Int, height: Int) -> String {
    let nodes_raw: String = json_get_raw(graph_json, "nodes")
    let edges_raw: String = json_get_raw(graph_json, "edges")
    let nodes_json: String = if str_eq(nodes_raw, "") { "[]" } else { nodes_raw }
    let edges_json: String = if str_eq(edges_raw, "") { "[]" } else { edges_raw }
    graph_svg_endpoint(nodes_json, edges_json, width, height)
}

// ── graph_to_json ─────────────────────────────────────────────────────────────
//
// Merge node metadata with computed positions into a portable export format.
// Output: { "nodes": [{...node fields..., "x": 123.0, "y": 456.0}], "edges": [...] }

fn graph_to_json(nodes_json: String, edges_json: String, positions_json: String) -> String {
    // Index positions by id
    build_position_index(positions_json)

    let node_count: Int = json_array_len(nodes_json)
    let nodes_out: String = "["
    let i: Int = 0
    while i < node_count {
        let n: String = json_array_get(nodes_json, i)
        let id: String = json_get_string(n, "id")
        let x: Float = get_pos_x(id)
        let y: Float = get_pos_y(id)
        // Inject x/y into the node JSON
        let n_with_pos: String = json_set(json_set(n, "x", format_float(x, 1)), "y", format_float(y, 1))
        if i == 0 {
            let nodes_out = nodes_out + n_with_pos
        } else {
            let nodes_out = nodes_out + "," + n_with_pos
        }
        let i = i + 1
    }
    let nodes_out = nodes_out + "]"

    "{\"nodes\":" + nodes_out + ",\"edges\":" + edges_json + "}"
}

// ── graph_snapshot_svg ────────────────────────────────────────────────────────
//
// Render a snapshot of the current in-process Engram graph as SVG.
// Uses engram_scan_nodes_json and reads edges from the snapshot file.
// This is the function called by the CGI Studio /api/graph/svg endpoint.

fn graph_snapshot_svg(width: Int, height: Int, snap_path: String) -> String {
    let nodes_json: String = engram_scan_nodes_json(9999, 0)
    let n_count: Int = json_array_len(nodes_json)

    // Read edges from snapshot file
    let snap: String = fs_read(snap_path)
    let edges_raw: String = if str_eq(snap, "") { "[]" } else { json_get_raw(snap, "edges") }
    let edges_json: String = if str_eq(edges_raw, "") { "[]" } else { edges_raw }

    if n_count == 0 {
        // Return an empty SVG with a "no data" message
        return svg_open(width, height) +
            "<text x=\"" + int_to_str(width / 2) + "\" y=\"" + int_to_str(height / 2) + "\" " +
            "text-anchor=\"middle\" fill=\"#8b9aaa\" font-size=\"14\" " +
            "font-family=\"IBM Plex Mono,monospace\">No nodes in graph</text>" +
            svg_close()
    }

    graph_svg_endpoint(nodes_json, edges_json, width, height)
}
