import init, {ludus} from "./rudus.js";

let initialized_wasm = false
onmessage = run

// exposed in rust as:
// async fn io (out: String) -> Result<JsValue, JsValue>
// rust calls this to perform io
export function io (out) {
  // only send messages if we have some
  if (out.length > 0) postMessage(out)
  // make an event handler that captures and delivers messages from the main thread
  // because our promise resolution isn't about calculating a value but setting a global variable, we can't asyncify it
  // explicitly return a promise
  return new Promise((resolve, reject) => {
    // deliver the response to ludus when we get a response from the main thread
    onmessage = (e) => {
      resolve(JSON.stringify(e.data))
    }
    // cancel the response if it takes too long
    setTimeout(() => reject("io took too long"), 500)
  })
}


// set as default event handler from main thread
async function run(e) {
  // we must NEVER run `await init()` twice
  if (!initialized_wasm) {
    // this must come before the init call
    initialized_wasm = true
    await init()
    console.log("Worker: Ludus has been initialized.")
  }
  // the data is always an array; we only really expect one member tho
  let msgs = e.data
  for (const msg of msgs) {
    // evaluate source if we get some
    if (msg.verb === "Run" && typeof msg.data === 'string') {
      // temporarily stash an empty function so we don't keep calling this one if we receive additional messages
      onmessage = () => {}
      // actually run the ludus--which will call `io`--and replace `run` as the event handler for ipc
      await ludus(msg.data)
      // once we've returned from `ludus`, make this the event handler again
      onmessage = run
    } else {
      // report and swallow any malformed startup messages
      console.log("Worker: Did not get valid startup message. Instead got:")
      console.log(e.data)
    }
  }
}



