// Boots the TinyGo `core.wasm` module under Vitest/JSDOM by reading
// the artefact and the matching wasm_exec.js shim from disk, evaluating
// the shim into the test's global scope, then instantiating WebAssembly
// against `(new Go()).importObject`. Returns a `Core` ready to use in
// tests; subsequent calls return the cached instance so each Vitest
// file pays the boot cost once.

import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { runInThisContext } from "node:vm";
import { adaptBridge, requireBridge } from "../src/platform/core/wasm";
import type { Core } from "../src/platform/core/index";

// Vitest is launched from ui/frontend, so the static artefacts produced
// by `make wasm` sit at <cwd>/static/. Resolving via process.cwd avoids
// the JSDOM-specific "URL must be of scheme file" error that
// import.meta.url triggers under the jsdom test environment.
const STATIC_DIR = resolve(process.cwd(), "static") + "/";

let cached: Promise<Core> | undefined;

export function loadWasmCoreForTest(): Promise<Core> {
	if (!cached) {
		cached = boot();
	}
	return cached;
}

async function boot(): Promise<Core> {
	if (typeof globalThis.Go === "undefined") {
		const shim = readFileSync(`${STATIC_DIR}wasm_exec.js`, "utf8");
		runInThisContext(shim);
	}
	const Go = globalThis.Go;
	if (!Go) {
		throw new Error("setup-wasm: Go runtime missing after wasm_exec.js eval");
	}
	const go = new Go();
	const wasm = readFileSync(`${STATIC_DIR}core.wasm`);
	const { instance } = await WebAssembly.instantiate(
		wasm,
		go.importObject,
	);
	void go.run(instance);
	// `go.run` is async but the Go side registers `globalThis.galaxyCore`
	// and then blocks on `select {}`; the registration happens
	// synchronously before the first await, so by the time the next
	// microtask runs the bridge is already available.
	await new Promise<void>((resolve) => setTimeout(resolve, 0));
	return adaptBridge(requireBridge());
}
