#!/usr/bin/env node

import { join, resolve } from "node:path";
import { repoRoot, runCommand, runMoonbitTool } from "./lib/moonbit-tool-runner.mjs";

const invocationRoot = process.cwd();
const toolPackage = "tools/moui/validate_web_runtime_handoff";

const usage = () => {
  console.error(
    "Usage: node scripts/validate-web-runtime-handoff.mjs [--base-url http://127.0.0.1:18080] [--manifest artifacts/conformance/web-runtime-handoff.json]",
  );
};

let baseUrl = "";
let manifestPath = "";
const rootDir = process.env.MOUI_WEB_RUNTIME_HANDOFF_ROOT || ".";
const originalArgs = process.argv.slice(2);

for (let i = 0; i < originalArgs.length; i += 1) {
  const arg = originalArgs[i];
  if (arg === "--base-url") {
    if (i + 1 >= originalArgs.length) {
      console.error("Missing value for --base-url");
      usage();
      process.exit(2);
    }
    baseUrl = originalArgs[i + 1];
    i += 1;
  } else if (arg === "--manifest") {
    if (i + 1 >= originalArgs.length) {
      console.error("Missing value for --manifest");
      usage();
      process.exit(2);
    }
    manifestPath = originalArgs[i + 1];
    i += 1;
  } else if (arg === "--help" || arg === "-h") {
    usage();
    process.exit(0);
  } else {
    console.error(`Unknown argument: ${arg}`);
    usage();
    process.exit(2);
  }
}

const targets = [
  {
    name: "showcase-web-wasm",
    packagePath: "examples/showcase/web_wasm",
    wasmPath: "_build/wasm-gc/debug/build/examples/showcase/web_wasm/web_wasm.wasm",
  },
  {
    name: "markdown-editor-web-wasm",
    packagePath: "examples/markdown_editor/web_wasm",
    wasmPath:
      "_build/wasm-gc/debug/build/examples/markdown_editor/web_wasm/web_wasm.wasm",
  },
];

const normalizeBaseUrl = url => url.replace(/\/+$/, "");

const checkHttp = async (path, label, httpChecks, httpFailures) => {
  const url = `${normalizeBaseUrl(baseUrl)}/${path}`;
  let response;
  try {
    response = await fetch(url, { method: "GET" });
  } catch (error) {
    httpFailures.push(`${label}: failed to fetch ${url}: ${error.message}`);
    return;
  }
  if (!response.ok) {
    httpFailures.push(`${label}: ${url} returned ${response.status} ${response.statusText}`);
    return;
  }
  const bytes = (await response.arrayBuffer()).byteLength;
  if (bytes === 0) {
    httpFailures.push(`${label}: ${url} returned an empty body`);
    return;
  }
  httpChecks.push({ label, path, url, bytes });
};

const collectHttpChecks = async () => {
  const httpChecks = [];
  const httpFailures = [];
  if (!baseUrl) {
    return { httpChecks, httpFailures };
  }
  if (typeof fetch !== "function") {
    return {
      httpChecks,
      httpFailures: ["Node fetch API is unavailable; cannot run --base-url checks"],
    };
  }
  for (const target of targets) {
    await checkHttp(
      `${target.packagePath}/index.html`,
      `${target.name} html`,
      httpChecks,
      httpFailures,
    );
    await checkHttp(target.wasmPath, `${target.name} wasm`, httpChecks, httpFailures);
  }
  await checkHttp("moui_web_renderer/runtime.js", "web runtime.js", httpChecks, httpFailures);
  await checkHttp(
    "moui/backend/web/browser_runtime.js",
    "browser_runtime.js",
    httpChecks,
    httpFailures,
  );
  return { httpChecks, httpFailures };
};

const { httpChecks, httpFailures } = await collectHttpChecks();

const toolArgs = [
  "--root",
  resolve(invocationRoot, rootDir),
  "--display-root",
  rootDir,
];
if (baseUrl) {
  toolArgs.push("--base-url", baseUrl);
}
if (manifestPath && httpFailures.length === 0) {
  toolArgs.push("--manifest", resolve(invocationRoot, manifestPath));
}
for (const check of httpChecks) {
  toolArgs.push(
    "--http-check",
    check.label,
    check.path,
    check.url,
    String(check.bytes),
  );
}

const toolResult = runMoonbitTool(toolPackage, toolArgs, {
  cwd: invocationRoot,
  exitOnFailure: false,
  failureStdoutToStderr: true,
  suppressSuccessStdout: httpFailures.length > 0,
});

let exitStatus = toolResult.status ?? 1;
for (const failure of httpFailures) {
  console.error(`web runtime handoff: ${failure}`);
}
if (httpFailures.length > 0 && exitStatus === 0) {
  exitStatus = 1;
}
if (exitStatus !== 0) {
  process.exit(exitStatus);
}

if (manifestPath) {
  runCommand(
    process.execPath,
    [join(repoRoot, "scripts/validate-web-runtime-handoff-manifest.mjs"), manifestPath],
    { cwd: invocationRoot },
  );
}