import assert from "node:assert/strict";

import {
  createIniPanelStateSummary,
  createMachineSessionControlView,
  createMachineSessionStateSnapshot,
  createMachineSessionStateBundle,
  createMachineSessionStateReport,
  createMachineSessionStateReportExport,
  createMachineSessionWorkflowOverview,
  createMachineSessionWorkflowStatus,
} from "../../../runtime/ui/ini-panel/panel-state-summary.js";
import {
  renderMachineSessionControlView,
} from "../../../runtime/ui/ini-panel/control-view-renderer.js";

const runReadinessFixture = {
  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/ui-session.ngc",
  },
  defaultProgram: {
    filename: "ui-session.ngc",
    opfsPath: "linuxcnc/gcode/ui-session.ngc",
    wasmPath: "/work/ui-session.ngc",
  },
  program: {
    filename: "ui-session.ngc",
    opfsPath: "linuxcnc/gcode/ui-session.ngc",
    source: "default",
    wasmPath: "/work/ui-session.ngc",
  },
  runButton: {
    enabled: true,
    reason: null,
  },
};

const expectedRunReadinessReport = {
  phase: "ready",
  canRun: true,
  missing: [],
  buttonEnabled: true,
  buttonReason: null,
  programSource: "default",
  programOpfsPath: "linuxcnc/gcode/ui-session.ngc",
  programWasmPath: "/work/ui-session.ngc",
  iniWasmPath: "/work/session-machine.ini",
};

const expectedEmptyRunReadinessReport = {
  phase: null,
  canRun: false,
  missing: [],
  buttonEnabled: false,
  buttonReason: null,
  programSource: null,
  programOpfsPath: null,
  programWasmPath: null,
  iniWasmPath: null,
};

const sessionReadinessFixture = {
  phase: "ready",
  ready: true,
  missing: [],
};

const expectedWorkflowOverview = {
  phase: "ran",
  missing: [],
  readiness: {
    ini: "INI WASM: ready",
    interp: "Interpreter WASM: ready",
    opfs: "OPFS: ready",
  },
  session: {
    snapshotLabel: "ui-machine-session/ui-machine-session.json",
    workflow: "save-session-snapshot",
    ini: "/work/session-machine.ini",
    gcode: "linuxcnc/gcode/ui-session.ngc",
  },
  loaded: {
    iniWasmPath: null,
    parameterWasmPath: null,
    toolTableWasmPath: null,
  },
  runReadiness: expectedRunReadinessReport,
  run: {
    status: "ok",
    canonicalEventCount: 2,
    motionSnapshotCount: 2,
    iniWasmPath: null,
  },
  status: {
    lastAction: "run-gcode",
    error: null,
  },
};

const summary = createIniPanelStateSummary({
  badges: {
    ini: "INI WASM: ready",
    interp: "Interpreter WASM: ready",
    opfs: "OPFS: ready",
  },
  machine: {
    machine: "xyzab-tdr",
    kinematics: "trivkins",
  },
  machineFiles: {
    iniOpfsPath: "linuxcnc/machines/xyzab-tdr/machine.ini",
    toolTableOpfsPath: "linuxcnc/machines/xyzab-tdr/tool.tbl",
    parameterOpfsPath: "linuxcnc/machines/xyzab-tdr/linuxcnc.var",
    gcodeOpfsPath: "linuxcnc/gcode/ui-session.ngc",
  },
  sessionSnapshot: {
    snapshotLabel: "ui-machine-session/ui-machine-session.json",
    workflow: "save-session-snapshot",
  },
  sessionReadiness: sessionReadinessFixture,
  sessionLoad: {
    iniOpfsPath: "linuxcnc/machines/xyzab-tdr/machine.ini",
    iniWasmPath: "/work/session-machine.ini",
  },
  runReadiness: runReadinessFixture,
  run: {
    runStatus: "ok",
    programSource: "snapshot",
  },
  fiveaxisRemap: "ok",
});

