const { spawnSync } = require("child_process");
const fs = require("fs");
const path = require("path");

const rootDir = path.resolve(__dirname, "..");
const manifestPath = path.join(__dirname, "manifest.json");
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));

const requestedSuite = process.argv[2] || "standard";
const visited = new Set();

function resolveSuite(name, stack = []) {
  const suite = manifest.suites[name];
  if (!suite) {
    throw new Error(`Unknown test suite: ${name}`);
  }

  if (stack.includes(name)) {
    throw new Error(`Cyclic test suite reference: ${[...stack, name].join(" -> ")}`);
  }

  if (visited.has(name)) {
    return [];
  }
  visited.add(name);

  const nested = suite.suites || [];
  const nestedCommands = nested.flatMap((suiteName) => resolveSuite(suiteName, [...stack, name]));
  return [...nestedCommands, ...(suite.commands || [])];
}

function assertSafeCommand(commandPath) {
  if (typeof commandPath !== "string" || !commandPath.trim()) {
    throw new Error("Test command must be a non-empty string.");
  }
  if (commandPath.includes("..") || path.isAbsolute(commandPath)) {
    throw new Error(`Unsafe test command path: ${commandPath}`);
  }
  if (!commandPath.startsWith("tools/")) {
    throw new Error(`Test command must point to tools/: ${commandPath}`);
  }
  const absolutePath = path.join(rootDir, commandPath);
  if (!fs.existsSync(absolutePath)) {
    throw new Error(`Test command file does not exist: ${commandPath}`);
  }
  return absolutePath;
}

const commands = resolveSuite(requestedSuite);

if (!commands.length) {
  throw new Error(`Suite has no commands: ${requestedSuite}`);
}

console.log(`MazeXChain test suite: ${requestedSuite}`);
console.log(`Commands: ${commands.length}`);

for (const [index, commandPath] of commands.entries()) {
  const absolutePath = assertSafeCommand(commandPath);
  console.log(`\n[${index + 1}/${commands.length}] node ${commandPath}`);

  const result = spawnSync(process.execPath, [absolutePath], {
    cwd: rootDir,
    stdio: "inherit",
    env: process.env
  });

  if (result.error) {
    throw result.error;
  }
  if (result.status !== 0) {
    process.exit(result.status || 1);
  }
}

console.log(`\nMazeXChain test suite passed: ${requestedSuite}`);
