/**
 * arcrun `code` 零件 —— Worker host（可部署）
 *
 * POST / → { code, input?, limits? }
 *        → QuickJS-wasm 沙箱（./sandbox.mjs 的 runCode）
 *        → { success:true, data } | { success:false, error, error_type }
 *
 * 封裝＝A（quickjs-emscripten wasmfile variant）。關鍵：CF Workers 禁止 runtime 從 bytes
 * 編譯 wasm（WebAssembly.instantiate(bytes) 被 embedder 擋），故不能用 singlefile(base64) 內嵌。
 * 改為 `import wasm from '.../wasm'` 讓 wrangler 在 build 時把 .wasm 綁成一個「已編好的
 * WebAssembly.Module」，再以 newVariant({ wasmModule }) 注入沙箱 → 執行期只 instantiate 既有
 * Module、不編譯，合 Workers 規則。無需 nodejs_compat（sandbox 用 TextEncoder 計 bytes）。
 *
 * 與其他 logic 零件不同：`code` 是自足 Worker（自帶 index.ts + sandbox.mjs + quickjs variant），
 * 不走 component-worker-template 的 TinyGo-wasm bundling 流程。部署見 DEPLOY.md。
 */

import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { newVariant } from 'quickjs-emscripten-core';
import baseVariant from '@jitl/quickjs-wasmfile-release-sync';
// wrangler 把相對路徑 .wasm import 綁成 WebAssembly.Module（build 時編好，執行期不重編）。
// wasm 從 quickjs-wasmfile-release-sync vendored 進 vendor/（見 DEPLOY.md「vendor 步驟」）。
import wasmModule from './vendor/quickjs.wasm';
// @ts-expect-error —— sandbox.mjs 為 runtime-agnostic JS 核心（Node 測試與 Worker 共用同一份）
import { runCode, setVariant } from './sandbox.mjs';

// 注入預編 Module（模組載入時一次）。之後 runCode 只 instantiate、不編譯。
setVariant(newVariant(baseVariant, { wasmModule: wasmModule as WebAssembly.Module }));

const app = new Hono();
app.use('*', cors());

app.get('/', (c) => c.json({ ok: true, component: 'code' }));

app.post('/', async (c) => {
  let body: { code?: unknown; input?: unknown; limits?: Record<string, number> };
  try {
    body = await c.req.json();
  } catch {
    return c.json({ success: false, error: 'request body must be JSON', error_type: 'ContractError' }, 400);
  }

  if (typeof body.code !== 'string') {
    return c.json({ success: false, error: 'code (string) is required', error_type: 'ContractError' }, 400);
  }

  try {
    const result = await runCode(body.code, body.input, { limits: body.limits });
    // sandbox 永遠回結構化 envelope；success=false 仍以 200 帶 error_type 回（零件語義層錯，非 HTTP 錯）
    return c.json(result);
  } catch (e) {
    // 理論上 runCode 自己 try/catch；這層是最後保險，Worker 絕不掛。
    return c.json(
      { success: false, error: e instanceof Error ? e.message : String(e), error_type: 'SandboxError' },
      500,
    );
  }
});

export default app;