assert.deepEqual(summary, {
  badges: {
    ini: "INI WASM: ready",
    interp: "Interpreter WASM: ready",
    opfs: "OPFS: ready",
  },
  machine: {
    machine: "xyzab-tdr",
    kinematics: "trivkins",
  },
  machineFiles: {
    iniOpfsPath: "linuxcnc/machines/xyzab-tdr/machine.ini",
    toolTableOpfsPath: "linuxcnc/machines/xyzab-tdr/tool.tbl",
    parameterOpfsPath: "linuxcnc/machines/xyzab-tdr/linuxcnc.var",
    gcodeOpfsPath: "linuxcnc/gcode/ui-session.ngc",
  },
  sessionSnapshot: {
    snapshotLabel: "ui-machine-session/ui-machine-session.json",
    workflow: "save-session-snapshot",
  },
  sessionReadiness: sessionReadinessFixture,
  sessionLoad: {
    iniOpfsPath: "linuxcnc/machines/xyzab-tdr/machine.ini",
    iniWasmPath: "/work/session-machine.ini",
  },
  runReadiness: runReadinessFixture,
  run: {
    runStatus: "ok",
    programSource: "snapshot",
  },
  fiveaxisRemap: "ok",
});

assert.deepEqual(
  createIniPanelStateSummary(),
  {
    badges: {
      ini: null,
      interp: null,
      opfs: null,
    },
    machine: null,
    machineFiles: null,
    sessionSnapshot: null,
    sessionReadiness: null,
    sessionLoad: null,
    runReadiness: null,
    run: null,
    fiveaxisRemap: null,
  },
);

assert.deepEqual(
  createMachineSessionStateSnapshot({
    badges: {
      ini: "INI WASM: ready",
      interp: "Interpreter WASM: ready",
      opfs: "OPFS: ready",
    },
    machine: {
      machine: "xyzab-tdr",
    },
    sessionSnapshot: {
      snapshotLabel: "ui-machine-session/ui-machine-session.json",
    },
    sessionReadiness: sessionReadinessFixture,
    sessionLoad: {
      iniWasmPath: "/work/session-machine.ini",
    },
    runReadiness: runReadinessFixture,
    selectedProgram: {
      source: "snapshot",
      opfsPath: "linuxcnc/gcode/ui-session.ngc",
      wasmPath: "/work/ui-session.ngc",
    },
    run: {
      runStatus: "ok",
      programSource: "snapshot",
    },
    fields: {
      sessionIni: "/work/session-machine.ini",
      sessionParameters: "/work/session-linuxcnc.var",
      sessionToolTable: "/work/session-tool.tbl",
      sessionGcode: "linuxcnc/gcode/ui-session.ngc",
      sessionSnapshot: "ui-machine-session/ui-machine-session.json",
      runStatus: "ok",
      runSource: "snapshot",
      runSnapshot: "ui-machine-session/ui-machine-session.json",
      runWorkflow: "save-session-snapshot",
      runOpfsPath: "linuxcnc/gcode/ui-session.ngc",
      runWasmPath: "/work/ui-session.ngc",
    },
    lastAction: "run-gcode",
    fiveaxisRemap: "ok",
  }),
  {
    badges: {
      ini: "INI WASM: ready",
      interp: "Interpreter WASM: ready",
      opfs: "OPFS: ready",
    },
    machine: {
      machine: "xyzab-tdr",
    },
    machineFiles: null,
    sessionSnapshot: {
      snapshotLabel: "ui-machine-session/ui-machine-session.json",
    },
    sessionReadiness: sessionReadinessFixture,
    sessionLoad: {
      iniWasmPath: "/work/session-machine.ini",
    },
    runReadiness: runReadinessFixture,
    run: {
      runStatus: "ok",
      programSource: "snapshot",
    },
    fiveaxisRemap: "ok",
    selectedProgram: {
      source: "snapshot",
      opfsPath: "linuxcnc/gcode/ui-session.ngc",
      wasmPath: "/work/ui-session.ngc",
    },
    fields: {
      sessionIni: "/work/session-machine.ini",
      sessionParameters: "/work/session-linuxcnc.var",
      sessionToolTable: "/work/session-tool.tbl",
      sessionGcode: "linuxcnc/gcode/ui-session.ngc",
      sessionSnapshot: "ui-machine-session/ui-machine-session.json",
      runStatus: "ok",
      runSource: "snapshot",
      runSnapshot: "ui-machine-session/ui-machine-session.json",
      runWorkflow: "save-session-snapshot",
      runOpfsPath: "linuxcnc/gcode/ui-session.ngc",
      runWasmPath: "/work/ui-session.ngc",
    },
    lastAction: "run-gcode",
    error: null,
  },
);

