///|
/// fetch → Bytes bridge for JS target.
/// Uses globalThis.__kagura_fetch[id] to support concurrent fetches.

///|
extern "js" fn js_fetch_url(
  url : String,
  fetch_id : Int,
  on_done : (Int, Int) -> Unit,
) -> Unit =
  #| (url, id, onDone) => {
  #|   if (!globalThis.__kagura_fetch) globalThis.__kagura_fetch = {};
  #|   fetch(url)
  #|     .then(r => r.arrayBuffer())
  #|     .then(buf => {
  #|       globalThis.__kagura_fetch[id] = new Uint8Array(buf);
  #|       onDone(id, globalThis.__kagura_fetch[id].length);
  #|     })
  #|     .catch(() => { onDone(id, -1); });
  #| }

///|
extern "js" fn js_fetch_buf_byte(fetch_id : Int, index : Int) -> Int =
  #| (id, i) => globalThis.__kagura_fetch[id][i]

///|
extern "js" fn js_fetch_buf_clear(fetch_id : Int) -> Unit =
  #| (id) => { delete globalThis.__kagura_fetch[id]; }

///|
let fetch_id_counter : Ref[Int] = Ref(0)

///|
pub fn fetch_bytes(url : String, callback : (Bytes?) -> Unit) -> Unit {
  let id = fetch_id_counter.val
  fetch_id_counter.val = id + 1
  js_fetch_url(url, id, fn(fid, len) {
    if len < 0 {
      callback(None)
      return
    }
    let arr : Array[Byte] = Array::make(len, b'\x00')
    for i in 0.. Unit) -> Unit {
  fetch_bytes(url, fn(bytes_opt) {
    match bytes_opt {
      None => callback(None)
      Some(bytes) =>
        callback(decode_image_spec_auto(bytes)) catch {
          _ => callback(None)
        }
    }
  })
}