#!/usr/bin/env node
"use strict";

const fs = require("node:fs/promises");
const path = require("node:path");
const { chromium } = require("playwright");
const {
  BASE_URL,
  UI_TIMEOUT_MS,
  assert,
  cleanupDocuments,
  createTempDocument,
  ensureAuthenticated,
  openDocument,
  renameDocument,
} = require("./tree-shell-smoke-helpers");

const TASK = "task167-mindmap-kmind-parity-smoke";
const OUTPUT_DIR = path.join(process.cwd(), "tmp", TASK);
const RESULT_PATH = path.join(OUTPUT_DIR, "result.json");
const STAGE = process.argv.includes("--stage") ? process.argv[process.argv.indexOf("--stage") + 1] : "all";

async function writeResult(payload) {
  await fs.mkdir(OUTPUT_DIR, { recursive: true });
  await fs.writeFile(RESULT_PATH, `${JSON.stringify({ ...payload, resultPath: RESULT_PATH }, null, 2)}\n`, "utf8");
}

async function screenshot(page, name) {
  const file = path.join(OUTPUT_DIR, `${name}.png`);
  await page.screenshot({ path: file, fullPage: true });
  return file;
}

async function insertMindmapThroughSlash(page) {
  const editor = page
    .locator('[data-testid="mnote-leptos-tiptap-island-editor-root"] .editor-surface .ProseMirror[contenteditable="true"]')
    .first();
  await editor.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
  await editor.click({ timeout: UI_TIMEOUT_MS });
  await page.keyboard.type("/");
  const item = page.getByTestId("slash-item-mindmap").first();
  await item.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
  await item.click({ timeout: UI_TIMEOUT_MS });
}

async function assertMindmapReady(page, stage) {
  await page.locator('[data-testid="mnote-mindmap-editor-root"]').waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
  await page.locator('[data-testid="simple-mind-map-runtime"]').waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const root = document.querySelector('[data-testid="mnote-mindmap-editor-root"]');
      const runtime = document.querySelector('[data-testid="simple-mind-map-runtime"]');
      const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
      const mindmapId = root instanceof HTMLElement ? root.dataset.mnoteMindmapId || null : null;
      const registry = window.__MNOTE_LEPTOS_MINDMAP_BRIDGES__ || {};
      const bridge = mindmapId ? registry[mindmapId] : null;
      return (
        runtime instanceof HTMLElement &&
        runtime.dataset.runtimeEngine === "simple-mind-map" &&
        runtime.dataset.runtimeReady === "true" &&
        shell instanceof HTMLElement &&
        shell.dataset.uiShellSource === "leptos-rust-shell" &&
        Boolean(bridge)
      );
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  ).catch((error) => {
    throw new Error(`mindmap_not_ready:${stage}:${error.message}`);
  });
}

async function readMindmapIdentity(page) {
  return page.evaluate(() => {
    const root = document.querySelector('[data-testid="mnote-mindmap-editor-root"]');
    return {
      mindmapId: root instanceof HTMLElement ? root.dataset.mnoteMindmapId || null : null,
    };
  });
}

async function readToolbarMetrics(page) {
  return page.evaluate(() => {
    const toolbar = document.querySelector('[data-testid="mindmap-schema-toolbar"]');
    const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
    const mainCluster = document.querySelector('[data-testid="mindmap-schema-toolbar-cluster-main"]');
    const fileCluster = document.querySelector('[data-testid="mindmap-schema-toolbar-cluster-file"]');
    const moreButton = document.querySelector('[data-testid="mindmap-schema-toolbar-action-more"]');
    const moreMenu = document.querySelector('[data-testid="mindmap-schema-toolbar-more-menu"]');
    const buttons = Array.from(document.querySelectorAll('[data-testid^="mindmap-schema-toolbar-action-"]')).filter(
      (node) => node instanceof HTMLElement && node.getBoundingClientRect().width > 0,
    );
    const rect = toolbar instanceof HTMLElement ? toolbar.getBoundingClientRect() : null;
    const topValues = buttons.map((node) => Math.round(node.getBoundingClientRect().top));
    return {
      toolbarExists: toolbar instanceof HTMLElement,
      shellExists: shell instanceof HTMLElement,
      height: rect ? rect.height : 0,
      width: rect ? rect.width : 0,
      toolbarRows: new Set(topValues).size,
      visibleActions:
        shell instanceof HTMLElement && shell.dataset.toolbarVisibleActions
          ? shell.dataset.toolbarVisibleActions.split(",").filter(Boolean)
          : [],
      overflowActions:
        shell instanceof HTMLElement && shell.dataset.toolbarOverflowActions
          ? shell.dataset.toolbarOverflowActions.split(",").filter(Boolean)
          : [],
      moreOpen: shell instanceof HTMLElement ? shell.dataset.toolbarMoreOpen === "true" : false,
      mainCluster: mainCluster instanceof HTMLElement,
      fileCluster: fileCluster instanceof HTMLElement,
      moreButton: moreButton instanceof HTMLButtonElement,
      moreMenu: moreMenu instanceof HTMLElement,
      labels: buttons.map((node) => (node.textContent || "").trim()),
      iconKeys: buttons.map((node) => (node instanceof HTMLElement ? node.dataset.iconKey || null : null)),
    };
  });
}