assert.deepEqual(
  createMachineSessionStateSnapshot().fields,
  {
    sessionIni: null,
    sessionParameters: null,
    sessionToolTable: null,
    sessionGcode: null,
    sessionSnapshot: null,
    runStatus: null,
    runSource: null,
    runSnapshot: null,
    runWorkflow: null,
    runOpfsPath: null,
    runWasmPath: null,
  },
);

assert.deepEqual(
  createMachineSessionStateReport({
    badges: {
      ini: "INI WASM: ready",
      interp: "Interpreter WASM: ready",
      opfs: "OPFS: ready",
    },
    fields: {
      sessionSnapshot: "ui-machine-session/ui-machine-session.json",
      sessionIni: "/work/session-machine.ini",
      sessionParameters: "/work/session-linuxcnc.var",
      sessionToolTable: "/work/session-tool.tbl",
      sessionGcode: "linuxcnc/gcode/ui-session.ngc",
      runStatus: "ok",
      runSource: "snapshot",
      runSnapshot: "ui-machine-session/ui-machine-session.json",
      runWorkflow: "save-session-snapshot",
      runOpfsPath: "linuxcnc/gcode/ui-session.ngc",
      runWasmPath: "/work/ui-session.ngc",
    },
    sessionLoad: {
      iniWasmPath: "/work/session-machine.ini",
      parameterWasmPath: "/work/session-linuxcnc.var",
      toolTableWasmPath: "/work/session-tool.tbl",
    },
    sessionReadiness: sessionReadinessFixture,
    runReadiness: runReadinessFixture,
    selectedProgram: {
      source: "snapshot",
      opfsPath: "linuxcnc/gcode/ui-session.ngc",
      wasmPath: "/work/ui-session.ngc",
    },
    run: {
      runStatus: "ok",
      programSource: "snapshot",
      programOpfsPath: "linuxcnc/gcode/ui-session.ngc",
      programWasmPath: "/work/ui-session.ngc",
      iniWasmPath: "/work/session-machine.ini",
      canonicalEventCount: 2,
      motionSnapshotCount: 2,
    },
    lastAction: "run-gcode",
    error: null,
    fiveaxisRemap: "ok",
  }),
  {
    readiness: {
      ini: "INI WASM: ready",
      interp: "Interpreter WASM: ready",
      opfs: "OPFS: ready",
    },
    session: {
      snapshotLabel: "ui-machine-session/ui-machine-session.json",
      workflow: "save-session-snapshot",
      ini: "/work/session-machine.ini",
      parameters: "/work/session-linuxcnc.var",
      toolTable: "/work/session-tool.tbl",
      gcode: "linuxcnc/gcode/ui-session.ngc",
    },
    sessionReadiness: sessionReadinessFixture,
    loaded: {
      iniWasmPath: "/work/session-machine.ini",
      parameterWasmPath: "/work/session-linuxcnc.var",
      toolTableWasmPath: "/work/session-tool.tbl",
    },
    program: {
      source: "snapshot",
      opfsPath: "linuxcnc/gcode/ui-session.ngc",
      wasmPath: "/work/ui-session.ngc",
    },
    runReadiness: expectedRunReadinessReport,
    run: {
      status: "ok",
      canonicalEventCount: 2,
      motionSnapshotCount: 2,
      iniWasmPath: "/work/session-machine.ini",
    },
    status: {
      lastAction: "run-gcode",
      error: null,
      fiveaxisRemap: "ok",
    },
  },
);

