// lower_return_loop_strlen_sum_box.hako — Recognize simple loop sum of String.length and fold
// Pattern (Program JSON v0):
//   local i=0; local s=New(StringBox,<String>); local total=0;
//   Loop(Compare(i < N)) { total = total + s.length(); i = i + 1 }
//   Return(total)
// Lowering: result = N * len(<String>) → MIR v1 const+ret

using selfhost.shared.json.utils.json_frag as JsonFragBox

static box LowerReturnLoopStrlenSumBox {
  try_lower(program_json) {
    if program_json == null { return null }
    local s = "" + program_json

    // Quick guards for required nodes
    if JsonFragBox.index_of_from(s, "\"type\":\"Loop\"", 0) < 0 { return null }
    if JsonFragBox.index_of_from(s, "\"type\":\"Return\"", 0) < 0 { return null }

    // Find Local s = New(StringBox, <String|Str>)
    local s_name = null
    local s_val = null
    {
      local pos = 0
      loop(true){
        local k = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", pos)
        if k < 0 { break }
        local kn = JsonFragBox.index_of_from(s, "\"name\":\"", k)
        if kn >= 0 {
          local nm = JsonFragBox.read_string_after(s, kn + 7)
          if nm == "s" {
            // ensure expr is New(StringBox, ...)
            local ke = JsonFragBox.index_of_from(s, "\"expr\":{", k)
            if ke >= 0 {
              if JsonFragBox.index_of_from(s, "\"type\":\"New\"", ke) >= 0 && JsonFragBox.index_of_from(s, "\"class\":\"StringBox\"", ke) >= 0 {
                local ka = JsonFragBox.index_of_from(s, "\"args\":[", ke)
                if ka >= 0 {
                  // accept {type:"String"} or {type:"Str"}
                  local ks = JsonFragBox.index_of_from(s, "\"type\":\"String\"", ka)
                  if ks < 0 { ks = JsonFragBox.index_of_from(s, "\"type\":\"Str\"", ka) }
                  if ks >= 0 {
                    local kv = JsonFragBox.index_of_from(s, "\"value\":\"", ks)
                    if kv >= 0 { s_val = JsonFragBox.read_string_after(s, kv + 8) s_name = nm break }
                  }
                }
              }
            }
          }
        }
        pos = k + 1
      }
    }
    if s_name == null || s_val == null { return null }

    // Find Loop cond i < N (best-effort); fallback to scan any Int literal as limit
    local limit = null
    {
      local kloop = JsonFragBox.index_of_from(s, "\"type\":\"Loop\"", 0)
      if kloop < 0 { return null }
      local kcmp = JsonFragBox.index_of_from(s, "\"type\":\"Compare\"", kloop); if kcmp < 0 { return null }
      local kop = JsonFragBox.index_of_from(s, "\"op\":", kcmp); if kop < 0 { return null }
      local op = JsonFragBox.read_string_after(s, kop + 5); if op == null || !(op == "<" || op == "<=") { return null }
      // rhs Int
      local krhs = JsonFragBox.index_of_from(s, "\"rhs\":{", kcmp); if krhs < 0 { return null }
      local ti = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", krhs); if ti < 0 { return null }
      local kv = JsonFragBox.index_of_from(s, "\"value\":", ti); if kv < 0 { return null }
      local lim = JsonFragBox.read_int_after(s, kv + 8); if lim == null { return null }
      limit = lim
    }
    if limit == null {
      // Fallback: pick the largest Int literal in JSON (heuristic)
      local pos2 = 0
      local best = 0
      loop(true){
        local kti = JsonFragBox.index_of_from(s, "\"type\":\"Int\"", pos2)
        if kti < 0 { break }
        local kv2 = JsonFragBox.index_of_from(s, "\"value\":", kti)
        if kv2 >= 0 {
          local v = JsonFragBox.read_int_after(s, kv2 + 8)
          if v != null {
            local vi = 0 + ("" + v)
            if vi > best { best = vi }
          }
        }
        pos2 = kti + 1
      }
      if best > 1 { limit = ("" + best) } else { return null }
    }

    // Verify body contains '+=' like total = total + s.length()
    // (structural guard only)
    if JsonFragBox.index_of_from(s, "\"name\":\"total\"", 0) < 0 { return null }
    if JsonFragBox.index_of_from(s, "\"method\":\"length\"", 0) < 0 && JsonFragBox.index_of_from(s, "\"method\":\"size\"", 0) < 0 { return null }

    // Compute byte-length (bench strings are ASCII)
    local slen = ("" + s_val).length()
    local lim_i = 0 + ("" + limit)
    local len_i = 0 + ("" + slen)
    local res = lim_i * len_i

    // Emit MIR v1 const+ret
    local mir = "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[{\"name\":\"main\",\"blocks\":[{\"id\":0,\"instructions\":[{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + res + "}},{\"op\":\"ret\",\"value\":1}]}]}]}"
    return mir
  }
}
