import { lstat, readFile, readdir } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { verifyCppPack } from "./cpp-engine-pack.mjs";
import { verifyDotNetPack } from "./dotnet-engine-pack.mjs";
import { verifyGoPack } from "./go-engine-pack.mjs";
import { verifyJavaPack } from "./java-engine-pack.mjs";
import { verifyPerlPack } from "./perl-engine-pack.mjs";
import { verifyPcre2Pack } from "./pcre2-engine-pack.mjs";
import { verifyPhpPack } from "./php-engine-pack.mjs";
import { verifyPythonPack } from "./python-engine-pack.mjs";
import { verifyRubyPack } from "./ruby-engine-pack.mjs";
import { verifyRustPack } from "./rust-engine-pack.mjs";

const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const arguments_ = process.argv.slice(2);

const enginePacks = [
  {
    id: "cpp",
    argument: "--cpp-pack",
    verify: (pack) => verifyCppPack(pack, root),
  },
  {
    id: "dotnet",
    argument: "--dotnet-pack",
    verify: (pack) => verifyDotNetPack(pack, root),
  },
  {
    id: "go",
    argument: "--go-pack",
    verify: (pack) => verifyGoPack(pack, root),
  },
  {
    id: "java",
    argument: "--java-pack",
    verify: (pack) => verifyJavaPack(pack, root),
  },
  {
    id: "pcre2",
    argument: "--pcre2-pack",
    verify: (pack) => verifyPcre2Pack(pack, root),
  },
  {
    id: "perl",
    argument: "--perl-pack",
    verify: (pack) => verifyPerlPack(pack, root),
  },
  {
    id: "php",
    argument: "--php-pack",
    verify: (pack) => verifyPhpPack(pack, root),
  },
  {
    id: "python",
    argument: "--python-pack",
    verify: (pack) => verifyPythonPack(pack, root),
  },
  {
    id: "ruby",
    argument: "--ruby-pack",
    verify: (pack) => verifyRubyPack(pack, root),
  },
  {
    id: "rust",
    argument: "--rust-pack",
    verify: (pack) => verifyRustPack(pack, root),
  },
];

if (arguments_.length > 0) {
  const selected = enginePacks.find(
    ({ argument }) => argument === arguments_[0],
  );
  if (arguments_.length !== 2 || !selected) {
    throw new Error(
      `Usage: node scripts/verify-engine-assets.mjs [${enginePacks
        .map(({ argument }) => argument)
        .join("|")} PATH]`,
    );
  }
  const pack = path.resolve(root, arguments_[1]);
  const metadata = await selected.verify(pack);
  console.log(
    `Verified staged ${metadata.engineVersion ?? metadata.semanticIdentity} ${selected.id} engine pack.`,
  );
  process.exit(0);
}

const engineDirectory = path.join(root, "dist", "engines");
const details = await lstat(engineDirectory);
if (details.isSymbolicLink() || !details.isDirectory()) {
  throw new Error("dist/engines must be a real directory.");
}

const entries = (await readdir(engineDirectory, { withFileTypes: true })).sort(
  (left, right) =>
    left.name < right.name ? -1 : left.name > right.name ? 1 : 0,
);
const expectedEntries = [
  { name: "README.md", directory: false },
  ...enginePacks.map(({ id }) => ({ name: id, directory: true })),
].sort((left, right) =>
  left.name < right.name ? -1 : left.name > right.name ? 1 : 0,
);
if (
  entries.length !== expectedEntries.length ||
  entries.some((entry, index) => {
    const expected = expectedEntries[index];
    return (
      !expected ||
      entry.name !== expected.name ||
      (expected.directory ? !entry.isDirectory() : !entry.isFile())
    );
  })
) {
  throw new Error(
    `The production build must contain only README.md and the declared engine packs: ${enginePacks
      .map(({ id }) => id)
      .join(", ")}.`,
  );
}

const notice = await readFile(path.join(engineDirectory, "README.md"), "utf8");
for (const identity of [
  "native `RegExp`",
  "PCRE2 10.47",
  "PHP 8.5.8",
  "Perl 5.28.1",
  "Pyodide 314.0.3",
  "CRuby 4.0.0",
  "TeaVM 0.15.0",
  "Emscripten 6.0.4",
  "Go 1.26.5",
  "Rust `regex` crate 1.13.1",
  ".NET 10.0.10",
  "Scala",
]) {
  if (!notice.includes(identity)) {
    throw new Error(
      `The engine asset notice does not describe ${identity} in this release.`,
    );
  }
}

for (const engine of enginePacks) {
  await engine.verify(path.join(engineDirectory, engine.id));
}

console.log(
  `Verified native ECMAScript plus ${enginePacks
    .map(({ id }) => id)
    .join(", ")} checked-in engine packs.`,
);