const expectedExportReport = {
  readiness: {
    ini: "INI WASM: ready",
    interp: "Interpreter WASM: ready",
    opfs: "OPFS: ready",
  },
  session: {
    snapshotLabel: "ui-machine-session/ui-machine-session.json",
    workflow: null,
    ini: "/work/session-machine.ini",
    parameters: null,
    toolTable: null,
    gcode: null,
  },
  sessionReadiness: null,
  loaded: {
    iniWasmPath: "/work/session-machine.ini",
    parameterWasmPath: null,
    toolTableWasmPath: null,
  },
  program: {
    source: null,
    opfsPath: null,
    wasmPath: null,
  },
  runReadiness: expectedEmptyRunReadinessReport,
  run: {
    status: null,
    canonicalEventCount: 0,
    motionSnapshotCount: 0,
    iniWasmPath: null,
  },
  status: {
    lastAction: "save-session-snapshot",
    error: null,
    fiveaxisRemap: null,
  },
};

assert.deepEqual(
  createMachineSessionStateReportExport({
    badges: {
      ini: "INI WASM: ready",
      interp: "Interpreter WASM: ready",
      opfs: "OPFS: ready",
    },
    fields: {
      sessionSnapshot: "ui-machine-session/ui-machine-session.json",
      sessionIni: "/work/session-machine.ini",
    },
    sessionLoad: {
      iniWasmPath: "/work/session-machine.ini",
    },
    lastAction: "save-session-snapshot",
  }),
  {
    filename: "machine-session-state-report.json",
    mediaType: "application/json",
    report: expectedExportReport,
    text: `${JSON.stringify(expectedExportReport, null, 2)}\n`,
  },
);

assert.deepEqual(
  createMachineSessionWorkflowStatus({
    badges: {
      ini: "INI WASM: ready",
      interp: "Interpreter WASM: ready",
      opfs: "OPFS: ready",
    },
    fields: {
      sessionSnapshot: "ui-machine-session/ui-machine-session.json",
      sessionIni: "/work/session-machine.ini",
      sessionGcode: "linuxcnc/gcode/ui-session.ngc",
      runStatus: "ok",
      runWorkflow: "save-session-snapshot",
    },
    runReadiness: runReadinessFixture,
    sessionReadiness: sessionReadinessFixture,
    run: {
      runStatus: "ok",
      canonicalEventCount: 2,
      motionSnapshotCount: 2,
    },
    lastAction: "run-gcode",
    error: null,
  }),
  {
    readiness: {
      ini: "INI WASM: ready",
      interp: "Interpreter WASM: ready",
      opfs: "OPFS: ready",
    },
    overview: {
      phase: "ran",
      missing: [],
      readiness: {
        ini: "INI WASM: ready",
        interp: "Interpreter WASM: ready",
        opfs: "OPFS: ready",
      },
      session: {
        snapshotLabel: "ui-machine-session/ui-machine-session.json",
        workflow: "save-session-snapshot",
        ini: "/work/session-machine.ini",
        gcode: "linuxcnc/gcode/ui-session.ngc",
      },
      loaded: {
        iniWasmPath: null,
        parameterWasmPath: null,
        toolTableWasmPath: null,
      },
      runReadiness: expectedRunReadinessReport,
      run: {
        status: "ok",
        canonicalEventCount: 2,
        motionSnapshotCount: 2,
        iniWasmPath: null,
      },
      status: {
        lastAction: "run-gcode",
        error: null,
      },
    },
    runReadiness: expectedRunReadinessReport,
    sessionReadiness: sessionReadinessFixture,
    lastAction: "run-gcode",
    error: null,
    session: {
      snapshotLabel: "ui-machine-session/ui-machine-session.json",
      workflow: "save-session-snapshot",
      ini: "/work/session-machine.ini",
      parameters: null,
      toolTable: null,
      gcode: "linuxcnc/gcode/ui-session.ngc",
    },
    run: {
      status: "ok",
      canonicalEventCount: 2,
      motionSnapshotCount: 2,
      iniWasmPath: null,
    },
  },
);

