// load the Wiregasm library
importScripts(
  'wiregasm_new.js', // self-compilation es5
  'wiregasm_load.js'
  // 'https://cdn.jsdelivr.net/npm/@goodtools/wiregasm/dist/wiregasm.js'
);

const wg = new Wiregasm();

const inflateRemoteBuffer = async url => {
  const res = await fetch(url);
  return await res.arrayBuffer();
};

const fetchPackages = async () => {
  console.log('Fetching packages');
  let [wasmBuffer, dataBuffer] = await Promise.all([
    await inflateRemoteBuffer(
      'wiregasm.wasm'
      // 'https://cdn.jsdelivr.net/npm/@goodtools/wiregasm/dist/wiregasm.wasm'
    ),
    await inflateRemoteBuffer(
      'wiregasm.data'
      // 'https://cdn.jsdelivr.net/npm/@goodtools/wiregasm/dist/wiregasm.data'
    ),
  ]);

  return { wasmBuffer, dataBuffer };
};

// Load the Wiregasm Wasm data
fetchPackages()
  .then(({ wasmBuffer, dataBuffer }) => {
    return wg.init(loadWiregasm, {
      wasmBinary: wasmBuffer,
      getPreloadedPackage() {
        return dataBuffer;
      },
      handleStatus: (type, status) => {
        postMessage({ type: 'status', code: type, status: status });
      },
      printErr: error => {
        postMessage({ type: 'error', error: error });
      },
    });
  })
  .then(() => {
    postMessage({ type: 'init' });
  })
  .catch(e => {
    postMessage({ type: 'error', error: e });
  });

/**Converts a Vector to a JS array */
function replacer(key, value) {
  if (value.constructor.name.startsWith('Vector')) {
    return vectorToArray(value);
  }
  return value;
}

// Event listener to receive messages from the main script
this.onmessage = ev => {
  const data = ev.data;
  switch (data.type) {
    case 'close':
      wg.destroy();
      break;
    case 'columns':
      const columns = wg.columns();
      if (Array.isArray(columns)) {
        this.postMessage({ type: 'columns', data: columns });
      }
      break;
    case 'select': // select a frame
      const number = data.number;
      const frameData = wg.frame(number);
      const frameDataToJSON = JSON.parse(JSON.stringify(frameData, replacer));
      this.postMessage({
        type: 'selected',
        data: frameDataToJSON,
      });
      break;
    case 'frames': // get frames list
      const skip = data.skip;
      const limit = data.limit;
      const filter = data.filter;
      const framesData = wg.frames(filter, skip, limit);
      const framesDataToJSON = JSON.parse(JSON.stringify(framesData, replacer));
      this.postMessage({
        type: 'frames',
        data: framesDataToJSON,
      });
      break;
    case 'process-data':
      const loadData = wg.load(data.name, new Uint8Array(data.data));
      this.postMessage({ type: 'processed', data: loadData });
      break;
    case 'process':
      const f = data.file;
      const reader = new FileReader();
      reader.addEventListener('load', event => {
        // XXX: this blocks the worker thread
        const loadData = wg.load(f.name, new Uint8Array(event.target.result));
        postMessage({ type: 'processed', data: loadData });
      });
      reader.readAsArrayBuffer(f);
      break;
    case 'check-filter':
      const filterStr = data.filter;
      const checkFilterRes = wg.lib.checkFilter(filterStr);
      this.postMessage({ type: 'filter', data: checkFilterRes });
      break;
  }

  if (data.type === 'reload-quick') {
    if (wg.session) {
      // TODO: this is a hack, we should be able to reload the session
      const name = data.name;
      const res = wg.session.load();

      postMessage({ type: 'processed', name: name, data: res });
    }
  } else if (data.type === 'module-tree') {
    const res = wg.list_modules();
    // send it to the correct port
    event.ports[0].postMessage({
      result: JSON.parse(JSON.stringify(res, replacer)),
    });
  } else if (data.type === 'module-prefs') {
    const res = wg.list_prefs(data.name);
    // send it to the correct port
    event.ports[0].postMessage({
      result: JSON.parse(JSON.stringify(res, replacer)),
    });
  } else if (data.type === 'upload-file') {
    const f = data.file;
    const reader = new FileReader();
    reader.addEventListener('load', e => {
      // XXX: this blocks the worker thread
      const path = '/uploads/' + f.name;
      wg.lib.FS.writeFile(path, Buffer.from(e.target.result));
      event.ports[0].postMessage({ result: path });
    });
    reader.readAsArrayBuffer(f);
  } else if (data.type === 'update-pref') {
    try {
      console.log(`set_pref(${data.module}, ${data.key}, ${data.value})`);
      wg.set_pref(data.module, data.key, data.value);
      event.ports[0].postMessage({ result: 'ok' });
    } catch (e) {
      console.error(
        `set_pref(${data.module}, ${data.key}, ${data.value}) failed: ${e.message}`
      );
      event.ports[0].postMessage({ error: e.message });
    }
  } else if (data.type === 'apply-prefs') {
    console.log(`apply_prefs()`);
    wg.apply_prefs();
    event.ports[0].postMessage({ result: 'ok' });
  }
};
