// tools/hako_check/render/graphviz.hako - GraphvizRenderBox (MVP)
// Render minimal DOT graph from one or more Analysis IRs.

using selfhost.shared.common.string_helpers as Str

static box GraphvizRenderBox {
  render_multi(irs) {
    // irs: ArrayBox of IR Map
    print("digraph Hako {")
    // Internal key names for node/edge key lists (avoid collisions with user names)
    local NK_KEY = "__graphviz_nodes__"
    local EK_KEY = "__graphviz_edges__"
    // optional graph attributes (kept minimal)
    // print("  rankdir=LR;")
    // Node and edge sets to avoid duplicates
    local nodes = new MapBox()
    local edges = new MapBox()
    if irs != null {
      local gi = 0
      while gi < irs.size() {
        local ir = irs.get(gi)
        me._render_ir(ir, nodes, edges)
        gi = gi + 1
      }
    }
    // Build clusters by box: group nodes whose name looks like Box.method/arity
    local groups = new MapBox()
    local group_keys = new ArrayBox()
    local nk = nodes.get(NK_KEY)
    if nk == null { nk = new ArrayBox() }
    if nk != null {
      local i = 0
      while i < nk.size() {
        local name = nk.get(i)
        local dot = name.indexOf(".")
        if dot > 0 {
          local box_name = name.substring(0, dot)
          local gkey = "cluster_" + box_name
          local arr = groups.get(gkey)
          if arr == null { arr = new ArrayBox(); groups.set(gkey, arr); group_keys.push(gkey) }
          // dedup in group
          local seen = 0; local j=0; while j < arr.size() { if arr.get(j) == name { seen = 1; break } j = j + 1 }
          if seen == 0 { arr.push(name) }
        }
        i = i + 1
      }
    }
    // Emit clusters
    local gi = 0
    while gi < group_keys.size() {
      local gk = group_keys.get(gi)
      print("  subgraph \"" + gk + "\" {")
      // label = box name (strip "cluster_")
      local label = gk.substring("cluster_".length())
      print("    label=\"" + label + "\";")
      local arr = groups.get(gk)
      local j = 0; while j < arr.size() { print("    \"" + arr.get(j) + "\";"); j = j + 1 }
      print("  }")
      gi = gi + 1
    }
    // Emit edges
    // Emit edges
    if edges != null {
      // edges map key = from + "\t" + to
      // naive iteration by trying to get keys from a stored list
      // We kept an ArrayBox under edges.get("__keys__") for listing
      local ks = edges.get(EK_KEY)
      if ks == null { ks = new ArrayBox() }
      if ks != null {
        local ei = 0
        while ei < ks.size() {
          local key = ks.get(ei)
          local tab = key.indexOf("\t")
          if tab > 0 {
            local src = key.substring(0, tab)
            local dst = key.substring(tab+1)
            print("  \"" + src + "\" -> \"" + dst + "\";")
            // also register nodes (in case they weren't explicitly collected)
            nodes.set(src, 1)
            nodes.set(dst, 1)
          }
          ei = ei + 1
        }
      }
    }
    // Emit standalone nodes not covered by clusters
    if nk != null {
      local ni = 0
      while ni < nk.size() {
        local name = nk.get(ni)
        local dot = name.indexOf(".")
        if dot < 0 { print("  \"" + name + "\";") }
        ni = ni + 1
      }
    }
    print("}")
    return 0
  }
  _render_ir(ir, nodes, edges) {
    if ir == null { return }
    // methods
    local ms = ir.get("methods")
    if ms != null {
      local mi = 0
      while mi < ms.size() {
        me._add_node(nodes, ms.get(mi))
        mi = mi + 1
      }
    }
    // calls
    local cs = ir.get("calls")
    if cs != null {
      local ci = 0
      while ci < cs.size() {
        local c = cs.get(ci)
        local f = c.get("from")
        local t = c.get("to")
        me._add_edge(edges, f, t)
        ci = ci + 1
      }
    }
  }
  _add_node(nodes, name) {
    if name == null { return }
    nodes.set(name, 1)
    // also store a list of keys for emitting (since Map has no key iterator)
    local arr = nodes.get("__graphviz_nodes__"); if arr == null { arr = new ArrayBox(); nodes.set("__graphviz_nodes__", arr) }
    // avoid duplicates
    local seen = 0
    local i = 0; while i < arr.size() { if arr.get(i) == name { seen = 1; break } i = i + 1 }
    if seen == 0 { arr.push(name) }
  }
  _add_edge(edges, src, dst) {
    if src == null || dst == null { return }
    local key = src + "\t" + dst
    if edges.get(key) == null { edges.set(key, 1) }
    local arr = edges.get("__graphviz_edges__"); if arr == null { arr = new ArrayBox(); edges.set("__graphviz_edges__", arr) }
    // avoid duplicates
    local seen = 0
    local i = 0; while i < arr.size() { if arr.get(i) == key { seen = 1; break } i = i + 1 }
    if seen == 0 { arr.push(key) }
  }
}

static box GraphvizRenderMain { method main(args) { return 0 } }