async function verifyToolbarStage(page) {
  await page.setViewportSize({ width: 1440, height: 960 });
  const desktopMetrics = await readToolbarMetrics(page);
  assert(desktopMetrics.toolbarExists, "toolbar_missing");
  assert(desktopMetrics.shellExists, "rust_shell_missing");
  assert(desktopMetrics.mainCluster, "toolbar_main_cluster_missing");
  assert(desktopMetrics.fileCluster, "toolbar_file_cluster_missing");
  assert(desktopMetrics.height <= 72, `toolbar_height_too_large:${desktopMetrics.height}`);
  assert(desktopMetrics.toolbarRows <= 1, `toolbar_not_single_row:${desktopMetrics.toolbarRows}`);
  assert(
    desktopMetrics.visibleActions.join(",").startsWith("undo,redo,editNode,insertSiblingAfter,deleteNode,insertChild"),
    "toolbar_order_unexpected",
  );
  assert(desktopMetrics.labels.every((label) => !/(palette|sliders|layout)/i.test(label)), "toolbar_internal_icon_key_visible");

  await page.setViewportSize({ width: 900, height: 760 });
  await page.waitForTimeout(500);
  const narrowMetrics = await readToolbarMetrics(page);
  assert(narrowMetrics.height <= 72, `narrow_toolbar_height_too_large:${narrowMetrics.height}`);
  assert(narrowMetrics.toolbarRows <= 1, `narrow_toolbar_not_single_row:${narrowMetrics.toolbarRows}`);
  assert(narrowMetrics.overflowActions.length > 0, "narrow_toolbar_overflow_missing");
  assert(narrowMetrics.moreButton, "toolbar_more_button_missing");
  await page.getByTestId("mindmap-schema-toolbar-action-more").click({ timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
      const menu = document.querySelector('[data-testid="mindmap-schema-toolbar-more-menu"]');
      return shell instanceof HTMLElement && shell.dataset.toolbarMoreOpen === "true" && menu instanceof HTMLElement;
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const menuMetrics = await readToolbarMetrics(page);
  assert(menuMetrics.moreOpen, "toolbar_more_not_open");
  assert(menuMetrics.moreMenu, "toolbar_more_menu_missing");
  await page.keyboard.press("Escape");
  await page.waitForFunction(
    () => {
      const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
      const menu = document.querySelector('[data-testid="mindmap-schema-toolbar-more-menu"]');
      return shell instanceof HTMLElement && shell.dataset.toolbarMoreOpen === "false" && !(menu instanceof HTMLElement);
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const closedMetrics = await readToolbarMetrics(page);
  assert(!closedMetrics.moreOpen, "toolbar_more_escape_not_closed");
  return {
    desktop: desktopMetrics,
    narrow: narrowMetrics,
    menu: menuMetrics,
    closed: closedMetrics,
  };
}

async function verifyFullscreenStage(page) {
  await page.setViewportSize({ width: 1440, height: 960 });
  await page.waitForTimeout(200);
  const before = await readToolbarMetrics(page);
  assert(before.toolbarExists, "toolbar_missing_before_fullscreen");
  const root = page.getByTestId("mnote-mindmap-editor-root");
  const rootBox = await root.boundingBox();
  assert(rootBox && rootBox.width > 0 && rootBox.height > 0, "fullscreen_root_box_missing");
  const fullscreenButton = page.getByTestId("mindmap-schema-navigator-action-fullscreenCanvas");
  await fullscreenButton.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
  await fullscreenButton.click({ timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const root = document.querySelector('[data-testid="mnote-mindmap-editor-root"]');
      const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
      const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
      return (
        root instanceof HTMLElement &&
        shell instanceof HTMLElement &&
        scene instanceof HTMLElement &&
        (document.fullscreenElement === root || root.contains(document.fullscreenElement)) &&
        shell.dataset.fullscreenActive === "true" &&
        scene.dataset.fullscreenActive === "true"
      );
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  await page.waitForFunction(
    () => {
      const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
      return scene instanceof HTMLElement && scene.dataset.fullscreenResizeStatus === "success";
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const active = await page.evaluate(() => {
    const root = document.querySelector('[data-testid="mnote-mindmap-editor-root"]');
    const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
    const toolbar = document.querySelector('[data-testid="mindmap-schema-toolbar"]');
    const sidebar = document.querySelector('[data-testid="mindmap-schema-sidebar"]');
    const navigator = document.querySelector('[data-testid="mindmap-schema-navigator"]');
    return {
      fullscreenElementIsRoot: root instanceof HTMLElement && document.fullscreenElement === root,
      fullscreenElementInsideRoot:
        root instanceof HTMLElement && Boolean(document.fullscreenElement) && root.contains(document.fullscreenElement),
      shellFullscreenActive: shell instanceof HTMLElement ? shell.dataset.fullscreenActive === "true" : false,
      toolbarVisible: toolbar instanceof HTMLElement && toolbar.getBoundingClientRect().height > 0,
      sidebarVisible: sidebar instanceof HTMLElement && sidebar.getBoundingClientRect().height > 0,
      navigatorVisible: navigator instanceof HTMLElement && navigator.getBoundingClientRect().height > 0,
    };
  });
  assert(active.fullscreenElementIsRoot || active.fullscreenElementInsideRoot, "fullscreen_element_unexpected");
  assert(active.shellFullscreenActive, "fullscreen_shell_state_missing");
  assert(active.toolbarVisible && active.sidebarVisible && active.navigatorVisible, "fullscreen_chrome_not_visible");
  await page.keyboard.press("Escape");
  await page.waitForFunction(() => document.fullscreenElement === null, null, { timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
      return shell instanceof HTMLElement && shell.dataset.fullscreenActive === "false";
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const after = await page.evaluate(() => {
    const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
    return {
      fullscreenElement: document.fullscreenElement === null,
      shellFullscreenActive: shell instanceof HTMLElement ? shell.dataset.fullscreenActive === "true" : null,
      chromeVisibility: shell instanceof HTMLElement ? shell.dataset.chromeVisibility || null : null,
    };
  });
  assert(after.fullscreenElement, "fullscreen_escape_exit_failed");
  assert(after.shellFullscreenActive === false, "fullscreen_shell_state_not_restored");
  assert(after.chromeVisibility === "visible", `fullscreen_visible_state_not_restored:${after.chromeVisibility}`);

  await page.mouse.move(rootBox.x + rootBox.width / 2, rootBox.y + rootBox.height / 2);
  await page.mouse.move(Math.max(4, rootBox.x - 24), Math.max(4, rootBox.y - 24));
  await page.waitForFunction(
    () => {
      const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
      return shell instanceof HTMLElement && shell.dataset.chromeVisibility === "hiddenByPointerLeave";
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  await page.evaluate(async () => {
    const root = document.querySelector('[data-testid="mnote-mindmap-editor-root"]');
    if (root instanceof HTMLElement && typeof root.requestFullscreen === "function") {
      await root.requestFullscreen();
    }
  });
  await page.waitForFunction(
    () => {
      const root = document.querySelector('[data-testid="mnote-mindmap-editor-root"]');
      return root instanceof HTMLElement && document.fullscreenElement === root;
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  await page.evaluate(async () => {
    if (document.fullscreenElement) {
      await document.exitFullscreen();
    }
  });
  await page.waitForFunction(() => document.fullscreenElement === null, null, { timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
      return shell instanceof HTMLElement && shell.dataset.fullscreenActive === "false";
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const hiddenAfterExit = await page.evaluate(() => {
    const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
    return {
      chromeVisibility: shell instanceof HTMLElement ? shell.dataset.chromeVisibility || null : null,
      shellFullscreenActive: shell instanceof HTMLElement ? shell.dataset.fullscreenActive === "true" : null,
    };
  });
  assert(hiddenAfterExit.shellFullscreenActive === false, "fullscreen_hidden_shell_state_not_restored");
  assert(
    hiddenAfterExit.chromeVisibility === "hiddenByPointerLeave",
    `fullscreen_hidden_state_unexpected:${hiddenAfterExit.chromeVisibility}`,
  );
  return { before, active, after, hiddenAfterExit };
}

async function readChromeVisibilityMetrics(page) {
  return page.evaluate(() => {
    const root = document.querySelector('[data-testid="mnote-mindmap-editor-root"]');
    const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
    const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
    const toolbar = document.querySelector('[data-testid="mindmap-schema-toolbar"]');
    const sidebar = document.querySelector('[data-testid="mindmap-schema-sidebar"]');
    const navigator = document.querySelector('[data-testid="mindmap-schema-navigator"]');
    const minimap = document.querySelector('[data-testid="mindmap-schema-minimap"]');
    return {
      rootBox: root instanceof HTMLElement ? root.getBoundingClientRect().toJSON?.() ?? null : null,
      sceneChromeVisibility: scene instanceof HTMLElement ? scene.dataset.chromeVisibility || null : null,
      shellChromeVisibility: shell instanceof HTMLElement ? shell.dataset.chromeVisibility || null : null,
      toolbarVisible: toolbar instanceof HTMLElement && toolbar.getBoundingClientRect().height > 0,
      sidebarVisible: sidebar instanceof HTMLElement && sidebar.getBoundingClientRect().height > 0,
      navigatorVisible: navigator instanceof HTMLElement && navigator.getBoundingClientRect().height > 0,
      minimapVisible: minimap instanceof HTMLElement && minimap.getBoundingClientRect().height > 0,
    };
  });
}

async function verifyChromeHideStage(page) {
  const root = page.getByTestId("mnote-mindmap-editor-root");
  await root.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
  const box = await root.boundingBox();
  assert(box && box.width > 0 && box.height > 0, "mindmap_root_box_missing");

  await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
  await page.waitForFunction(
    () => {
      const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
      return shell instanceof HTMLElement && shell.dataset.chromeVisibility === "visible";
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const before = await readChromeVisibilityMetrics(page);
  assert(before.toolbarVisible && before.sidebarVisible && before.navigatorVisible, "chrome_not_visible_before_leave");

  await page.mouse.move(Math.max(4, box.x - 24), Math.max(4, box.y - 24));
  await page.waitForFunction(
    () => {
      const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
      return shell instanceof HTMLElement && shell.dataset.chromeVisibility === "hiddenByPointerLeave";
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const hidden = await readChromeVisibilityMetrics(page);
  assert(!hidden.toolbarVisible && !hidden.sidebarVisible && !hidden.navigatorVisible, "chrome_not_hidden_after_leave");

  await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
  await page.waitForTimeout(300);
  const afterEnter = await readChromeVisibilityMetrics(page);
  assert(afterEnter.shellChromeVisibility === "hiddenByPointerLeave", "chrome_restored_by_pointer_enter");

  await page.mouse.click(box.x + box.width / 2, box.y + box.height / 2);
  await page.waitForFunction(
    () => {
      const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
      return shell instanceof HTMLElement && shell.dataset.chromeVisibility === "visible";
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const restored = await readChromeVisibilityMetrics(page);
  assert(restored.toolbarVisible && restored.sidebarVisible && restored.navigatorVisible, "chrome_not_restored_after_click");
  return { before, hidden, afterEnter, restored };
}

async function readContextMenuMetrics(page) {
  return page.evaluate(() => {
    const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
    const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
    const menu = document.querySelector('[data-testid="mindmap-schema-context-menu"]');
    const buttons = Array.from(
      document.querySelectorAll('[data-testid^="mindmap-schema-context-menu-action-"]'),
    ).filter((node) => node instanceof HTMLButtonElement);
    return {
      chromeVisibility: shell instanceof HTMLElement ? shell.dataset.chromeVisibility || null : null,
      contextMenuKind: scene instanceof HTMLElement ? scene.dataset.contextMenuKind || null : null,
      menuVisible: menu instanceof HTMLElement && menu.getBoundingClientRect().width > 0,
      itemIds: buttons.map((button) => button.dataset.mindmapContextActionId || null),
      disabledIds: buttons
        .filter((button) => button.disabled || button.dataset.disabled === "true")
        .map((button) => button.dataset.mindmapContextActionId || null),
    };
  });
}

async function findCanvasEmptyPoint(page) {
  const point = await page.evaluate(() => {
    const root = document.querySelector('[data-testid="mnote-mindmap-editor-root"]');
    if (!(root instanceof HTMLElement)) return null;
    const rootRect = root.getBoundingClientRect();
    const blockers = Array.from(
      document.querySelectorAll(
        '.smm-node,[data-testid="mindmap-schema-toolbar"],[data-testid="mindmap-schema-sidebar"],[data-testid="mindmap-schema-navigator"],[data-testid="mindmap-schema-context-menu"]',
      ),
    )
      .filter((node) => node instanceof HTMLElement)
      .map((node) => node.getBoundingClientRect())
      .filter((rect) => rect.width > 0 && rect.height > 0);
    const padding = 36;
    for (let y = rootRect.top + padding; y < rootRect.bottom - padding; y += 24) {
      for (let x = rootRect.left + padding; x < rootRect.right - padding; x += 24) {
        const blocked = blockers.some((rect) => x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom);
        if (!blocked) return { x, y };
      }
    }
    return {
      x: rootRect.left + rootRect.width * 0.5,
      y: rootRect.top + rootRect.height * 0.75,
    };
  });
  assert(point && typeof point.x === "number" && typeof point.y === "number", "context_menu_canvas_point_missing");
  return point;
}

async function verifyContextMenuStage(page) {
  const rootNode = page.locator(".smm-node").first();
  await rootNode.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
  await rootNode.click({ button: "right", timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const menu = document.querySelector('[data-testid="mindmap-schema-context-menu"]');
      const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
      return (
        menu instanceof HTMLElement &&
        scene instanceof HTMLElement &&
        scene.dataset.contextMenuKind === "node"
      );
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const nodeMenu = await readContextMenuMetrics(page);
  assert(nodeMenu.menuVisible, "node_context_menu_not_visible");
  assert(nodeMenu.contextMenuKind === "node", `node_context_menu_kind_unexpected:${nodeMenu.contextMenuKind}`);
  assert(
    nodeMenu.itemIds.join(",") === "insertChild,insertSiblingAfter,deleteNode,summary,associativeLine,expandCollapse,copyNodeText",
    `node_context_menu_items_unexpected:${nodeMenu.itemIds.join(",")}`,
  );
  assert(nodeMenu.disabledIds.includes("deleteNode"), `root_delete_not_disabled:${nodeMenu.disabledIds.join(",")}`);

  const rootBox = await page.getByTestId("mnote-mindmap-editor-root").boundingBox();
  assert(rootBox && rootBox.width > 0 && rootBox.height > 0, "context_menu_root_box_missing");
  await page.mouse.move(Math.max(4, rootBox.x - 24), Math.max(4, rootBox.y - 24));
  await page.waitForTimeout(250);
  const afterLeave = await readContextMenuMetrics(page);
  assert(afterLeave.menuVisible, "context_menu_closed_after_pointerleave");
  assert(afterLeave.chromeVisibility === "visible", `chrome_hidden_while_context_menu_open:${afterLeave.chromeVisibility}`);

  await page.keyboard.press("Escape");
  await page.waitForFunction(
    () => !(document.querySelector('[data-testid="mindmap-schema-context-menu"]') instanceof HTMLElement),
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const afterEscape = await readContextMenuMetrics(page);
  assert(!afterEscape.menuVisible, "context_menu_escape_not_closed");

  const point = await findCanvasEmptyPoint(page);
  await page.mouse.click(point.x, point.y, { button: "right" });
  await page.waitForFunction(
    () => {
      const menu = document.querySelector('[data-testid="mindmap-schema-context-menu"]');
      const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
      return (
        menu instanceof HTMLElement &&
        scene instanceof HTMLElement &&
        scene.dataset.contextMenuKind === "canvas"
      );
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const canvasMenu = await readContextMenuMetrics(page);
  assert(canvasMenu.contextMenuKind === "canvas", `canvas_context_menu_kind_unexpected:${canvasMenu.contextMenuKind}`);
  assert(
    canvasMenu.itemIds.join(",") === "centerRoot,fitView,search,readonly,showMenu",
    `canvas_context_menu_items_unexpected:${canvasMenu.itemIds.join(",")}`,
  );
  assert(!canvasMenu.itemIds.includes("insertChild"), "canvas_context_menu_contains_insert_child");
  assert(!canvasMenu.itemIds.includes("deleteNode"), "canvas_context_menu_contains_delete_node");

  return { nodeMenu, afterLeave, afterEscape, canvasMenu };
}

async function readThemeMetrics(page) {
  return page.evaluate(() => {
    const root = document.querySelector('[data-testid="mnote-mindmap-editor-root"]');
    const runtime = document.querySelector('[data-testid="simple-mind-map-runtime"]');
    const mindmapId = root instanceof HTMLElement ? root.dataset.mnoteMindmapId || null : null;
    const registry = window.__MNOTE_LEPTOS_MINDMAP_BRIDGES__ || {};
    const bridge = mindmapId ? registry[mindmapId] : null;
    const instance = bridge?.instance || null;
    const themeConfig = typeof instance?.getThemeConfig === "function" ? instance.getThemeConfig() : null;
    const nodeRects = Array.from(document.querySelectorAll(".smm-node"))
      .filter((node) => node instanceof Element)
      .map((node) => node.getBoundingClientRect())
      .filter((rect) => rect.width > 0 && rect.height > 0)
      .map((rect) => ({
        left: rect.left,
        top: rect.top,
        right: rect.right,
        bottom: rect.bottom,
        width: rect.width,
        height: rect.height,
      }));
    const paths = Array.from(runtime?.querySelectorAll?.("svg path") || []).filter(
      (node) => node instanceof SVGPathElement && node.getBoundingClientRect().width + node.getBoundingClientRect().height > 0,
    );
    let overlaps = 0;
    for (let i = 0; i < nodeRects.length; i += 1) {
      for (let j = i + 1; j < nodeRects.length; j += 1) {
        const a = nodeRects[i];
        const b = nodeRects[j];
        const width = Math.max(0, Math.min(a.right, b.right) - Math.max(a.left, b.left));
        const height = Math.max(0, Math.min(a.bottom, b.bottom) - Math.max(a.top, b.top));
        if (width * height > 4) overlaps += 1;
      }
    }
    return {
      layout: typeof instance?.getLayout === "function" ? instance.getLayout() : null,
      theme: typeof instance?.getTheme === "function" ? instance.getTheme() : null,
      themeConfig,
      nodeCount: nodeRects.length,
      pathCount: paths.length,
      overlaps,
    };
  });
}

async function verifyThemeStage(page) {
  const initial = await readThemeMetrics(page);
  assert(initial.layout === "logicalStructure", `theme_layout_unexpected:${initial.layout}`);
  assert(initial.theme === "default", `theme_template_unexpected:${initial.theme}`);
  assert(initial.themeConfig?.root?.fillColor === "#e25563", `theme_root_fill_unexpected:${initial.themeConfig?.root?.fillColor}`);
  assert(initial.themeConfig?.root?.color === "#ffffff", `theme_root_color_unexpected:${initial.themeConfig?.root?.color}`);
  assert(initial.themeConfig?.second?.fillColor === "#4f7df3", `theme_second_fill_unexpected:${initial.themeConfig?.second?.fillColor}`);
  assert(initial.themeConfig?.second?.color === "#ffffff", `theme_second_color_unexpected:${initial.themeConfig?.second?.color}`);
  assert(initial.themeConfig?.node?.color === "#315aa9", `theme_node_color_unexpected:${initial.themeConfig?.node?.color}`);
  assert(
    initial.themeConfig?.generalizationLineColor === "#ef6a5b",
    `theme_generalization_line_unexpected:${initial.themeConfig?.generalizationLineColor}`,
  );
  assert(initial.themeConfig?.lineStyle === "curve", `theme_line_style_unexpected:${initial.themeConfig?.lineStyle}`);
  assert(initial.nodeCount >= 2, `theme_node_count_too_small:${initial.nodeCount}`);
  assert(initial.pathCount > 0, `theme_path_count_empty:${initial.pathCount}`);
  assert(initial.overlaps === 0, `theme_nodes_overlap:${initial.overlaps}`);

  return { initial };
}

async function readSidebarMetrics(page) {
  return page.evaluate(() => {
    const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
    const rail = document.querySelector('[data-testid="mindmap-schema-sidebar-rail"]');
    const drawer = document.querySelector('[data-testid="mindmap-schema-sidebar-drawer"]');
    const title = document.querySelector('[data-testid="mindmap-schema-sidebar-title"]');
    const closeButton = document.querySelector('[data-testid="mindmap-schema-sidebar-close"]');
    const hideHandle = document.querySelector('[data-testid="mindmap-schema-sidebar-hide-handle"]');
    const restoreHandle = document.querySelector('[data-testid="mindmap-schema-sidebar-restore-handle"]');
    const structureCards = Array.from(
      document.querySelectorAll('[data-testid^="mindmap-schema-sidebar-option-layout-"][data-control-type="layoutCard"]'),
    );
    return {
      triggerVisible: shell instanceof HTMLElement ? shell.dataset.sidebarTriggerVisible === "true" : null,
      panelOpen: shell instanceof HTMLElement ? shell.dataset.sidebarPanelOpen === "true" : null,
      railVisible: rail instanceof HTMLElement && rail.getBoundingClientRect().height > 0,
      drawerVisible: drawer instanceof HTMLElement && drawer.getBoundingClientRect().width > 0,
      drawerWidth: drawer instanceof HTMLElement ? Math.round(drawer.getBoundingClientRect().width) : 0,
      title: title instanceof HTMLElement ? (title.textContent || "").trim() : "",
      closeButton: closeButton instanceof HTMLButtonElement,
      hideHandle: hideHandle instanceof HTMLButtonElement,
      restoreHandle: restoreHandle instanceof HTMLButtonElement,
      structureCardCount: structureCards.length,
    };
  });
}

async function verifySidebarStage(page) {
  const structureTab = page.getByTestId("mindmap-schema-sidebar-tab-structure");
  await structureTab.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
  await structureTab.click({ timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
      const title = document.querySelector('[data-testid="mindmap-schema-sidebar-title"]');
      return (
        shell instanceof HTMLElement &&
        shell.dataset.sidebarPanelOpen === "true" &&
        shell.dataset.sidebarActivePanel === "structure" &&
        title instanceof HTMLElement &&
        (title.textContent || "").trim() === "结构"
      );
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const opened = await readSidebarMetrics(page);
  assert(opened.railVisible, "sidebar_rail_missing");
  assert(opened.drawerVisible, "sidebar_drawer_not_visible");
  assert(opened.drawerWidth >= 280, `sidebar_drawer_width_too_small:${opened.drawerWidth}`);
  assert(opened.title === "结构", `sidebar_title_unexpected:${opened.title}`);
  assert(opened.structureCardCount >= 6, `sidebar_structure_cards_missing:${opened.structureCardCount}`);
  assert(opened.closeButton, "sidebar_close_button_missing");
  assert(opened.hideHandle, "sidebar_hide_handle_missing");

  await page.getByTestId("mindmap-schema-sidebar-close").click({ timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
      const drawer = document.querySelector('[data-testid="mindmap-schema-sidebar-drawer"]');
      return shell instanceof HTMLElement && shell.dataset.sidebarPanelOpen === "false" && !(drawer instanceof HTMLElement);
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const closed = await readSidebarMetrics(page);
  assert(closed.panelOpen === false, "sidebar_close_not_applied");

  await structureTab.click({ timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
      return shell instanceof HTMLElement && shell.dataset.sidebarPanelOpen === "true";
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  await page.getByTestId("mindmap-schema-sidebar-hide-handle").click({ timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
      const restoreHandle = document.querySelector('[data-testid="mindmap-schema-sidebar-restore-handle"]');
      return (
        shell instanceof HTMLElement &&
        shell.dataset.sidebarTriggerVisible === "false" &&
        shell.dataset.sidebarPanelOpen === "false" &&
        restoreHandle instanceof HTMLButtonElement
      );
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const hidden = await readSidebarMetrics(page);
  assert(hidden.restoreHandle, "sidebar_restore_handle_missing");
  assert(hidden.triggerVisible === false, "sidebar_trigger_not_hidden");

  await page.getByTestId("mindmap-schema-sidebar-restore-handle").click({ timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
      const title = document.querySelector('[data-testid="mindmap-schema-sidebar-title"]');
      return (
        shell instanceof HTMLElement &&
        shell.dataset.sidebarTriggerVisible === "true" &&
        shell.dataset.sidebarPanelOpen === "true" &&
        title instanceof HTMLElement &&
        (title.textContent || "").trim() === "结构"
      );
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const restored = await readSidebarMetrics(page);
  assert(restored.drawerVisible, "sidebar_drawer_not_restored");
  return { opened, closed, hidden, restored };
}

async function readRuntimeMindmapState(page) {
  return page.evaluate(() => {
    const root = document.querySelector('[data-testid="mnote-mindmap-editor-root"]');
    const mindmapId = root instanceof HTMLElement ? root.dataset.mnoteMindmapId || null : null;
    const registry = window.__MNOTE_LEPTOS_MINDMAP_BRIDGES__ || {};
    const bridge = mindmapId ? registry[mindmapId] : null;
    const instance = bridge?.instance || null;
    const snapshot = bridge?.getSnapshot?.() || null;
    const data = snapshot && typeof snapshot === "object" && !Array.isArray(snapshot) ? snapshot.data || null : null;
    return {
      mindmapId,
      layout: typeof instance?.getLayout === "function" ? instance.getLayout() : null,
      theme: typeof instance?.getTheme === "function" ? instance.getTheme() : null,
      rootFillColor: data && typeof data === "object" ? data.fillColor || null : null,
      commandStatus:
        document.querySelector('[data-testid="leptos-mindmap-island"]') instanceof HTMLElement
          ? document.querySelector('[data-testid="leptos-mindmap-island"]').dataset.commandStatus || null
          : null,
    };
  });
}

async function readPersistedMindmapState(page) {
  return page.evaluate(async () => {
    const root = document.querySelector('[data-testid="mnote-mindmap-editor-root"]');
    const mindmapId = root instanceof HTMLElement ? root.dataset.mnoteMindmapId || null : null;
    const match = window.location.pathname.match(/\/documents\/([^/?#]+)/);
    const documentId = match?.[1] ? decodeURIComponent(match[1]) : null;
    if (!documentId || !mindmapId) {
      return {
        documentId,
        mindmapId,
        status: null,
        layout: null,
        theme: null,
        rootFillColor: null,
      };
    }
    const response = await fetch(
      `/api/mindmap/${encodeURIComponent(documentId)}/${encodeURIComponent(mindmapId)}?view=simple_mind_map_scene&queryName=mindmap.simple_mind_map_scene.get`,
      { headers: { Accept: "application/json" } },
    );
    const payload = await response.json().catch(() => null);
    const rootData =
      payload && typeof payload === "object" && payload.root && typeof payload.root === "object" && !Array.isArray(payload.root)
        ? payload.root.data || null
        : null;
    return {
      documentId,
      mindmapId,
      status: response.status,
      layout: payload && typeof payload === "object" ? payload.layout || null : null,
      theme: payload && typeof payload === "object" ? payload.theme || null : null,
      rootFillColor: rootData && typeof rootData === "object" ? rootData.fillColor || null : null,
    };
  });
}

async function waitForMindmapCommandSuccess(page, actionId, predicate) {
  try {
    await page.waitForFunction(
      ({ actionId }) => {
        const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
        return (
          scene instanceof HTMLElement &&
          scene.dataset.lastSchemaAction === actionId &&
          scene.dataset.commandStatus === "success"
        );
      },
      { actionId },
      { timeout: UI_TIMEOUT_MS },
    );
  } catch (error) {
    const debug = await page.evaluate(() => {
      const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
      const errorNode = document.querySelector('[data-testid="leptos-mindmap-error"]');
      return {
        commandStatus: scene instanceof HTMLElement ? scene.dataset.commandStatus || null : null,
        lastSchemaAction: scene instanceof HTMLElement ? scene.dataset.lastSchemaAction || null : null,
        commandFailedAction: scene instanceof HTMLElement ? scene.dataset.commandFailedAction || null : null,
        commandFailedMessage: scene instanceof HTMLElement ? scene.dataset.commandFailedMessage || null : null,
        errorText: errorNode instanceof HTMLElement ? (errorNode.textContent || "").trim() : null,
      };
    });
    throw new Error(
      `mindmap_command_not_success:${actionId}:${JSON.stringify(debug)}:${error instanceof Error ? error.message : String(error)}`,
    );
  }
  if (predicate) {
    await page.waitForFunction(predicate, null, { timeout: UI_TIMEOUT_MS });
  }
}

async function verifySidebarActionsStage(page) {
  await page.getByTestId("mindmap-schema-sidebar-tab-structure").click({ timeout: UI_TIMEOUT_MS });
  await page.getByTestId("mindmap-schema-sidebar-option-layout-mind-map").click({ timeout: UI_TIMEOUT_MS });
  await waitForMindmapCommandSuccess(
    page,
    "setLayout",
    () => {
      const root = document.querySelector('[data-testid="mnote-mindmap-editor-root"]');
      const mindmapId = root instanceof HTMLElement ? root.dataset.mnoteMindmapId || null : null;
      const registry = window.__MNOTE_LEPTOS_MINDMAP_BRIDGES__ || {};
      const bridge = mindmapId ? registry[mindmapId] : null;
      return bridge?.instance?.getLayout?.() === "mindMap";
    },
  );

  await page.getByTestId("mindmap-schema-sidebar-tab-theme").click({ timeout: UI_TIMEOUT_MS });
  await page.getByTestId("mindmap-schema-sidebar-option-theme-dark").click({ timeout: UI_TIMEOUT_MS });
  await waitForMindmapCommandSuccess(page, "setTheme");

  await page.getByTestId("mindmap-schema-sidebar-tab-nodeStyle").click({ timeout: UI_TIMEOUT_MS });
  await page.getByTestId("mindmap-schema-sidebar-option-node-fill-blue").click({ timeout: UI_TIMEOUT_MS });
  await waitForMindmapCommandSuccess(page, "painter");

  const beforeReload = await readPersistedMindmapState(page);
  assert(beforeReload.layout === "mindMap", `sidebar_actions_layout_before_reload:${beforeReload.layout}`);
  assert(beforeReload.theme === "dark", `sidebar_actions_theme_before_reload:${beforeReload.theme}`);
  assert(beforeReload.rootFillColor === "#dbeafe", `sidebar_actions_fill_before_reload:${beforeReload.rootFillColor}`);

  await page.reload({ waitUntil: "domcontentloaded" });
  await assertMindmapReady(page, "sidebar-actions-reload");
  const afterReload = await readPersistedMindmapState(page);
  assert(afterReload.layout === "mindMap", `sidebar_actions_layout_after_reload:${afterReload.layout}`);
  assert(afterReload.theme === "dark", `sidebar_actions_theme_after_reload:${afterReload.theme}`);
  assert(afterReload.rootFillColor === "#dbeafe", `sidebar_actions_fill_after_reload:${afterReload.rootFillColor}`);

  return { beforeReload, afterReload };
}

async function readNavigatorMetrics(page) {
  return page.evaluate(() => {
    const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
    const navigator = document.querySelector('[data-testid="mindmap-schema-navigator"]');
    const searchInput = document.querySelector('[data-testid="mindmap-schema-navigator-search"]');
    const minimap = document.querySelector('[data-testid="mindmap-schema-minimap"]');
    const readonlyButton = document.querySelector('[data-testid="mindmap-schema-navigator-action-readonly"]');
    const zoomInput = document.querySelector('[data-testid="mindmap-schema-navigator-zoom-input"]');
    return {
      navigatorVisible: navigator instanceof HTMLElement && navigator.getBoundingClientRect().height > 0,
      searchOpen: shell instanceof HTMLElement ? shell.dataset.navigatorSearchOpen === "true" : false,
      minimapOpen: shell instanceof HTMLElement ? shell.dataset.navigatorMinimapOpen === "true" : false,
      readonly: shell instanceof HTMLElement ? shell.dataset.navigatorReadonly === "true" : false,
      searchInputVisible: searchInput instanceof HTMLInputElement && searchInput.getBoundingClientRect().width > 0,
      minimapVisible: minimap instanceof HTMLElement && minimap.getBoundingClientRect().height > 0,
      readonlyActive: readonlyButton instanceof HTMLButtonElement ? readonlyButton.dataset.active === "true" : false,
      zoomValue: zoomInput instanceof HTMLInputElement ? zoomInput.value : null,
    };
  });
}

async function verifyNavigatorStage(page, screenshots) {
  const initial = await readNavigatorMetrics(page);
  assert(initial.navigatorVisible, "navigator_missing");
  assert(!initial.searchInputVisible, "navigator_search_should_be_collapsed");
  screenshots.push(await screenshot(page, "07-navigator-icons"));

  await page.getByTestId("mindmap-schema-navigator-action-search").click({ timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
      const input = document.querySelector('[data-testid="mindmap-schema-navigator-search"]');
      return shell instanceof HTMLElement && shell.dataset.navigatorSearchOpen === "true" && input instanceof HTMLInputElement;
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const searchInput = page.getByTestId("mindmap-schema-navigator-search");
  await searchInput.fill("主题", { timeout: UI_TIMEOUT_MS });
  screenshots.push(await screenshot(page, "08-search-expanded"));
  await searchInput.press("Escape");
  await page.waitForFunction(
    () => {
      const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
      const input = document.querySelector('[data-testid="mindmap-schema-navigator-search"]');
      return shell instanceof HTMLElement && shell.dataset.navigatorSearchOpen === "false" && !(input instanceof HTMLInputElement);
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );

  await page.getByTestId("mindmap-schema-navigator-action-minimap").click({ timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
      const minimap = document.querySelector('[data-testid="mindmap-schema-minimap"]');
      return shell instanceof HTMLElement && shell.dataset.navigatorMinimapOpen === "true" && minimap instanceof HTMLElement;
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );

  await page.getByTestId("mindmap-schema-navigator-action-readonly").click({ timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
      return shell instanceof HTMLElement && shell.dataset.navigatorReadonly === "true";
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );

  const zoomInputField = page.getByTestId("mindmap-schema-navigator-zoom-input");
  const previousZoom = await zoomInputField.inputValue();
  await zoomInputField.fill("abc", { timeout: UI_TIMEOUT_MS });
  await zoomInputField.press("Enter");
  await page.waitForTimeout(200);
  const afterInvalidZoom = await zoomInputField.inputValue();
  assert(afterInvalidZoom === previousZoom, `navigator_zoom_invalid_not_restored:${afterInvalidZoom}`);

  const final = await readNavigatorMetrics(page);
  assert(final.minimapVisible, "navigator_minimap_not_visible");
  assert(final.readonlyActive, "navigator_readonly_not_active");
  return { initial, final };
}

async function restoreNavigatorDefaultState(page) {
  const current = await readNavigatorMetrics(page);
  if (current.minimapOpen) {
    await page.getByTestId("mindmap-schema-navigator-action-minimap").click({ timeout: UI_TIMEOUT_MS });
    await page.waitForFunction(
      () => {
        const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
        return shell instanceof HTMLElement && shell.dataset.navigatorMinimapOpen === "false";
      },
      null,
      { timeout: UI_TIMEOUT_MS },
    );
  }
  if (current.readonly) {
    await page.getByTestId("mindmap-schema-navigator-action-readonly").click({ timeout: UI_TIMEOUT_MS });
    await page.waitForFunction(
      () => {
        const shell = document.querySelector('[data-testid="mindmap-rust-shell"]');
        return shell instanceof HTMLElement && shell.dataset.navigatorReadonly === "false";
      },
      null,
      { timeout: UI_TIMEOUT_MS },
    );
  }
}

async function restoreCanvasIdleState(page) {
  await page.keyboard.press("Escape").catch(() => undefined);
  const root = page.getByTestId("mnote-mindmap-editor-root");
  const box = await root.boundingBox();
  if (box && box.width > 0 && box.height > 0) {
    await page.mouse.click(box.x + box.width / 2, box.y + box.height / 2);
  }
  await page.waitForTimeout(200);
}

async function main() {
  if (!["all", "toolbar", "fullscreen", "chrome-hide", "sidebar", "sidebar-actions", "navigator", "context-menu", "theme"].includes(STAGE)) {
    throw new Error(`当前 smoke 只实现 --stage all/toolbar/fullscreen/chrome-hide/sidebar/sidebar-actions/navigator/context-menu/theme，收到：${STAGE}`);
  }
  await fs.mkdir(OUTPUT_DIR, { recursive: true });

  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext({ viewport: { width: 1440, height: 960 }, locale: "zh-CN" });
  const page = await context.newPage();
  const screenshots = [];
  const createdIds = [];
  const result = {
    ok: false,
    task: TASK,
    stage: STAGE,
    baseUrl: BASE_URL,
    documentId: null,
    mindmapId: null,
    toolbar: null,
    screenshots,
  };

  try {
    await ensureAuthenticated(page, context.request);
    const doc = await createTempDocument(context.request, null);
    createdIds.push(doc.documentId);
    const title = `task167-mindmap-${Date.now().toString().slice(-6)}`;
    await renameDocument(context.request, doc.workspaceId, doc.documentId, title);
    result.documentId = doc.documentId;

    await openDocument(page, doc.workspaceId, doc.documentId);
    await insertMindmapThroughSlash(page);
    await assertMindmapReady(page, STAGE);
    result.mindmapId = (await readMindmapIdentity(page)).mindmapId;
    if (STAGE === "all") {
      result.toolbar = await verifyToolbarStage(page);
      screenshots.push(await screenshot(page, "01-toolbar-single-row"));
      result.fullscreen = await verifyFullscreenStage(page);
      screenshots.push(await screenshot(page, "02-fullscreen-canvas"));
      await restoreCanvasIdleState(page);
      result.chromeHide = await verifyChromeHideStage(page);
      screenshots.push(await screenshot(page, "03-chrome-hidden-after-leave"));
      screenshots.push(await screenshot(page, "04-chrome-restored-after-click"));
      result.sidebar = await verifySidebarStage(page);
      screenshots.push(await screenshot(page, "05-sidebar-structure-drawer"));
      await page.getByTestId("mindmap-schema-sidebar-hide-handle").click({ timeout: UI_TIMEOUT_MS }).catch(() => undefined);
      await page.waitForTimeout(200);
      screenshots.push(await screenshot(page, "06-sidebar-hidden-handle"));
      await page.getByTestId("mindmap-schema-sidebar-restore-handle").click({ timeout: UI_TIMEOUT_MS }).catch(() => undefined);
      await page.waitForTimeout(200);
      await page.getByTestId("mindmap-schema-sidebar-close").click({ timeout: UI_TIMEOUT_MS }).catch(() => undefined);
      await page.waitForTimeout(200);
      result.navigator = await verifyNavigatorStage(page, screenshots);
      await restoreNavigatorDefaultState(page);
      result.contextMenu = await verifyContextMenuStage(page);
      screenshots.push(await screenshot(page, "09-node-context-menu"));
      await restoreCanvasIdleState(page);
      result.theme = await verifyThemeStage(page);
      screenshots.push(await screenshot(page, "10-kmind-theme-baseline"));
      result.sidebarActions = await verifySidebarActionsStage(page);
      result.toolbarRows = result.toolbar?.desktop?.toolbarRows ?? null;
      result.fullscreenOk = Boolean(result.fullscreen);
      result.chromeHideOk = Boolean(result.chromeHide);
      result.sidebarDrawerOk = Boolean(result.sidebar);
      result.navigatorOk = Boolean(result.navigator);
      result.contextMenuOk = Boolean(result.contextMenu);
      result.themeOk = Boolean(result.theme);
      result.reloadOk = Boolean(result.sidebarActions);
    } else if (STAGE === "toolbar") {
      result.toolbar = await verifyToolbarStage(page);
      screenshots.push(await screenshot(page, "01-toolbar-single-row"));
    } else if (STAGE === "fullscreen") {
      result.fullscreen = await verifyFullscreenStage(page);
      screenshots.push(await screenshot(page, "02-fullscreen-canvas"));
    } else if (STAGE === "chrome-hide") {
      result.chromeHide = await verifyChromeHideStage(page);
      screenshots.push(await screenshot(page, "03-chrome-hidden-after-leave"));
      screenshots.push(await screenshot(page, "04-chrome-restored-after-click"));
    } else if (STAGE === "sidebar") {
      result.sidebar = await verifySidebarStage(page);
      screenshots.push(await screenshot(page, "05-sidebar-structure-drawer"));
      await page.getByTestId("mindmap-schema-sidebar-hide-handle").click({ timeout: UI_TIMEOUT_MS }).catch(() => undefined);
      await page.waitForTimeout(200);
      screenshots.push(await screenshot(page, "06-sidebar-hidden-handle"));
    } else if (STAGE === "sidebar-actions") {
      result.sidebarActions = await verifySidebarActionsStage(page);
    } else if (STAGE === "navigator") {
      result.navigator = await verifyNavigatorStage(page, screenshots);
    } else if (STAGE === "context-menu") {
      result.contextMenu = await verifyContextMenuStage(page);
      screenshots.push(await screenshot(page, "09-node-context-menu"));
    } else if (STAGE === "theme") {
      result.theme = await verifyThemeStage(page);
      screenshots.push(await screenshot(page, "10-kmind-theme-baseline"));
    }

    result.ok = true;
    await writeResult(result);
  } catch (error) {
    result.error = error instanceof Error ? error.stack || error.message : String(error);
    screenshots.push(await screenshot(page, "99-failure").catch(() => null));
    await writeResult(result);
    throw error;
  } finally {
    await cleanupDocuments(context.request, createdIds).catch(() => undefined);
    await browser.close();
  }
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