const expectedBundleReport = {
  readiness: {
    ini: "INI WASM: ready",
    interp: "Interpreter WASM: ready",
    opfs: "OPFS: ready",
  },
  session: {
    snapshotLabel: "ui-machine-session/ui-machine-session.json",
    workflow: "save-session-snapshot",
    ini: "/work/session-machine.ini",
    parameters: null,
    toolTable: null,
    gcode: "linuxcnc/gcode/ui-session.ngc",
  },
  sessionReadiness: sessionReadinessFixture,
  loaded: {
    iniWasmPath: null,
    parameterWasmPath: null,
    toolTableWasmPath: null,
  },
  program: {
    source: null,
    opfsPath: null,
    wasmPath: null,
  },
  runReadiness: expectedRunReadinessReport,
  run: {
    status: "ok",
    canonicalEventCount: 2,
    motionSnapshotCount: 2,
    iniWasmPath: null,
  },
  status: {
    lastAction: "run-gcode",
    error: null,
    fiveaxisRemap: null,
  },
};

assert.deepEqual(
  createMachineSessionWorkflowOverview(expectedBundleReport),
  expectedWorkflowOverview,
);

assert.deepEqual(
  createMachineSessionStateBundle({
    badges: {
      ini: "INI WASM: ready",
      interp: "Interpreter WASM: ready",
      opfs: "OPFS: ready",
    },
    fields: {
      sessionSnapshot: "ui-machine-session/ui-machine-session.json",
      sessionIni: "/work/session-machine.ini",
      sessionGcode: "linuxcnc/gcode/ui-session.ngc",
      runStatus: "ok",
      runWorkflow: "save-session-snapshot",
    },
    runReadiness: runReadinessFixture,
    sessionReadiness: sessionReadinessFixture,
    run: {
      runStatus: "ok",
      canonicalEventCount: 2,
      motionSnapshotCount: 2,
    },
    lastAction: "run-gcode",
    error: null,
  }),
  {
    report: expectedBundleReport,
    overview: expectedWorkflowOverview,
    export: {
      filename: "machine-session-state-report.json",
      mediaType: "application/json",
      report: expectedBundleReport,
      text: `${JSON.stringify(expectedBundleReport, null, 2)}\n`,
    },
    workflowStatus: {
      readiness: {
        ini: "INI WASM: ready",
        interp: "Interpreter WASM: ready",
        opfs: "OPFS: ready",
      },
      overview: expectedWorkflowOverview,
      sessionReadiness: sessionReadinessFixture,
      lastAction: "run-gcode",
      error: null,
      runReadiness: expectedRunReadinessReport,
      session: {
        snapshotLabel: "ui-machine-session/ui-machine-session.json",
        workflow: "save-session-snapshot",
        ini: "/work/session-machine.ini",
        parameters: null,
        toolTable: null,
        gcode: "linuxcnc/gcode/ui-session.ngc",
      },
      run: {
        status: "ok",
        canonicalEventCount: 2,
        motionSnapshotCount: 2,
        iniWasmPath: null,
      },
    },
  },
);

