import assert from "node:assert/strict";

import {
  createRunSessionReadinessState,
  runGcodeSessionWorkflow,
  selectSessionGcodeProgram,
} from "../../../runtime/ui/ini-panel/run-workflow.js";

const defaultProgram = selectSessionGcodeProgram({
  defaultFilename: "ui-session.ngc",
  defaultOpfsPath: "linuxcnc/gcode/ui-session.ngc",
  wasmPath: "/work/ui-session.ngc",
  gcodeFilenameFromProgramPath: () => {
    throw new Error("not used");
  },
});

assert.deepEqual(defaultProgram, {
  filename: "ui-session.ngc",
  opfsPath: "linuxcnc/gcode/ui-session.ngc",
  source: "default",
  wasmPath: "/work/ui-session.ngc",
});

const snapshotProgram = selectSessionGcodeProgram({
  snapshot: {
    payload: {
      files: {
        gcode: "linuxcnc/gcode/snapshot-session.ngc",
      },
    },
  },
  defaultFilename: "ui-session.ngc",
  defaultOpfsPath: "linuxcnc/gcode/ui-session.ngc",
  wasmPath: "/work/ui-session.ngc",
  gcodeFilenameFromProgramPath: (path) => path.split("/").at(-1),
});

assert.deepEqual(snapshotProgram, {
  filename: "snapshot-session.ngc",
  opfsPath: "linuxcnc/gcode/snapshot-session.ngc",
  source: "snapshot",
  wasmPath: "/work/ui-session.ngc",
});

const readiness = createRunSessionReadinessState({
  loadedSession: {
    ini: {
      wasmPath: "/work/session-machine.ini",
    },
  },
  snapshot: {
    sessionId: "ui-machine-session",
    metadata: {
      workflow: "save-session-snapshot",
      snapshotLabel: "ui-machine-session/ui-machine-session.json",
      defaultGcodeOpfsPath: "linuxcnc/gcode/ui-session.ngc",
    },
    payload: {
      files: {
        gcode: "linuxcnc/gcode/snapshot-session.ngc",
      },
    },
  },
  defaultFilename: "ui-session.ngc",
  defaultOpfsPath: "linuxcnc/gcode/ui-session.ngc",
  wasmPath: "/work/ui-session.ngc",
  gcodeFilenameFromProgramPath: (path) => path.split("/").at(-1),
});

assert.deepEqual(readiness, {
  phase: "ready",
  canRun: true,
  missing: [],
  loadedSession: {
    iniWasmPath: "/work/session-machine.ini",
  },
  snapshot: {
    present: true,
    label: "ui-machine-session/ui-machine-session.json",
    workflow: "save-session-snapshot",
    gcodeOpfsPath: "linuxcnc/gcode/snapshot-session.ngc",
  },
  defaultProgram: {
    filename: "ui-session.ngc",
    opfsPath: "linuxcnc/gcode/ui-session.ngc",
    wasmPath: "/work/ui-session.ngc",
  },
  program: {
    filename: "snapshot-session.ngc",
    opfsPath: "linuxcnc/gcode/snapshot-session.ngc",
    source: "snapshot",
    wasmPath: "/work/ui-session.ngc",
  },
  runButton: {
    enabled: true,
    reason: null,
  },
});

const calls = [];
const workflow = await runGcodeSessionWorkflow({
  interp: {
    writeTextFile: (wasmPath, text) => {
      calls.push(["writeTextFile", wasmPath, text]);
    },
    runFileWithIni: (programWasmPath, iniWasmPath) => {
      calls.push(["runFileWithIni", programWasmPath, iniWasmPath]);
      return [
        "canon_event=STRAIGHT_FEED line=1 x=1 y=2",
        "run_step phase=execute line=1 x=1 y=2 statement_uri=G1%20X1%20Y2",
        "",
      ].join("\n");
    },
  },
  loadedSession: {
    ini: {
      wasmPath: "/work/session-machine.ini",
    },
  },
  snapshot: {
    sessionId: "ui-machine-session",
    metadata: {
      workflow: "save-session-snapshot",
      snapshotLabel: "ui-machine-session/ui-machine-session.json",
      defaultGcodeOpfsPath: "linuxcnc/gcode/ui-session.ngc",
    },
    payload: {
      files: {
        gcode: "linuxcnc/gcode/snapshot-session.ngc",
      },
    },
  },
  defaultFilename: "ui-session.ngc",
  defaultOpfsPath: "linuxcnc/gcode/ui-session.ngc",
  wasmPath: "/work/ui-session.ngc",
  gcodeFilenameFromProgramPath: (path) => path.split("/").at(-1),
  loadGcodeProgram: async (filename) => {
    calls.push(["loadGcodeProgram", filename]);
    return "G1 X1 Y2\n";
  },
  snapshotLabel: "ui-machine-session/ui-machine-session.json",
  summarizeRun: (resultText, programText) => {
    calls.push(["summarizeRun", resultText, programText]);
    return {
      canonicalEventCount: 1,
      motionSnapshotCount: 1,
      motionSnapshots: [{ line: 1 }],
    };
  },
});

assert.deepEqual(calls, [
  ["loadGcodeProgram", "snapshot-session.ngc"],
  ["writeTextFile", "/work/ui-session.ngc", "G1 X1 Y2\n"],
  ["runFileWithIni", "/work/ui-session.ngc", "/work/session-machine.ini"],
  [
    "summarizeRun",
    "canon_event=STRAIGHT_FEED line=1 x=1 y=2\nrun_step phase=execute line=1 x=1 y=2 statement_uri=G1%20X1%20Y2",
    "G1 X1 Y2\n",
  ],
]);

assert.deepEqual(workflow.summary, {
  runStatus: "ok",
  programSource: "snapshot",
  snapshotLabel: "ui-machine-session/ui-machine-session.json",
  workflow: "save-session-snapshot",
  programOpfsPath: "linuxcnc/gcode/snapshot-session.ngc",
  programWasmPath: "/work/ui-session.ngc",
  iniWasmPath: "/work/session-machine.ini",
  canonicalEventCount: 1,
  motionSnapshotCount: 1,
});

assert.deepEqual(workflow.fields, {
  sessionGcode: "linuxcnc/gcode/snapshot-session.ngc",
  runStatus: "ok",
  runSource: "snapshot",
  runSnapshot: "ui-machine-session/ui-machine-session.json",
  runWorkflow: "save-session-snapshot",
  runOpfsPath: "linuxcnc/gcode/snapshot-session.ngc",
  runWasmPath: "/work/ui-session.ngc",
});
assert.deepEqual(workflow.readiness, readiness);

assert.deepEqual(workflow.motionSnapshots, [{ line: 1 }]);

assert.deepEqual(workflow.logLines, [
  "Program: linuxcnc/gcode/snapshot-session.ngc -> /work/ui-session.ngc",
  "Program source: snapshot",
  "Snapshot: ui-machine-session/ui-machine-session.json",
  "Workflow: save-session-snapshot",
  "Default G-code: linuxcnc/gcode/ui-session.ngc",
  "INI: /work/session-machine.ini",
  "canon_event=STRAIGHT_FEED line=1 x=1 y=2\nrun_step phase=execute line=1 x=1 y=2 statement_uri=G1%20X1%20Y2",
]);

await assert.rejects(
  () => runGcodeSessionWorkflow({
    loadedSession: null,
  }),
  /Load a machine session before running G-code/,
);

console.log("ini_panel_run_workflow_node_smoke=ok");
