import {
  createOnMessage as __wasmCreateOnMessageForFsProxy,
  getDefaultContext as __emnapiGetDefaultContext,
  instantiateNapiModule as __emnapiInstantiateNapiModule,
  WASI as __WASI,
  instantiateNapiModuleSync,
  MessageHandler
} from '@sivukhin/wasm-runtime'

import { MainDummyImports, OpfsDirectory, workerImports, isWebWorker } from "@sivukhin/database-browser-common";

let napiModule = {
  exports: {
    Database: {},
    Opfs: {},
    OpfsFile: {},
    Statement: {},
    connect: {},
    initThreadPool: {},
  }
};
export let MainWorker = null;
if (isWebWorker()) {
  let opfs = new OpfsDirectory();
  let memory = null;

  const handler = new MessageHandler({
    onLoad({ wasmModule, wasmMemory }) {
      memory = wasmMemory;
      const wasi = new __WASI({
        print: function () {
          // eslint-disable-next-line no-console
          console.log.apply(console, arguments)
        },
        printErr: function () {
          // eslint-disable-next-line no-console
          console.error.apply(console, arguments)
        },
      })
      return instantiateNapiModuleSync(wasmModule, {
        childThread: true,
        wasi,
        overwriteImports(importObject) {
          importObject.env = {
            ...importObject.env,
            ...importObject.napi,
            ...importObject.emnapi,
            ...workerImports(opfs, memory),
            memory: wasmMemory,
          }
        },
      })
    },
  })

  globalThis.onmessage = async function (e) {
    if (e.data.__turso__ == 'register') {
      try {
        await opfs.registerFile(e.data.path);
        self.postMessage({ id: e.data.id });
      } catch (error) {
        self.postMessage({ id: e.data.id, error: error });
      }
      return;
    } else if (e.data.__turso__ == 'unregister') {
      try {
        await opfs.unregisterFile(e.data.path);
        self.postMessage({ id: e.data.id });
      } catch (error) {
        self.postMessage({ id: e.data.id, error: error });
      }
      return;
    }
    handler.handle(e)
  }
} else {

  const __wasi = new __WASI({
    version: 'preview1',
  })

  const tursoPackageVersion = "0.2.0-pre.6";

  // both Vite and Turbopack has issues with loading wasm modules in dev server
  // Vite: https://github.com/vitejs/vite/issues/8427
  // Turbopack: https://github.com/vercel/next.js/issues/82520
  // So, we use completely remote url for development only
  const remoteWasmUrl = `https://unpkg.com/@sivukhin/database-browser@${tursoPackageVersion}/turso.wasm32-wasi.wasm`;
  const __wasmUrl = process.env.NODE_ENV == 'development' ? remoteWasmUrl : new URL('./turso.wasm32-wasi.wasm', import.meta.url).href;

  const __emnapiContext = __emnapiGetDefaultContext()


  const __sharedMemory = new WebAssembly.Memory({
    initial: 4000,
    maximum: 65536,
    shared: true,
  })

  const __wasmFile = await fetch(__wasmUrl).then((res) => res.arrayBuffer())

  const {
    instance: __napiInstance,
    module: __wasiModule,
    napiModule: __napiModule,
  } = await __emnapiInstantiateNapiModule(__wasmFile, {
    context: __emnapiContext,
    asyncWorkPoolSize: 1,
    wasi: __wasi,
    onCreateWorker() {
      const worker = new Worker(import.meta.url, {
        name: 'turso-database',
        type: 'module',
      })
      MainWorker = worker;
      return worker
    },
    overwriteImports(importObject) {
      importObject.env = {
        ...importObject.env,
        ...importObject.napi,
        ...importObject.emnapi,
        ...MainDummyImports,
        memory: __sharedMemory,
      }
      return importObject
    },
    beforeInit({ instance }) {
      for (const name of Object.keys(instance.exports)) {
        if (name.startsWith('__napi_register__')) {
          instance.exports[name]()
        }
      }
    },
  })
  napiModule = __napiModule;
}

export default napiModule.exports
export const Database = napiModule.exports.Database
export const Opfs = napiModule.exports.Opfs
export const OpfsFile = napiModule.exports.OpfsFile
export const Statement = napiModule.exports.Statement
export const connect = napiModule.exports.connect
export const initThreadPool = napiModule.exports.initThreadPool