assert.deepEqual(
  createMachineSessionControlView({
    report: expectedBundleReport,
    export: {
      filename: "machine-session-state-report.json",
      mediaType: "application/json",
      report: expectedBundleReport,
      text: `${JSON.stringify(expectedBundleReport, null, 2)}\n`,
    },
    workflowStatus: {
      readiness: {
        ini: "INI WASM: ready",
        interp: "Interpreter WASM: ready",
        opfs: "OPFS: ready",
      },
      lastAction: "run-gcode",
      error: null,
      overview: expectedWorkflowOverview,
      session: {
        snapshotLabel: "ui-machine-session/ui-machine-session.json",
        workflow: "save-session-snapshot",
        ini: "/work/session-machine.ini",
        parameters: null,
        toolTable: null,
        gcode: "linuxcnc/gcode/ui-session.ngc",
      },
      runReadiness: expectedRunReadinessReport,
      run: {
        status: "ok",
        canonicalEventCount: 2,
        motionSnapshotCount: 2,
        iniWasmPath: null,
      },
    },
  }),
  {
    status: {
      lastAction: "run-gcode",
      error: null,
      runStatus: "ok",
    },
    sections: [
      {
        id: "readiness",
        title: "Readiness",
        rows: [
          { label: "INI", value: "INI WASM: ready" },
          { label: "Interpreter", value: "Interpreter WASM: ready" },
          { label: "OPFS", value: "OPFS: ready" },
        ],
      },
      {
        id: "session",
        title: "Session",
        rows: [
          { label: "Snapshot", value: "ui-machine-session/ui-machine-session.json" },
          { label: "Workflow", value: "save-session-snapshot" },
          { label: "INI", value: "/work/session-machine.ini" },
          { label: "G-code", value: "linuxcnc/gcode/ui-session.ngc" },
        ],
      },
      {
        id: "workflow",
        title: "Workflow",
        rows: [
          { label: "Phase", value: "ran" },
          { label: "Missing", value: null },
          { label: "Last action", value: "run-gcode" },
          { label: "Error", value: null },
        ],
      },
      {
        id: "run",
        title: "Run",
        rows: [
          { label: "Ready", value: "ready" },
          { label: "Button", value: "enabled" },
          { label: "Status", value: "ok" },
          { label: "Canonical events", value: 2 },
          { label: "Motion snapshots", value: 2 },
          { label: "INI WASM", value: null },
        ],
      },
    ],
  },
);

function createElement(tagName) {
  const node = {
    tagName,
    children: [],
    dataset: {},
    textContent: "",
    ownerDocument: null,
    append(...children) {
      this.children.push(...children);
    },
    appendChild(child) {
      this.children.push(child);
      return child;
    },
  };
  node.ownerDocument = { createElement };
  return node;
}

const controlViewContainer = createElement("div");
const renderedControlView = renderMachineSessionControlView(
  controlViewContainer,
  createMachineSessionControlView({
    report: expectedBundleReport,
    workflowStatus: {
      readiness: expectedBundleReport.readiness,
      overview: expectedWorkflowOverview,
      lastAction: "run-gcode",
      error: null,
      session: expectedBundleReport.session,
      runReadiness: expectedBundleReport.runReadiness,
      run: expectedBundleReport.run,
    },
  }),
);

assert.equal(renderedControlView.statusNode.textContent, "run-gcode | ok | -");
assert.equal(renderedControlView.sectionNodes.length, 4);
assert.equal(renderedControlView.sectionNodes[3].dataset.sectionId, "run");
assert.equal(
  renderedControlView.sectionNodes[3].children[1].children[3].textContent,
  "enabled",
);

assert.deepEqual(
  {
    getMachineSessionControlView: typeof globalThis.window?.linuxCncIniPanelApi?.getMachineSessionControlView,
    renderMachineSessionControlView: typeof globalThis.window?.linuxCncIniPanelApi?.renderMachineSessionControlView,
    getMachineSessionStateBundle: typeof globalThis.window?.linuxCncIniPanelApi?.getMachineSessionStateBundle,
    getMachineSessionStateReport: typeof globalThis.window?.linuxCncIniPanelApi?.getMachineSessionStateReport,
    getMachineSessionStateReportExport: typeof globalThis.window?.linuxCncIniPanelApi?.getMachineSessionStateReportExport,
    getMachineSessionWorkflowStatus: typeof globalThis.window?.linuxCncIniPanelApi?.getMachineSessionWorkflowStatus,
  },
  {
    getMachineSessionControlView: "undefined",
    renderMachineSessionControlView: "undefined",
    getMachineSessionStateBundle: "undefined",
    getMachineSessionStateReport: "undefined",
    getMachineSessionStateReportExport: "undefined",
    getMachineSessionWorkflowStatus: "undefined",
  },
);

console.log("ini_panel_state_summary_node_smoke=ok");
