import { sveltekit } from "@sveltejs/kit/vite"
import { readFile } from "node:fs/promises"
import path from "node:path"
import { defineConfig, type Plugin, type ResolvedConfig } from "vite"

export default defineConfig({
	plugins: [sveltekit(), cloudflareWasmImport()],
})

// This plugin allows us to import WebAssembly modules and have them work in
// both the browser, Node.js, and Cloudflare Workers.
function cloudflareWasmImport(): Plugin {
	const wasmPostfix = ".wasm"
	const importMetaPrefix = "___WASM_IMPORT_PATH___"

	let config: ResolvedConfig

	return {
		name: "cloudflare-wasm-import",
		configResolved(resolvedConfig) {
			config = resolvedConfig
		},
		async load(id) {
			if (!id.endsWith(wasmPostfix)) return

			if (config.command === "serve") {
				// Running dev server

				// We generate a module that on the browser will fetch the WASM file
				// (through a Vite `?url` import), and on the server will read the file
				// from the file system.

				return `
					import WASM_URL from ${JSON.stringify(`${id}?url`)}

					let promise
					export default function() {
						if (import.meta.env.SSR) {
							return promise ?? (promise = import("node:fs/promises")
								.then(({ readFile }) => readFile(${JSON.stringify(id)})))
						} else {
							return promise ?? (promise = fetch(WASM_URL).then(r => r.arrayBuffer()))
						}
					}
				`
			}

			// When building, we emit the WASM file as an asset and generate a module
			// that will fetch the asset in the browser, import the WASM file when in
			// a Cloudflare Worker, and read the file from the file system when in
			// Node.js.

			const wasmSource = await readFile(id)

			const refId = this.emitFile({
				type: "asset",
				name: path.basename(id),
				source: wasmSource,
			})

			return `
				import WASM_URL from ${JSON.stringify(`${id}?url`)}

				let promise
				export default function() {
					if (import.meta.env.SSR) {
						if (typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers") {
							return promise ?? (promise = import(import.meta.${importMetaPrefix}${refId}))
						} else {
							return promise ?? (promise = import(\`\${"node:fs/promises"}\`)
								.then(({ readFile }) => readFile(new URL(import.meta.ROLLUP_FILE_URL_${refId}))))
						}
					} else {
						return promise ?? (promise = fetch(WASM_URL).then(r => r.arrayBuffer()))
					}
				}
			`
		},
		resolveImportMeta(property, { chunkId }) {
			if (!property?.startsWith(importMetaPrefix)) return

			const refId = property.slice(importMetaPrefix.length)
			const fileName = this.getFileName(refId)
			const relativePath = path.relative(path.dirname(chunkId), fileName)

			return JSON.stringify(relativePath)
		},
	}
}