import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, resolve } from "node:path";
import assert from "node:assert/strict";

import { createLinuxCncInterpSdk } from "../../../runtime/sdk/src/index.js";

function verifyExpectedOutput(fixtureName, output, expectedText) {
  const expectedLines = expectedText.split("\n").filter(Boolean);

  for (const expectedLine of expectedLines) {
    if (expectedLine.startsWith("absent=")) {
      const forbidden = expectedLine.slice("absent=".length);
      assert.equal(
        output.includes(forbidden),
        false,
        `${fixtureName}: unexpected ${forbidden}`,
      );
      continue;
    }

    assert.equal(
      output.includes(expectedLine),
      true,
      `${fixtureName}: ${expectedLine}`,
    );
  }
}

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const rootDir = resolve(__dirname, "../../..");
const wasmPath = resolve(rootDir, "build/wasm/core/linuxcnc_interp.wasm");
const ncFilesDir = resolve(rootDir, "vendor/linuxcnc/nc_files");

const interp = await createLinuxCncInterpSdk({
  wasmBinary: readFileSync(wasmPath),
  print() {},
  printErr(message) {
    console.error(message);
  },
});

function runVendorNcFile(filename) {
  const wasmPath = `/work/nc-files/${filename}`;
  interp.writeTextFile(wasmPath, readFileSync(resolve(ncFilesDir, filename), "utf8"));
  return interp.runFile(wasmPath);
}

function runVendorNcFileWithToolTable(filename) {
  const wasmDir = "/work/nc-files-context";
  const wasmPath = `${wasmDir}/${filename}`;
  const iniPath = `${wasmDir}/nc_files_context.ini`;
  interp.writeTextFile(wasmPath, readFileSync(resolve(ncFilesDir, filename), "utf8"));
  interp.writeTextFile(
    `${wasmDir}/tool.tbl`,
    "T1 P1 D10.000000 Z+0.000000 ; nc_files representative context tool\n",
  );
  interp.writeTextFile(
    iniPath,
    [
      "[RS274NGC]",
      "SUBROUTINE_PATH = .",
      "",
      "[TRAJ]",
      "COORDINATES = X Y Z A B C U V W",
      "",
      "[EMCIO]",
      "TOOL_TABLE = tool.tbl",
      "",
    ].join("\n"),
  );
  return interp.runFileWithIni(wasmPath, iniPath);
}

verifyExpectedOutput(
  "nc_files_3d_chips_context_wasm",
  runVendorNcFileWithToolTable("3D_Chips.ngc"),
  [
    "file_open=0",
    "file_read_count=4706",
    "file_execute_count=4706",
    "file_saw_error=0",
    "run_step phase=execute step=18 rc=2 line=18",
    "statement_uri=N50T%23%3Ctoolno%3EM6",
    "run_step phase=execute step=19 rc=0 line=19",
    "statement_uri=N60M8",
    "canon_event=CHANGE_TOOL",
    "canon_event=START_SPINDLE_CLOCKWISE spindle=0",
    "canon_event=STRAIGHT_TRAVERSE line=21 x=0 y=0 z=10",
    "canon_event=STRAIGHT_FEED line=23 x=53 y=-56.128 z=-25.372",
    "canon_event=PROGRAM_END",
    "absent=file_error_text=",
    "absent=Requested tool 1 not found",
  ].join("\n"),
);

verifyExpectedOutput(
  "nc_files_arcspiral_wasm",
  runVendorNcFile("arcspiral.ngc"),
  [
    "file_open=0",
    "file_read_count=1008",
    "file_execute_count=1008",
    "file_saw_error=0",
    "canon_event=STRAIGHT_TRAVERSE line=3 x=0 y=0 z=1",
    "canon_event=STRAIGHT_FEED line=6 x=1.72464 y=-1.01273 z=-0.1",
    "canon_event=PROGRAM_END",
    "absent=file_error_text=",
  ].join("\n"),
);

verifyExpectedOutput(
  "nc_files_hole_circle_wasm",
  runVendorNcFile("hole-circle.ngc"),
  [
    "file_open=0",
    "file_read_count=12",
    "file_execute_count=12",
    "file_saw_error=0",
    "canon_event=STRAIGHT_TRAVERSE line=7 x=1.5 y=0 z=0",
    "canon_event=STRAIGHT_FEED line=10 x=0.75 y=1.29904 z=-0.4",
    "canon_event=PROGRAM_END",
    "absent=file_error_text=",
  ].join("\n"),
);

verifyExpectedOutput(
  "nc_files_factorial_wasm",
  runVendorNcFile("factorial.ngc"),
  [
    "file_open=0",
    "file_read_count=11",
    "file_execute_count=11",
    "file_saw_error=0",
    "canon_event=PROGRAM_END",
    "absent=file_error_text=",
  ].join("\n"),
);

verifyExpectedOutput(
  "nc_files_m6demo_wasm",
  runVendorNcFile("m6demo.ngc"),
  [
    "file_open=0",
    "file_read_count=88",
    "file_execute_count=88",
    "file_saw_error=0",
    "canon_event=SET_G5X_OFFSET index=1",
    "canon_event=STOP_SPINDLE_TURNING spindle=0",
    "canon_event=PROGRAM_END",
    "absent=file_error_text=",
  ].join("\n"),
);

console.log("nc_files_wasm_node_smoke=ok");
