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

import {
  createControlPageBrowserApiManifest,
  createControlPageBrowserApiMethods,
  createControlPageBrowserApiSchema,
  createIniPanelLaunchApiManifest,
  createIniPanelShellControlPageContract,
  createIniPanelShellViewModel,
  createMachineSessionControlPageController,
  createMachineSessionReadonlyStatusApiManifest,
  loadMachineSessionForControlPageWorkflow,
  readMachineSessionReadonlyStatus,
  refreshMachineSessionControlPage,
  renderMachineSessionControlView,
  isSupportedIniPanelControlPageApiManifest,
} from "../../../runtime/ui/ini-panel/ui-shell.js";

const __dirname = dirname(fileURLToPath(import.meta.url));
const root = resolve(__dirname, "../../..");
const shellText = readFileSync(resolve(root, "runtime/ui/ini-panel/ui-shell.js"), "utf8");
const docText = readFileSync(resolve(root, "docs/panel-entry.md"), "utf8");

const expectedMethodNames = [
  "createController",
  "loadSessionState",
  "readStatus",
  "refresh",
  "renderView",
];

const contract = createIniPanelShellControlPageContract();
const manifest = createMachineSessionReadonlyStatusApiManifest();
const browserApiSchema = createControlPageBrowserApiSchema();
const browserApiManifest = createControlPageBrowserApiManifest();

assert.deepEqual(browserApiSchema, {
  apiName: "ini-panel-control-page",
  manifestVersion: 1,
  fields: [
    "apiName",
    "manifestVersion",
    "methods",
    "contract",
    "readonlyStatusApiManifest",
  ],
});

assert.deepEqual(contract, {
  methodNames: expectedMethodNames,
  readonlyStatusApiManifest: manifest,
  readonlyStatusApiMethodNames: ["readStatus"],
  readonlyStatusApiStatusFields: [
    "stateBundle",
    "workflowStatus",
    "overview",
    "controlView",
    "report",
    "sessionReadiness",
    "runReadiness",
    "run",
    "session",
    "status",
  ],
  relatedControlPageMethods: [
    "loadSessionState",
    "readStatus",
    "refresh",
    "renderView",
  ],
});

assert.deepEqual(browserApiManifest, {
  apiName: "ini-panel-control-page",
  manifestVersion: 1,
  methods: createControlPageBrowserApiMethods(),
  contract,
  readonlyStatusApiManifest: manifest,
});
assert.equal(isSupportedIniPanelControlPageApiManifest(browserApiManifest), true);
assert.equal(isSupportedIniPanelControlPageApiManifest({ ...browserApiManifest, manifestVersion: 2 }), false);
assert.equal(isSupportedIniPanelControlPageApiManifest({ ...browserApiManifest, apiName: "other" }), false);
const missingReadonlyManifest = { ...browserApiManifest };
delete missingReadonlyManifest.readonlyStatusApiManifest;
assert.equal(isSupportedIniPanelControlPageApiManifest(missingReadonlyManifest), false);
assert.equal(isSupportedIniPanelControlPageApiManifest(null), false);

const shellViewModel = createIniPanelShellViewModel();
assert.deepEqual(shellViewModel.launchApiManifest, createIniPanelLaunchApiManifest());
assert.deepEqual(Object.keys(shellViewModel.controlPage), [
  "browserApiSchema",
  "browserApiManifest",
  "browserApiMethods",
  "contract",
  "createController",
  "isSupportedBrowserApiManifest",
  "loadSessionState",
  "readonlyStatusApiManifest",
  "readStatus",
  "refresh",
  "renderView",
]);
assert.deepEqual(shellViewModel.controlPage.browserApiSchema, browserApiSchema);
assert.deepEqual(shellViewModel.controlPage.browserApiManifest, browserApiManifest);
assert.deepEqual(shellViewModel.controlPage.browserApiMethods, createControlPageBrowserApiMethods());
assert.deepEqual(shellViewModel.controlPage.contract, contract);
assert.deepEqual(shellViewModel.controlPage.readonlyStatusApiManifest, manifest);
assert.equal(shellViewModel.controlPage.createController, createMachineSessionControlPageController);
assert.equal(shellViewModel.controlPage.isSupportedBrowserApiManifest, isSupportedIniPanelControlPageApiManifest);
assert.equal(shellViewModel.controlPage.loadSessionState, loadMachineSessionForControlPageWorkflow);
assert.equal(shellViewModel.controlPage.readStatus, readMachineSessionReadonlyStatus);
assert.equal(shellViewModel.controlPage.refresh, refreshMachineSessionControlPage);
assert.equal(shellViewModel.controlPage.renderView, renderMachineSessionControlView);

for (const methodName of contract.methodNames) {
  assert.equal(typeof shellViewModel.controlPage[methodName], "function");
  assert.match(docText, new RegExp(`\\b${methodName}\\b`));
}

for (const fieldName of contract.readonlyStatusApiStatusFields) {
  assert.match(docText, new RegExp(`\\b${fieldName}\\b`));
}

assert.match(shellText, /\bexport function createIniPanelShellControlPageContract\b/);
assert.match(shellText, /\bexport function createControlPageBrowserApiManifest\b/);
assert.match(shellText, /\bexport function createControlPageBrowserApiMethods\b/);
assert.match(shellText, /\bexport function createControlPageBrowserApiSchema\b/);
assert.match(shellText, /\bexport function isSupportedIniPanelControlPageApiManifest\b/);
assert.match(docText, /\bcreateIniPanelShellControlPageContract\b/);
assert.match(docText, /\bcreateControlPageBrowserApiManifest\b/);
assert.match(docText, /\bcreateControlPageBrowserApiSchema\b/);
assert.match(docText, /\bisSupportedIniPanelControlPageApiManifest\b/);
assert.match(docText, /\bcontrolPage\.contract\b/);
assert.doesNotMatch(shellText, /\bparseGcode\b|\bcanonicalEvents\b|\btoolTable\b|\bplanner\b/);

console.log("ini_panel_shell_control_page_contract_node_smoke=ok");
