import assert from "node:assert/strict";

import {
  createMachineSessionControlPageController,
} from "../../../runtime/ui/ini-panel/control-page-controller.js";
import {
  controlPageStatusText,
} from "../../../runtime/ui/ini-panel/control-page-refresh-workflow.js";

function createPanelFrame(panelApi = null) {
  const listeners = new Map();
  return {
    contentWindow: panelApi ? { linuxCncIniPanelApi: panelApi } : null,
    src: null,
    addEventListener(type, listener) {
      listeners.set(type, listener);
    },
    dispatch(type) {
      listeners.get(type)?.();
    },
  };
}

const rendered = [];
const viewNode = { textContent: "" };
const statusNode = { textContent: "" };
const expectedView = {
  status: {
    lastAction: "run-gcode",
    runStatus: "ok",
    error: null,
  },
  sections: [
    {
      id: "run",
      rows: [
        { label: "Canonical events", value: 2 },
      ],
    },
  ],
};
const expectedStateBundle = {
  report: {
    readiness: {
      ini: "INI WASM: ready",
    },
  },
};
const expectedWorkflowStatus = {
  lastAction: "run-gcode",
  error: null,
};

let intervalCallback = null;
const panelFrame = createPanelFrame();
const controller = createMachineSessionControlPageController({
  panelFrame,
  statusNode,
  viewNode,
  pollMs: 250,
  setIntervalFn: (callback, ms) => {
    intervalCallback = callback;
    return `timer:${ms}`;
  },
  renderControlView: (container, view) => {
    rendered.push({ container, view });
    return { statusNode: { textContent: "rendered" } };
  },
});

assert.equal(controller.getPanelWindow(), null);
assert.equal(controller.getPanelApi(), null);
assert.equal(controller.getControlView(), null);
assert.equal(controller.render(), null);
assert.equal(statusNode.textContent, "waiting for panel");
assert.equal(viewNode.textContent, "");
assert.equal(controller.startPolling(), "timer:250");
assert.equal(controller.startPolling(), "timer:250");
assert.equal(typeof intervalCallback, "function");

const panelApi = {
  getMachineSessionControlView: () => expectedView,
  getMachineSessionStateBundle: () => expectedStateBundle,
  getMachineSessionWorkflowStatus: () => expectedWorkflowStatus,
};
panelFrame.contentWindow = { linuxCncIniPanelApi: panelApi };

assert.equal(controller.getPanelApi(), panelApi);
assert.equal(controller.getControlView(), expectedView);
assert.deepEqual(controller.readStatus(), {
  stateBundle: expectedStateBundle,
  workflowStatus: expectedWorkflowStatus,
  overview: null,
  controlView: expectedView,
  report: expectedStateBundle.report,
  sessionReadiness: null,
  runReadiness: null,
  run: null,
  session: null,
  status: {
    lastAction: "run-gcode",
    error: null,
    runStatus: null,
  },
});
assert.deepEqual(controller.loadSessionState(), {
  phase: "ready",
  panelReady: true,
  apiReady: true,
  controlViewReady: true,
  stateBundle: expectedStateBundle,
  workflowStatus: expectedWorkflowStatus,
  sessionReadiness: null,
  controlView: expectedView,
  error: null,
});
const renderResult = controller.render();
assert.deepEqual(renderResult, { statusNode: { textContent: "rendered" } });
assert.equal(statusNode.textContent, "run-gcode | ok | -");
assert.deepEqual(rendered, [{ container: viewNode, view: expectedView }]);
const refreshResult = controller.refresh();
assert.equal(refreshResult.phase, "rendered");
assert.equal(refreshResult.statusText, controlPageStatusText(expectedView.status));

const mountedFrame = createPanelFrame(panelApi);
const mountedStatusNode = { textContent: "" };
const mountedViewNode = { textContent: "" };
let mountedIntervalMs = null;
const mountedController = createMachineSessionControlPageController({
  panelFrame: mountedFrame,
  statusNode: mountedStatusNode,
  viewNode: mountedViewNode,
  setIntervalFn: (_callback, ms) => {
    mountedIntervalMs = ms;
    return "mounted-timer";
  },
  renderControlView: () => "mounted-render",
});

assert.equal(mountedController.mount({ panelSrc: "./custom-panel.html" }), mountedController);
assert.equal(mountedFrame.src, "./custom-panel.html");
assert.equal(mountedIntervalMs, 200);
mountedFrame.dispatch("load");
assert.equal(mountedStatusNode.textContent, "run-gcode | ok | -");

assert.throws(
  () => createMachineSessionControlPageController(),
  /panel iframe/,
);

console.log("ini_panel_control_page_controller_node_smoke=ok");
