// bundle_resolver.hako — Stage‑B bundling resolver (Box‑first)

static box BundleResolver {
  // Resolve and merge bundles. Returns merged prefix string or null on error.
  // Policy:
  //  - Duplicate named modules are Fail‑Fast ([bundle/duplicate] Name)
  //  - --require-mod Name must appear in named bundles ([bundle/missing] Name)
  //  - Merge order: bundle-src* → bundle-mod* (in given order)
  resolve(bundle_srcs, bundle_names, bundle_mod_srcs, require_mods) {
    // Shallow recursion guard to prevent accidental self-recursion in Stage‑B bundler.
    {
      local depth = env.get("HAKO_STAGEB_BUNDLE_DEPTH")
      if depth != null && ("" + depth) != "0" {
        print("[stageb/recursion] BundleResolver.resolve recursion detected")
        return null
      }
      env.set("HAKO_STAGEB_BUNDLE_DEPTH", "1")
    }
    // Alias table via env: HAKO_BUNDLE_ALIAS_TABLE / NYASH_BUNDLE_ALIAS_TABLE
    // Format: entries separated by '|||', each entry as 'Name:code'
    local table = env.get("HAKO_BUNDLE_ALIAS_TABLE")
    if table == null || table == "" { table = env.get("NYASH_BUNDLE_ALIAS_TABLE") }
    if table != null && table != "" {
      local i = 0
      loop(i < table.length()) {
        // find next delimiter or end
        local j = table.indexOf("|||", i)
        local seg = ""
        if j >= 0 { seg = table.substring(i, j) } else { seg = table.substring(i, table.length()) }
        if seg != "" {
          local pos = -1
          local k = 0
          loop(k < seg.length()) { if seg.substring(k,k+1) == ":" { pos = k break } k = k + 1 }
          if pos < 0 { print("[bundle/alias-table/bad] " + seg) return null }
          local name = seg.substring(0, pos)
          local code = seg.substring(pos+1, seg.length())
          if name == "" || code == "" { print("[bundle/alias-table/bad] " + seg) return null }
          if bundle_names == null { bundle_names = new ArrayBox() }
          if bundle_mod_srcs == null { bundle_mod_srcs = new ArrayBox() }
          bundle_names.push(name)
          bundle_mod_srcs.push(code)
        }
        if j < 0 { break }
        i = j + 3
      }
    }
    // Env alias injection (TTL, dev-only): HAKO_BUNDLE_ALIAS_<Name> / NYASH_BUNDLE_ALIAS_<Name>
    // If a required module is not provided via --bundle-mod, but an env alias
    // supplies its code, synthesize a named bundle entry before checks/merge.
    if require_mods != null {
      local i0 = 0; local rn0 = require_mods.length()
      loop(i0 < rn0) {
        local need = "" + require_mods.get(i0)
        local present = 0
        if bundle_names != null {
          local j0 = 0; local bn0 = bundle_names.length()
          loop(j0 < bn0) { if ("" + bundle_names.get(j0)) == need { present = 1 break } j0 = j0 + 1 }
        }
        if present == 0 {
          local alias_key = "HAKO_BUNDLE_ALIAS_" + need
          local code = env.get(alias_key)
          if code == null || code == "" { code = env.get("NYASH_BUNDLE_ALIAS_" + need) }
          if code != null && code != "" {
            if bundle_names == null { bundle_names = new ArrayBox() }
            if bundle_mod_srcs == null { bundle_mod_srcs = new ArrayBox() }
            bundle_names.push(need)
            bundle_mod_srcs.push("" + code)
          }
        }
        i0 = i0 + 1
      }
    }
    // Fail on duplicate names
    if bundle_names != null && bundle_names.length() > 1 {
      local i = 0; local n = bundle_names.length()
      loop(i < n) {
        local name_i = "" + bundle_names.get(i)
        local j = i + 1
        loop(j < n) {
          if ("" + bundle_names.get(j)) == name_i {
            print("[bundle/duplicate] " + name_i)
            return null
          }
          j = j + 1
        }
        i = i + 1
      }
    }
    // Check required modules
    if require_mods != null && require_mods.length() > 0 {
      local idx = 0; local rn = require_mods.length()
      loop(idx < rn) {
        local need = "" + require_mods.get(idx)
        local found = 0
        if bundle_names != null {
          local j = 0; local bn = bundle_names.length()
          loop(j < bn) { if ("" + bundle_names.get(j)) == need { found = 1 break } j = j + 1 }
        }
        if found == 0 { print("[bundle/missing] " + need) return null }
        idx = idx + 1
      }
    }
    // Merge in order: bundle-src* → bundle-mod*
    local merged = ""
    if bundle_srcs != null {
      local i = 0; local m = bundle_srcs.length()
      loop(i < m) { merged = merged + bundle_srcs.get(i) + "\n" i = i + 1 }
    }
    if bundle_mod_srcs != null {
      local i2 = 0; local m2 = bundle_mod_srcs.length()
      loop(i2 < m2) { merged = merged + bundle_mod_srcs.get(i2) + "\n" i2 = i2 + 1 }
    }
    // Clear depth guard before returning
    env.set("HAKO_STAGEB_BUNDLE_DEPTH", "0")
    return merged
  }
}
