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

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

const TASK = "task166-mindmap-phase6-block-smoke";
const OUTPUT_DIR = path.join(process.cwd(), "tmp", TASK);
const RESULT_PATH = path.join(OUTPUT_DIR, "result.json");

function checkPort(port) {
  const result = spawnSync("lsof", ["-nP", `-iTCP:${port}`, "-sTCP:LISTEN"], {
    encoding: "utf8",
    stdio: "pipe",
  });
  const lines = (result.stdout || "")
    .split(/\r?\n/)
    .map((line) => line.trim())
    .filter(Boolean);
  const rows = lines.slice(1).map((line) => {
    const parts = line.split(/\s+/);
    const pid = parts[1] || "";
    const commandLine =
      pid.length > 0
        ? spawnSync("ps", ["-p", pid, "-o", "command="], {
            encoding: "utf8",
            stdio: "pipe",
          }).stdout.trim()
        : "";
    return {
      command: parts[0] || "",
      pid,
      commandLine,
      name: parts.slice(8).join(" "),
      raw: line,
    };
  });
  return { port, rows };
}

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 readMindmapMetrics(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 scene = root instanceof HTMLElement ? root.querySelector('[data-testid="leptos-mindmap-island"]') : null;
    const overlayLayer = root instanceof HTMLElement ? root.querySelector('[data-testid="mindmap-overlay-layer"]') : null;
    const canvasLayer = root instanceof HTMLElement ? root.querySelector('[data-testid="mindmap-canvas-layer"]') : null;
    const schemaToolbar = document.querySelector('[data-testid="mindmap-schema-toolbar"]');
    const schemaSidebar = document.querySelector('[data-testid="mindmap-schema-sidebar"]');
    const schemaNavigator = document.querySelector('[data-testid="mindmap-schema-navigator"]');
    const schemaCount = document.querySelector('[data-testid="mindmap-schema-count"]');
    const schemaContextMenu = document.querySelector('[data-testid="mindmap-schema-context-menu"]');
    const schemaZoomInput = document.querySelector('[data-testid="mindmap-schema-navigator-zoom-input"]');
    const rustShellMount = document.querySelector('[data-testid="mindmap-rust-shell-mount"]');
    const rustShell = document.querySelector('[data-testid="mindmap-rust-shell"]');
    const error = document.querySelector('[data-testid="leptos-mindmap-error"]');
    const mindmapId = root instanceof HTMLElement ? root.dataset.mnoteMindmapId || null : null;
    const registry = window.__MNOTE_LEPTOS_MINDMAP_BRIDGES__ || {};
    const bridge = mindmapId ? registry[mindmapId] : null;
    const snapshot = bridge && typeof bridge.getSnapshot === "function" ? bridge.getSnapshot() : null;
    const canonicalRoot =
      snapshot && typeof snapshot === "object" && !Array.isArray(snapshot) && "root" in snapshot
        ? snapshot.root
        : snapshot;
    const snapshotStats = { nodeCount: 0, edgeCount: 0, nodeTexts: [] };
    const visit = (node) => {
      if (!node || typeof node !== "object" || Array.isArray(node)) return;
      snapshotStats.nodeCount += 1;
      const text = node.data && typeof node.data.text === "string" ? node.data.text.trim() : "";
      if (text) snapshotStats.nodeTexts.push(text);
      const children = Array.isArray(node.children) ? node.children : [];
      snapshotStats.edgeCount += children.length;
      children.forEach(visit);
    };
    visit(canonicalRoot);
    const runtimeNodes = runtime
      ? Array.from(runtime.querySelectorAll(".smm-node")).filter((node) => {
          const rect = node.getBoundingClientRect();
          return rect.width > 0 && rect.height > 0;
        }).length
      : 0;
    const svgPaths = runtime
      ? Array.from(runtime.querySelectorAll("svg path, svg line, svg polyline")).filter((edge) => {
          const rect = edge.getBoundingClientRect();
          return rect.width > 0 || rect.height > 0 || edge.getAttribute("d") || edge.getAttribute("points");
        }).length
      : 0;
    const runtimeRect = runtime?.getBoundingClientRect();
    const rootRect = root?.getBoundingClientRect();
    const overlayRect = overlayLayer?.getBoundingClientRect();
    const canvasRect = canvasLayer?.getBoundingClientRect();
    return {
      errorStage: error instanceof HTMLElement ? error.dataset.stage || "unknown_error" : null,
      rootExists: root instanceof HTMLElement,
      mindmapId,
      runtimeExists: runtime instanceof HTMLElement,
      runtimeEngine: runtime instanceof HTMLElement ? runtime.dataset.runtimeEngine || null : null,
      runtimeReady: runtime instanceof HTMLElement ? runtime.dataset.runtimeReady === "true" : false,
      lastViewEvent:
        root instanceof HTMLElement
          ? root.querySelector('[data-testid="leptos-mindmap-island"]')?.dataset.lastViewEvent || null
          : null,
      debugChrome:
        scene instanceof HTMLElement ? scene.dataset.debugChrome || null : null,
      uiShell:
        scene instanceof HTMLElement ? scene.dataset.uiShell || null : null,
      rustShell: {
        mount: rustShellMount instanceof HTMLElement,
        mountSource: rustShellMount instanceof HTMLElement ? rustShellMount.dataset.uiShellSource || null : null,
        shell: rustShell instanceof HTMLElement,
        shellSource: rustShell instanceof HTMLElement ? rustShell.dataset.uiShellSource || null : null,
      },
      schemaChrome: {
        toolbar:
          schemaToolbar instanceof HTMLElement &&
          schemaToolbar.dataset.schemaSource === "mindmapDefaultUiSchema" &&
          schemaToolbar.dataset.uiSource === "leptos-rust-shell",
        sidebar:
          schemaSidebar instanceof HTMLElement &&
          schemaSidebar.dataset.schemaSource === "mindmapDefaultUiSchema" &&
          schemaSidebar.dataset.uiSource === "leptos-rust-shell",
        navigator:
          schemaNavigator instanceof HTMLElement &&
          schemaNavigator.dataset.schemaSource === "mindmapDefaultUiSchema" &&
          schemaNavigator.dataset.uiSource === "leptos-rust-shell",
        count:
          schemaCount instanceof HTMLElement &&
          schemaCount.dataset.schemaSource === "mindmapDefaultUiSchema" &&
          schemaCount.dataset.uiSource === "leptos-rust-shell",
        toolbarActions: Array.from(document.querySelectorAll("[data-mindmap-action-id]"))
          .map((item) => item instanceof HTMLElement ? item.dataset.mindmapActionId : null)
          .filter(Boolean),
        disabledActions: Array.from(document.querySelectorAll("[data-mindmap-action-id]"))
          .filter((item) => item instanceof HTMLButtonElement && item.disabled)
          .map((item) => item.dataset.mindmapActionId)
          .filter(Boolean),
        sidebarPanels: Array.from(document.querySelectorAll("[data-mindmap-sidebar-panel-id]"))
          .map((item) => item instanceof HTMLElement ? item.dataset.mindmapSidebarPanelId : null)
          .filter(Boolean),
        statsText: schemaNavigator?.querySelector('[data-testid="mindmap-schema-navigator-stats"]')?.textContent || null,
        countText: schemaCount?.textContent || null,
        zoomText: schemaNavigator?.querySelector('[data-testid="mindmap-schema-navigator-zoom"]')?.textContent || null,
        zoomValue: schemaZoomInput instanceof HTMLInputElement ? schemaZoomInput.value : null,
        minimap: Boolean(document.querySelector('[data-testid="mindmap-schema-minimap"]')),
        contextMenu:
          schemaContextMenu instanceof HTMLElement
            ? {
                kind: schemaContextMenu.dataset.contextMenuKind || null,
                actions: Array.from(schemaContextMenu.querySelectorAll("[data-mindmap-context-action-id]"))
                  .map((item) => item instanceof HTMLElement ? item.dataset.mindmapContextActionId : null)
                  .filter(Boolean),
              }
            : null,
      },
      overlayShell: {
        overlay: overlayLayer instanceof HTMLElement,
        canvas: canvasLayer instanceof HTMLElement,
        rootBox: rootRect
          ? { width: rootRect.width, height: rootRect.height }
          : { width: 0, height: 0 },
        overlayBox: overlayRect
          ? { width: overlayRect.width, height: overlayRect.height }
          : { width: 0, height: 0 },
        canvasBox: canvasRect
          ? { width: canvasRect.width, height: canvasRect.height }
          : { width: 0, height: 0 },
      },
      legacyFallback: {
        toolbar: Boolean(document.querySelector('[data-testid="mindmap-command-toolbar"]')),
        sidebar: Boolean(document.querySelector('[data-testid="mindmap-sidebar"]')),
        bottomBar: Boolean(document.querySelector('[data-testid="mindmap-bottom-bar"]')),
      },
      viewCommandStatus:
        scene instanceof HTMLElement ? scene.dataset.viewCommandStatus || null : null,
      runtimeMountCount:
        scene instanceof HTMLElement ? Number(scene.dataset.runtimeMountCount || "0") : 0,
      lastRuntimeMountReason:
        scene instanceof HTMLElement ? scene.dataset.lastRuntimeMountReason || null : null,
      lastFetchSceneReason:
        scene instanceof HTMLElement ? scene.dataset.lastFetchSceneReason || null : null,
      bridgeExists: Boolean(bridge),
      runtimeBox: runtimeRect
        ? { width: runtimeRect.width, height: runtimeRect.height }
        : { width: 0, height: 0 },
      nodeCount: snapshotStats.nodeCount || runtimeNodes,
      edgeCount: snapshotStats.edgeCount || svgPaths,
      runtimeNodeCount: runtimeNodes,
      svgPathCount: svgPaths,
      nodeTexts: snapshotStats.nodeTexts,
    };
  });
}

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 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" &&
        Boolean(bridge)
      );
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const metrics = await readMindmapMetrics(page);
  if (metrics.errorStage) {
    throw new Error(`${metrics.errorStage}: ${stage}`);
  }
  assert(metrics.rootExists, `${stage}: mnote-mindmap-editor-root 不存在`);
  assert(metrics.runtimeExists, `${stage}: runtime_render_failed`);
  assert(metrics.runtimeEngine === "simple-mind-map", `${stage}: runtime_engine_failed`);
  assert(metrics.runtimeReady, `${stage}: runtime_not_ready`);
  assert(metrics.bridgeExists, `${stage}: bridge_not_registered`);
  assert(metrics.runtimeBox.width > 0 && metrics.runtimeBox.height > 0, `${stage}: runtime_render_failed`);
  assert(metrics.debugChrome === "false", `${stage}: debug_chrome_unexpected`);
  assert(metrics.uiShell === "leptos-rust-shell", `${stage}: ui_shell_source_unexpected`);
  assert(metrics.rustShell.mount, `${stage}: rust_shell_mount_missing`);
  assert(metrics.rustShell.mountSource === "leptos-rust-shell", `${stage}: rust_shell_mount_source_unexpected`);
  assert(metrics.rustShell.shell, `${stage}: rust_shell_missing`);
  assert(metrics.rustShell.shellSource === "leptos-rust-shell", `${stage}: rust_shell_source_unexpected`);
  assert(metrics.schemaChrome.toolbar, `${stage}: ui_shell_missing toolbar`);
  assert(metrics.schemaChrome.sidebar, `${stage}: ui_shell_missing sidebar`);
  assert(metrics.schemaChrome.navigator, `${stage}: ui_shell_missing navigator`);
  assert(metrics.schemaChrome.count, `${stage}: ui_shell_missing count`);
  assert(metrics.overlayShell.overlay, `${stage}: floating_overlay_missing overlay`);
  assert(metrics.overlayShell.canvas, `${stage}: floating_overlay_missing canvas`);
  assert(metrics.runtimeBox.width / Math.max(metrics.overlayShell.rootBox.width, 1) >= 0.9, `${stage}: runtime_width_squeezed`);
  assert(metrics.runtimeBox.height / Math.max(metrics.overlayShell.rootBox.height, 1) >= 0.85, `${stage}: runtime_height_squeezed`);
  assert(!metrics.legacyFallback.toolbar, `${stage}: legacy_toolbar_unexpected`);
  assert(!metrics.legacyFallback.sidebar, `${stage}: legacy_sidebar_unexpected`);
  assert(!metrics.legacyFallback.bottomBar, `${stage}: legacy_bottom_bar_unexpected`);
  const expectedActions = [
    "undo",
    "redo",
    "insertSiblingAfter",
    "insertChild",
    "deleteNode",
    "tag",
    "hyperlink",
    "note",
    "image",
    "icon",
    "summary",
    "associativeLine",
    "formula",
    "painter",
    "import",
    "export",
  ];
  for (const actionId of expectedActions) {
    assert(metrics.schemaChrome.toolbarActions.includes(actionId), `${stage}: ui_shell_missing action=${actionId}`);
  }
  for (const panelId of ["nodeStyle", "baseStyle", "theme", "structure", "outline"]) {
    assert(metrics.schemaChrome.sidebarPanels.includes(panelId), `${stage}: ui_shell_missing panel=${panelId}`);
  }
  assert(/节点/.test(metrics.schemaChrome.countText || ""), `${stage}: ui_shell_missing count_stats`);
  assert(/%/.test(metrics.schemaChrome.zoomText || metrics.schemaChrome.zoomValue || ""), `${stage}: ui_shell_missing zoom`);
  assert(metrics.nodeCount >= 4, `${stage}: runtime_render_failed nodeCount=${metrics.nodeCount}`);
  assert(metrics.edgeCount >= 3, `${stage}: runtime_render_failed edgeCount=${metrics.edgeCount}`);
  return metrics;
}

async function readMindmapSnapshotStats(page, mindmapId) {
  return page.evaluate((mindmapId) => {
    const registry = window.__MNOTE_LEPTOS_MINDMAP_BRIDGES__ || {};
    const bridge = registry[mindmapId];
    const snapshot = bridge && typeof bridge.getSnapshot === "function" ? bridge.getSnapshot() : null;
    const root =
      snapshot && typeof snapshot === "object" && !Array.isArray(snapshot) && "root" in snapshot
        ? snapshot.root
        : snapshot;
    const stats = { nodeCount: 0, edgeCount: 0, nodeTexts: [] };
    const visit = (node) => {
      if (!node || typeof node !== "object" || Array.isArray(node)) return;
      stats.nodeCount += 1;
      const text = node.data && typeof node.data.text === "string" ? node.data.text.trim() : "";
      if (text) stats.nodeTexts.push(text);
      const children = Array.isArray(node.children) ? node.children : [];
      stats.edgeCount += children.length;
      children.forEach(visit);
    };
    visit(root);
    return stats;
  }, mindmapId);
}

function findNodeFillColorByUid(root, nodeId) {
  if (!root || typeof root !== "object" || Array.isArray(root) || !nodeId) return null;
  const queue = [root];
  while (queue.length > 0) {
    const node = queue.shift();
    if (!node || typeof node !== "object" || Array.isArray(node)) continue;
    const uid = typeof node.data?.uid === "string" ? node.data.uid.trim() : "";
    if (uid === nodeId) {
      return typeof node.data?.fillColor === "string" ? node.data.fillColor : null;
    }
    if (Array.isArray(node.children)) queue.push(...node.children);
  }
  return null;
}

async function armBridgeStabilityProbe(page, mindmapId, probeKey) {
  await page.evaluate(
    ({ mindmapId, probeKey }) => {
      const registry = window.__MNOTE_LEPTOS_MINDMAP_BRIDGES__ || {};
      window.__mnoteSmokeBridgeProbes = window.__mnoteSmokeBridgeProbes || {};
      window.__mnoteSmokeBridgeProbes[probeKey] = registry[mindmapId] || null;
    },
    { mindmapId, probeKey },
  );
}

async function readBridgeStabilityProbe(page, mindmapId, probeKey) {
  return page.evaluate(
    ({ mindmapId, probeKey }) => {
      const registry = window.__MNOTE_LEPTOS_MINDMAP_BRIDGES__ || {};
      const probes = window.__mnoteSmokeBridgeProbes || {};
      return Boolean(probes[probeKey] && registry[mindmapId] === probes[probeKey]);
    },
    { mindmapId, probeKey },
  );
}

async function clickToolbarActionAndWaitForCommand(page, mindmapId, actionId) {
  const probeKey = `toolbar:${actionId}:${Date.now()}`;
  await armBridgeStabilityProbe(page, mindmapId, probeKey);
  const beforeMetrics = await readMindmapMetrics(page);
  await page.evaluate(() => {
    const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
    if (scene instanceof HTMLElement) {
      scene.dataset.commandStatus = "smoke-waiting";
      delete scene.dataset.lastSchemaAction;
    }
  });
  await page.getByTestId(`mindmap-schema-toolbar-action-${actionId}`).click({ timeout: UI_TIMEOUT_MS });
  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(async (error) => {
    const diagnostics = await page.evaluate((actionId) => {
      const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
      const button = document.querySelector(`[data-testid="mindmap-schema-toolbar-action-${actionId}"]`);
      const errorLayer = document.querySelector('[data-testid="leptos-mindmap-error"]');
      return {
        sceneDataset: scene instanceof HTMLElement ? { ...scene.dataset } : null,
        buttonDisabled: button instanceof HTMLButtonElement ? button.disabled : null,
        buttonExists: button instanceof HTMLElement,
        errorStage: errorLayer instanceof HTMLElement ? errorLayer.getAttribute("data-stage") : null,
        errorText: errorLayer instanceof HTMLElement ? errorLayer.textContent : null,
      };
    }, actionId);
    throw new Error(`command_failed:${actionId}:command_status_timeout:${JSON.stringify(diagnostics)}:${error.message}`);
  });
  const bridgeStable = await readBridgeStabilityProbe(page, mindmapId, probeKey);
  const afterMetrics = await readMindmapMetrics(page);
  const afterSceneDataset = await page.evaluate(() => {
    const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
    return scene instanceof HTMLElement ? { ...scene.dataset } : null;
  });
  return { ok: () => true, bridgeStable, beforeMetrics, afterMetrics, afterSceneDataset };
}

async function clickSidebarOptionAndWaitForCommand(page, optionId, actionId) {
  await page.evaluate(() => {
    const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
    if (scene instanceof HTMLElement) {
      scene.dataset.commandStatus = "smoke-waiting";
      delete scene.dataset.lastSchemaAction;
      delete scene.dataset.lastSchemaCommand;
    }
  });
  await page.getByTestId(`mindmap-schema-sidebar-option-${optionId}`).click({ timeout: UI_TIMEOUT_MS });
  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(async (error) => {
    const diagnostics = await page.evaluate((optionId) => {
      const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
      const option = document.querySelector(`[data-testid="mindmap-schema-sidebar-option-${optionId}"]`);
      const errorLayer = document.querySelector('[data-testid="leptos-mindmap-error"]');
      return {
        sceneDataset: scene instanceof HTMLElement ? { ...scene.dataset } : null,
        optionExists: option instanceof HTMLElement,
        errorStage: errorLayer instanceof HTMLElement ? errorLayer.getAttribute("data-stage") : null,
        errorText: errorLayer instanceof HTMLElement ? errorLayer.textContent : null,
      };
    }, optionId);
    throw new Error(`command_failed:${actionId}:${optionId}:command_status_timeout:${JSON.stringify(diagnostics)}:${error.message}`);
  });
}

async function verifyReadonlyToolbarState(page, stage) {
  await page.getByTestId("mindmap-schema-navigator-action-readonly").click({ timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const insertChild = document.querySelector('[data-testid="mindmap-schema-toolbar-action-insertChild"]');
      const deleteNode = document.querySelector('[data-testid="mindmap-schema-toolbar-action-deleteNode"]');
      const zoomIn = document.querySelector('[data-testid="mindmap-schema-navigator-action-zoomIn"]');
      const centerRoot = document.querySelector('[data-testid="mindmap-schema-navigator-action-centerRoot"]');
      return (
        insertChild instanceof HTMLButtonElement &&
        deleteNode instanceof HTMLButtonElement &&
        zoomIn instanceof HTMLButtonElement &&
        centerRoot instanceof HTMLButtonElement &&
        insertChild.disabled &&
        deleteNode.disabled &&
        !zoomIn.disabled &&
        !centerRoot.disabled
      );
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  ).catch((error) => {
    throw new Error(`ui_shell_missing:${stage}:readonly_disabled_state:${error.message}`);
  });
  await page.getByTestId("mindmap-schema-navigator-action-readonly").click({ timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const insertChild = document.querySelector('[data-testid="mindmap-schema-toolbar-action-insertChild"]');
      return insertChild instanceof HTMLButtonElement && !insertChild.disabled;
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  return true;
}

async function exerciseToolbarNodeActions(page, documentId, mindmapId) {
  const before = await readMindmapSnapshotStats(page, mindmapId);
  const childResponse = await clickToolbarActionAndWaitForCommand(page, mindmapId, "insertChild");
  await page.waitForFunction(
    ({ mindmapId, expected }) => {
      const registry = window.__MNOTE_LEPTOS_MINDMAP_BRIDGES__ || {};
      const bridge = registry[mindmapId];
      const snapshot = bridge && typeof bridge.getSnapshot === "function" ? bridge.getSnapshot() : null;
      const root =
        snapshot && typeof snapshot === "object" && !Array.isArray(snapshot) && "root" in snapshot
          ? snapshot.root
          : snapshot;
      let count = 0;
      const visit = (node) => {
        if (!node || typeof node !== "object" || Array.isArray(node)) return;
        count += 1;
        if (Array.isArray(node.children)) node.children.forEach(visit);
      };
      visit(root);
      return count >= expected;
    },
    { mindmapId, expected: before.nodeCount + 1 },
    { timeout: UI_TIMEOUT_MS },
  );
  const afterChild = await readMindmapSnapshotStats(page, mindmapId);

  const siblingResponse = await clickToolbarActionAndWaitForCommand(page, mindmapId, "insertSiblingAfter");
  await page.waitForFunction(
    ({ mindmapId, expected }) => {
      const registry = window.__MNOTE_LEPTOS_MINDMAP_BRIDGES__ || {};
      const bridge = registry[mindmapId];
      const snapshot = bridge && typeof bridge.getSnapshot === "function" ? bridge.getSnapshot() : null;
      const root =
        snapshot && typeof snapshot === "object" && !Array.isArray(snapshot) && "root" in snapshot
          ? snapshot.root
          : snapshot;
      let count = 0;
      const visit = (node) => {
        if (!node || typeof node !== "object" || Array.isArray(node)) return;
        count += 1;
        if (Array.isArray(node.children)) node.children.forEach(visit);
      };
      visit(root);
      return count >= expected;
    },
    { mindmapId, expected: afterChild.nodeCount + 1 },
    { timeout: UI_TIMEOUT_MS },
  );
  const afterSibling = await readMindmapSnapshotStats(page, mindmapId);

  const deleteResponse = await clickToolbarActionAndWaitForCommand(page, mindmapId, "deleteNode");
  await page.waitForFunction(
    ({ mindmapId, expectedMax }) => {
      const registry = window.__MNOTE_LEPTOS_MINDMAP_BRIDGES__ || {};
      const bridge = registry[mindmapId];
      const snapshot = bridge && typeof bridge.getSnapshot === "function" ? bridge.getSnapshot() : null;
      const root =
        snapshot && typeof snapshot === "object" && !Array.isArray(snapshot) && "root" in snapshot
          ? snapshot.root
          : snapshot;
      let count = 0;
      const visit = (node) => {
        if (!node || typeof node !== "object" || Array.isArray(node)) return;
        count += 1;
        if (Array.isArray(node.children)) node.children.forEach(visit);
      };
      visit(root);
      return count <= expectedMax;
    },
    { mindmapId, expectedMax: afterSibling.nodeCount - 1 },
    { timeout: UI_TIMEOUT_MS },
  );
  const afterDelete = await readMindmapSnapshotStats(page, mindmapId);

  return {
    insertChildOk: childResponse.ok() && afterChild.nodeCount >= before.nodeCount + 1,
    insertSiblingOk: siblingResponse.ok() && afterSibling.nodeCount >= afterChild.nodeCount + 1,
    deleteOk: deleteResponse.ok() && afterDelete.nodeCount <= afterSibling.nodeCount - 1,
    childBridgeStable: childResponse.bridgeStable,
    siblingBridgeStable: siblingResponse.bridgeStable,
    deleteBridgeStable: deleteResponse.bridgeStable,
    childRuntimeMountCountBefore: childResponse.beforeMetrics.runtimeMountCount,
    childRuntimeMountCountAfter: childResponse.afterMetrics.runtimeMountCount,
    childRuntimeMountReason: childResponse.afterMetrics.lastRuntimeMountReason,
    childFetchSceneReason: childResponse.afterMetrics.lastFetchSceneReason,
    childCommandApplyMode: childResponse.afterSceneDataset?.commandApplyMode ?? null,
    childCommandRuntimeError: childResponse.afterSceneDataset?.commandRuntimeError ?? null,
    childCommandRuntimeMessage: childResponse.afterSceneDataset?.commandRuntimeMessage ?? null,
    childCommandActiveNodeId: childResponse.afterSceneDataset?.lastSchemaActiveNodeId ?? null,
    childCommandLocalApplyErrors: childResponse.afterSceneDataset?.commandLocalApplyErrors ?? null,
    beforeNodeCount: before.nodeCount,
    afterChildNodeCount: afterChild.nodeCount,
    afterSiblingNodeCount: afterSibling.nodeCount,
    afterDeleteNodeCount: afterDelete.nodeCount,
  };
}

async function pressMindmapShortcutAndWaitForCommand(page, mindmapId, key, actionId) {
  const probeKey = `shortcut:${actionId}:${Date.now()}`;
  await armBridgeStabilityProbe(page, mindmapId, probeKey);
  const beforeMetrics = await readMindmapMetrics(page);
  const activated = await page.evaluate((mindmapId) => {
    const registry = window.__MNOTE_LEPTOS_MINDMAP_BRIDGES__ || {};
    const bridge = registry[mindmapId];
    const renderer = bridge?.instance?.renderer;
    if (!renderer) return false;
    const snapshot = bridge?.getSnapshot?.();
    const rootData =
      snapshot && typeof snapshot === "object" && !Array.isArray(snapshot) && "root" in snapshot
        ? snapshot.root
        : snapshot;
    const queue = Array.isArray(rootData?.children) ? [...rootData.children] : [];
    let targetUid = null;
    while (queue.length > 0) {
      const node = queue.shift();
      if (!node || typeof node !== "object" || Array.isArray(node)) continue;
      const uid = typeof node.data?.uid === "string" ? node.data.uid.trim() : "";
      if (uid) {
        targetUid = uid;
        break;
      }
      if (Array.isArray(node.children)) queue.push(...node.children);
    }
    const target =
      (targetUid && typeof renderer.findNodeByUid === "function" ? renderer.findNodeByUid(targetUid) : null) ??
      renderer.activeNodeList?.find?.((node) => node && node.isRoot !== true && node.isGeneralization !== true) ??
      renderer.lastActiveNodeList?.find?.((node) => node && node.isRoot !== true && node.isGeneralization !== true) ??
      null;
    if (!target) return false;
    renderer.clearActiveNodeList?.();
    renderer.addNodeToActiveList?.(target, true);
    renderer.lastActiveNodeList = [target];
    renderer.emitNodeActiveEvent?.(target, [target]);
    bridge.instance?.execCommand?.("SET_NODE_ACTIVE", target, true);
    return true;
  }, mindmapId);
  if (!activated) {
    throw new Error(`shortcut_failed:${actionId}:${key}:non_root_activation_failed`);
  }
  await page.evaluate(() => {
    const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
    if (scene instanceof HTMLElement) {
      scene.dataset.commandStatus = "smoke-waiting";
      delete scene.dataset.lastSchemaAction;
      delete scene.dataset.lastShortcutAction;
      delete scene.dataset.lastShortcutActionBlocked;
    }
  });
  await page.keyboard.press(key);
  await page.waitForFunction(
    ({ actionId }) => {
      const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
      return (
        scene instanceof HTMLElement &&
        scene.dataset.lastShortcutAction === actionId &&
        scene.dataset.commandStatus === "success"
      );
    },
    { actionId },
    { timeout: UI_TIMEOUT_MS },
  ).catch(async (error) => {
    const diagnostics = await page.evaluate(() => {
      const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
      const root = document.querySelector('[data-testid="mnote-mindmap-editor-root"]');
      return {
        sceneDataset: scene instanceof HTMLElement ? { ...scene.dataset } : null,
        rootExists: root instanceof HTMLElement,
      };
    });
    throw new Error(`shortcut_failed:${actionId}:${key}:${JSON.stringify(diagnostics)}:${error.message}`);
  });
  const bridgeStable = await readBridgeStabilityProbe(page, mindmapId, probeKey);
  const afterMetrics = await readMindmapMetrics(page);
  const afterSceneDataset = await page.evaluate(() => {
    const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
    return scene instanceof HTMLElement ? { ...scene.dataset } : null;
  });
  return { ok: true, bridgeStable, beforeMetrics, afterMetrics, afterSceneDataset };
}

async function exerciseKeyboardShortcuts(page, mindmapId) {
  const before = await readMindmapSnapshotStats(page, mindmapId);
  const enterResponse = await pressMindmapShortcutAndWaitForCommand(page, mindmapId, "Enter", "insertSiblingAfter");
  const afterEnter = await readMindmapSnapshotStats(page, mindmapId);
  const deleteResponse = await pressMindmapShortcutAndWaitForCommand(page, mindmapId, "Delete", "deleteNode");
  const afterDelete = await readMindmapSnapshotStats(page, mindmapId);
  const rootStillExists = await page.evaluate(() => {
    const root = document.querySelector('[data-testid="mnote-mindmap-editor-root"]');
    return root instanceof HTMLElement;
  });
  return {
    enterOk: enterResponse.ok && afterEnter.nodeCount >= before.nodeCount + 1,
    deleteOk: deleteResponse.ok && afterDelete.nodeCount <= afterEnter.nodeCount - 1,
    enterBridgeStable: enterResponse.bridgeStable,
    deleteBridgeStable: deleteResponse.bridgeStable,
    enterRuntimeMountCountBefore: enterResponse.beforeMetrics.runtimeMountCount,
    enterRuntimeMountCountAfter: enterResponse.afterMetrics.runtimeMountCount,
    enterRuntimeMountReason: enterResponse.afterMetrics.lastRuntimeMountReason,
    enterFetchSceneReason: enterResponse.afterMetrics.lastFetchSceneReason,
    enterCommandApplyMode: enterResponse.afterSceneDataset?.commandApplyMode ?? null,
    enterCommandRuntimeError: enterResponse.afterSceneDataset?.commandRuntimeError ?? null,
    enterCommandRuntimeMessage: enterResponse.afterSceneDataset?.commandRuntimeMessage ?? null,
    enterCommandActiveNodeId: enterResponse.afterSceneDataset?.lastSchemaActiveNodeId ?? null,
    enterCommandLocalApplyErrors: enterResponse.afterSceneDataset?.commandLocalApplyErrors ?? null,
    rootStillExists,
    beforeNodeCount: before.nodeCount,
    afterEnterNodeCount: afterEnter.nodeCount,
    afterDeleteNodeCount: afterDelete.nodeCount,
  };
}

async function exerciseSidebarActions(page, documentId, mindmapId) {
  await page.getByTestId("mindmap-schema-sidebar-tab-theme").click({ timeout: UI_TIMEOUT_MS });
  await clickSidebarOptionAndWaitForCommand(page, "theme-classic4", "setTheme");
  const themedProjection = await fetchAdapterProjection(page, documentId, mindmapId);
  if (themedProjection?.theme !== "classic4") {
    throw new Error(`command_failed:setTheme theme=${JSON.stringify(themedProjection?.theme)}`);
  }

  await page.getByTestId("mindmap-schema-sidebar-tab-structure").click({ timeout: UI_TIMEOUT_MS });
  await clickSidebarOptionAndWaitForCommand(page, "layout-mind-map", "setLayout");
  const layoutProjection = await fetchAdapterProjection(page, documentId, mindmapId);
  if (layoutProjection?.layout !== "mindMap") {
    throw new Error(`command_failed:setLayout layout=${JSON.stringify(layoutProjection?.layout)}`);
  }

  await page.getByTestId("mindmap-schema-sidebar-tab-nodeStyle").click({ timeout: UI_TIMEOUT_MS });
  await clickSidebarOptionAndWaitForCommand(page, "node-fill-blue", "painter");
  const nodeStyleProjection = await fetchAdapterProjection(page, documentId, mindmapId);
  const nodeStyleDiagnostics = await page.evaluate(() => {
    const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
    return scene instanceof HTMLElement ? { ...scene.dataset } : null;
  });
  const filledNodes = [];
  const collectFilledNodes = (node) => {
    if (!node || typeof node !== "object" || Array.isArray(node)) return;
    const uid = typeof node.data?.uid === "string" ? node.data.uid : null;
    const fillColor = typeof node.data?.fillColor === "string" ? node.data.fillColor : null;
    if (uid && fillColor) filledNodes.push({ uid, fillColor });
    if (Array.isArray(node.children)) node.children.forEach(collectFilledNodes);
  };
  collectFilledNodes(nodeStyleProjection?.root);
  const activeNodeId = typeof nodeStyleDiagnostics?.lastSchemaActiveNodeId === "string"
    ? nodeStyleDiagnostics.lastSchemaActiveNodeId
    : null;
  const activeNodeFill = activeNodeId
    ? filledNodes.find((node) => node.uid === activeNodeId)?.fillColor ?? null
    : null;
  if (activeNodeFill !== "#dbeafe") {
    throw new Error(`command_failed:nodeStyle compat fill=${JSON.stringify(activeNodeFill)} active=${JSON.stringify(activeNodeId)} nodes=${JSON.stringify(filledNodes)}`);
  }

  await page.getByTestId("mindmap-schema-sidebar-tab-baseStyle").click({ timeout: UI_TIMEOUT_MS });
  await clickSidebarOptionAndWaitForCommand(page, "base-curve-line", "painter");
  const baseStyleProjection = await fetchAdapterProjection(page, documentId, mindmapId);
  const lineStyle = baseStyleProjection?.compatPayload?.style?.map?.lineStyle;
  if (lineStyle !== "curve") {
    throw new Error(`command_failed:baseStyle compat lineStyle=${JSON.stringify(lineStyle)}`);
  }

  await page.getByTestId("mindmap-schema-sidebar-tab-outline").click({ timeout: UI_TIMEOUT_MS });
  const outlineItems = await page
    .locator('[data-testid="mindmap-schema-sidebar-outline-outline"] li')
    .evaluateAll((items) => items.map((item) => item.textContent?.trim()).filter(Boolean));
  if (outlineItems.length === 0) {
    throw new Error("ui_shell_missing:outline_items");
  }

  return {
    themeOk: themedProjection.theme === "classic4",
    layoutOk: layoutProjection.layout === "mindMap",
    nodeStyleCompatOk: activeNodeFill === "#dbeafe",
    nodeStyleTargetNodeId: activeNodeId,
    baseStyleCompatOk: lineStyle === "curve",
    outlineDerivedOk: outlineItems.length > 0,
    outlineItems,
  };
}

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 fetchAdapterProjection(page, documentId, mindmapId) {
  return page.evaluate(
    async ({ documentId, mindmapId }) => {
      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);
      if (!response.ok) {
        throw new Error(`projection_load_failed:${response.status}`);
      }
      if (payload && typeof payload === "object" && !Array.isArray(payload) && payload.result) {
        return payload.result;
      }
      return payload;
    },
    { documentId, mindmapId },
  );
}

async function editRootNode(page, documentId, mindmapId, text) {
  const responsePromise = page.waitForResponse(
    (response) =>
      response.url().includes(`/api/mindmap/${encodeURIComponent(documentId)}/${encodeURIComponent(mindmapId)}`) &&
      response.request().method() === "POST",
    { timeout: UI_TIMEOUT_MS },
  );
  await page.evaluate(
    async ({ documentId, mindmapId, text }) => {
      const response = await fetch(`/api/mindmap/${encodeURIComponent(documentId)}/${encodeURIComponent(mindmapId)}`, {
        method: "POST",
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          commandName: "mindmap.command.apply",
          documentId,
          mindmapId,
          commands: [{ type: "updateText", mindmapId, nodeId: "root", text }],
        }),
      });
      if (!response.ok) {
        throw new Error(`command_failed:${response.status}`);
      }
    },
    { documentId, mindmapId, text },
  );
  const response = await responsePromise;
  if (!response.ok()) {
    throw new Error(`command_failed:${response.status()}`);
  }
  const projection = await fetchAdapterProjection(page, documentId, mindmapId);
  const root = projection && typeof projection === "object" && projection.root ? projection.root : projection;
  const rootText = root?.data?.text;
  if (rootText !== text) {
    throw new Error(`command_failed:update_text_projection_mismatch text=${JSON.stringify(rootText)}`);
  }
}

async function zoomMindmapAndVerifyViewPatch(page, documentId, mindmapId) {
  const responsePromise = page.waitForResponse(
    (response) =>
      response.url().includes(`/api/mindmap/${encodeURIComponent(documentId)}/${encodeURIComponent(mindmapId)}`) &&
      response.request().method() === "POST" &&
      response.request().postData()?.includes('"type":"patchView"'),
    { timeout: UI_TIMEOUT_MS },
  );
  await page.getByTestId("mindmap-schema-navigator-action-zoomIn").click({ timeout: UI_TIMEOUT_MS });
  const response = await responsePromise;
  if (!response.ok()) {
    throw new Error(`view_command_failed:${response.status()}`);
  }
  await page.waitForFunction(
    () => {
      const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
      return scene instanceof HTMLElement && scene.dataset.viewCommandStatus === "success";
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const projection = await fetchAdapterProjection(page, documentId, mindmapId);
  const scale = projection?.view?.state?.scale;
  if (!(typeof scale === "number" && scale > 1)) {
    const requestPayload = JSON.parse(response.request().postData() || "null");
    throw new Error(
      `view_patch_failed scale=${scale} view=${JSON.stringify(projection?.view ?? null)} patch=${JSON.stringify(
        requestPayload?.commands?.[0]?.patch ?? null,
      )}`,
    );
  }
  return scale;
}

async function centerRootAndVerifyViewPatch(page, documentId, mindmapId) {
  const responsePromise = page.waitForResponse(
    (response) =>
      response.url().includes(`/api/mindmap/${encodeURIComponent(documentId)}/${encodeURIComponent(mindmapId)}`) &&
      response.request().method() === "POST" &&
      response.request().postData()?.includes('"type":"patchView"'),
    { timeout: UI_TIMEOUT_MS },
  );
  await page.getByTestId("mindmap-schema-navigator-action-centerRoot").click({ timeout: UI_TIMEOUT_MS });
  const response = await responsePromise;
  if (!response.ok()) {
    throw new Error(`view_command_failed:centerRoot:${response.status()}`);
  }
  await page.waitForFunction(
    () => {
      const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
      return scene instanceof HTMLElement && scene.dataset.viewCommandStatus === "success";
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  return true;
}

async function exerciseNavigatorActions(page, documentId, mindmapId) {
  const centerRootOk = await centerRootAndVerifyViewPatch(page, documentId, mindmapId);
  const zoomScale = await zoomMindmapAndVerifyViewPatch(page, documentId, mindmapId);
  await page.getByTestId("mindmap-schema-navigator-action-search").click({ timeout: UI_TIMEOUT_MS });
  await page.getByTestId("mindmap-schema-navigator-search").waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
  await page.getByTestId("mindmap-schema-navigator-search").fill("KMIND", { timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
      return scene instanceof HTMLElement && scene.dataset.searchStatus === "ready" && scene.dataset.lastSearchQuery === "KMIND";
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  await page.getByTestId("mindmap-schema-navigator-action-minimap").click({ timeout: UI_TIMEOUT_MS });
  await page.getByTestId("mindmap-schema-minimap").waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
  return {
    centerRootOk,
    zoomOk: typeof zoomScale === "number" && zoomScale > 1,
    searchOk: true,
    minimapOk: true,
    zoomScale,
  };
}

async function openContextMenu(page, targetKind) {
  if (targetKind === "node") {
    const node = page.locator('[data-testid="simple-mind-map-runtime"] .smm-node').first();
    await node.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
    await node.click({ timeout: UI_TIMEOUT_MS });
    await node.click({ button: "right", timeout: UI_TIMEOUT_MS });
  } else {
    await page.getByTestId("simple-mind-map-runtime").click({ button: "right", position: { x: 36, y: 36 }, timeout: UI_TIMEOUT_MS });
  }
  await page.getByTestId("mindmap-schema-context-menu").waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
  const metrics = await readMindmapMetrics(page);
  assert(metrics.schemaChrome.contextMenu?.kind === targetKind, `ui_shell_missing:context_menu_kind expected=${targetKind} actual=${metrics.schemaChrome.contextMenu?.kind}`);
  return metrics.schemaChrome.contextMenu.actions;
}

async function exerciseContextMenuActions(page, mindmapId) {
  const nodeActions = await openContextMenu(page, "node");
  for (const actionId of ["insertChild", "insertSiblingAfter", "deleteNode", "summary", "associativeLine", "expandCollapse", "copyNodeText"]) {
    assert(nodeActions.includes(actionId), `ui_shell_missing:node_context_action=${actionId}`);
  }
  await page.getByTestId("mindmap-schema-context-menu-action-copyNodeText").click({ timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
      return scene instanceof HTMLElement && scene.dataset.lastContextMenuAction === "copyNodeText" && (scene.dataset.copiedNodeText || "").length > 0;
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );

  const before = await readMindmapSnapshotStats(page, mindmapId);
  await openContextMenu(page, "node");
  await page.evaluate(() => {
    const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
    if (scene instanceof HTMLElement) {
      scene.dataset.commandStatus = "smoke-waiting";
      delete scene.dataset.lastSchemaAction;
    }
  });
  await page.getByTestId("mindmap-schema-context-menu-action-insertChild").click({ timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
      return scene instanceof HTMLElement && scene.dataset.lastSchemaAction === "insertChild" && scene.dataset.commandStatus === "success";
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const afterInsert = await readMindmapSnapshotStats(page, mindmapId);

  const canvasActions = await openContextMenu(page, "canvas");
  for (const actionId of ["centerRoot", "fitView", "search", "readonly"]) {
    assert(canvasActions.includes(actionId), `ui_shell_missing:canvas_context_action=${actionId}`);
  }
  assert(!canvasActions.includes("insertChild"), "ui_shell_missing:canvas_context_hides_node_action");

  return {
    nodeMenuOk: nodeActions.includes("insertChild") && nodeActions.includes("copyNodeText"),
    canvasMenuOk: canvasActions.includes("centerRoot") && canvasActions.includes("readonly") && !canvasActions.includes("insertChild"),
    copyTextOk: true,
    insertChildOk: afterInsert.nodeCount >= before.nodeCount + 1,
    beforeNodeCount: before.nodeCount,
    afterInsertNodeCount: afterInsert.nodeCount,
  };
}

async function waitForMindmapText(page, mindmapId, text, stage) {
  await page.waitForFunction(
    ({ mindmapId, text }) => {
      const registry = window.__MNOTE_LEPTOS_MINDMAP_BRIDGES__ || {};
      const bridge = registry[mindmapId];
      const snapshot = bridge && typeof bridge.getSnapshot === "function" ? bridge.getSnapshot() : null;
      const root =
        snapshot && typeof snapshot === "object" && !Array.isArray(snapshot) && "root" in snapshot
          ? snapshot.root
          : snapshot;
      const stack = root ? [root] : [];
      while (stack.length > 0) {
        const node = stack.pop();
        if (!node || typeof node !== "object" || Array.isArray(node)) continue;
        if (node.data && node.data.text === text) return true;
        if (Array.isArray(node.children)) stack.push(...node.children);
      }
      return false;
    },
    { mindmapId, text },
    { timeout: UI_TIMEOUT_MS },
  ).catch((error) => {
    throw new Error(`reload_mismatch:${stage}:${error.message}`);
  });
}

async function main() {
  await fs.rm(OUTPUT_DIR, { recursive: true, force: true });
  await fs.mkdir(OUTPUT_DIR, { recursive: true });

  const portReport = [checkPort(3000), checkPort(8000)];
  const screenshots = [];
  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 createdIds = [];
  let result = {
    ok: false,
    task: TASK,
    baseUrl: BASE_URL,
    documentId: null,
    mindmapId: null,
    nodeCount: 0,
    edgeCount: 0,
    toolbarActions: null,
    sidebarActions: null,
    kernelRevision: null,
    adapterSource: null,
    viewScale: null,
    navigatorActions: null,
    contextMenuActions: null,
    keyboardActions: null,
    screenshots,
    ports: portReport,
  };

  try {
    await ensureAuthenticated(page, context.request);
    const doc = await createTempDocument(context.request, null);
    createdIds.push(doc.documentId);
    const title = `task166-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);
    const inserted = await assertMindmapReady(page, "insert");
    screenshots.push(await screenshot(page, "01-after-insert-floating-overlay"));
    screenshots.push(await screenshot(page, "toolbar-actions"));

    const mindmapId = inserted.mindmapId;
    assert(mindmapId, "insert: mindmapId 缺失");
    result.mindmapId = mindmapId;
    const insertedProjection = await fetchAdapterProjection(page, doc.documentId, mindmapId);
    result.kernelRevision =
      typeof insertedProjection?.kernelRevision === "number" ? insertedProjection.kernelRevision : null;
    result.adapterSource =
      typeof insertedProjection?.source === "string"
        ? insertedProjection.source
        : typeof insertedProjection?.compatPayload?.source === "string"
          ? insertedProjection.compatPayload.source
          : null;

    const editedText = `KMIND-${Date.now().toString().slice(-5)}`;
    await editRootNode(page, doc.documentId, mindmapId, editedText);
    const edited = await assertMindmapReady(page, "edit");
    screenshots.push(await screenshot(page, "02-after-edit"));

    await verifyReadonlyToolbarState(page, "toolbar");
    const toolbarActions = await exerciseToolbarNodeActions(page, doc.documentId, mindmapId);
    assert(toolbarActions.insertChildOk, "command_failed:insertChild");
    assert(toolbarActions.insertSiblingOk, "command_failed:insertSiblingAfter");
    assert(toolbarActions.deleteOk, "command_failed:deleteNode");
    assert(
      toolbarActions.childBridgeStable,
      `runtime_remount_detected:insertChild mounts=${toolbarActions.childRuntimeMountCountBefore}->${toolbarActions.childRuntimeMountCountAfter} mountReason=${toolbarActions.childRuntimeMountReason} fetchReason=${toolbarActions.childFetchSceneReason} activeNode=${toolbarActions.childCommandActiveNodeId} applyMode=${toolbarActions.childCommandApplyMode} runtimeError=${toolbarActions.childCommandRuntimeError} runtimeMessage=${toolbarActions.childCommandRuntimeMessage} localErrors=${toolbarActions.childCommandLocalApplyErrors}`,
    );
    assert(toolbarActions.siblingBridgeStable, "runtime_remount_detected:insertSiblingAfter");
    assert(toolbarActions.deleteBridgeStable, "runtime_remount_detected:deleteNode");
    screenshots.push(await screenshot(page, "03-after-toolbar-actions"));

    const keyboardActions = await exerciseKeyboardShortcuts(page, mindmapId);
    assert(keyboardActions.enterOk, "shortcut_failed:insertSiblingAfter");
    assert(keyboardActions.deleteOk, "shortcut_failed:deleteNode");
    assert(
      keyboardActions.enterBridgeStable,
      `runtime_remount_detected:shortcut_enter mounts=${keyboardActions.enterRuntimeMountCountBefore}->${keyboardActions.enterRuntimeMountCountAfter} mountReason=${keyboardActions.enterRuntimeMountReason} fetchReason=${keyboardActions.enterFetchSceneReason} activeNode=${keyboardActions.enterCommandActiveNodeId} applyMode=${keyboardActions.enterCommandApplyMode} runtimeError=${keyboardActions.enterCommandRuntimeError} runtimeMessage=${keyboardActions.enterCommandRuntimeMessage} localErrors=${keyboardActions.enterCommandLocalApplyErrors}`,
    );
    assert(keyboardActions.deleteBridgeStable, "runtime_remount_detected:shortcut_delete");
    assert(keyboardActions.rootStillExists, "shortcut_failed:mindmap_root_deleted");
    screenshots.push(await screenshot(page, "03b-after-keyboard-actions"));

    for (const [panelId, name] of [
      ["nodeStyle", "sidebar-node-style"],
      ["baseStyle", "sidebar-base-style"],
      ["theme", "sidebar-theme"],
      ["structure", "sidebar-structure"],
      ["outline", "sidebar-outline"],
    ]) {
      await page.getByTestId(`mindmap-schema-sidebar-tab-${panelId}`).click({ timeout: UI_TIMEOUT_MS });
      screenshots.push(await screenshot(page, name));
    }
    const sidebarActions = await exerciseSidebarActions(page, doc.documentId, mindmapId);
    assert(sidebarActions.themeOk, "command_failed:setTheme");
    assert(sidebarActions.layoutOk, "command_failed:setLayout");
    assert(sidebarActions.nodeStyleCompatOk, "command_failed:nodeStyleCompat");
    assert(sidebarActions.baseStyleCompatOk, "command_failed:baseStyleCompat");
    assert(sidebarActions.outlineDerivedOk, "ui_shell_missing:outline");
    screenshots.push(await screenshot(page, "sidebar-actions"));
    screenshots.push(await screenshot(page, "navigator-default"));
    const navigatorActions = await exerciseNavigatorActions(page, doc.documentId, mindmapId);
    assert(navigatorActions.centerRootOk, "view_command_failed:centerRoot");
    assert(navigatorActions.zoomOk, "view_command_failed:zoomIn");
    assert(navigatorActions.searchOk, "ui_shell_missing:search");
    assert(navigatorActions.minimapOk, "ui_shell_missing:minimap");
    screenshots.push(await screenshot(page, "navigator-zoomed"));
    screenshots.push(await screenshot(page, "navigator-minimap"));

    const contextMenuActions = await exerciseContextMenuActions(page, mindmapId);
    assert(contextMenuActions.nodeMenuOk, "ui_shell_missing:node_context_menu");
    assert(contextMenuActions.canvasMenuOk, "ui_shell_missing:canvas_context_menu");
    assert(contextMenuActions.copyTextOk, "command_failed:copyNodeText");
    assert(contextMenuActions.insertChildOk, "command_failed:context_insertChild");
    screenshots.push(await screenshot(page, "context-menu-actions"));

    await page.reload({ waitUntil: "domcontentloaded", timeout: UI_TIMEOUT_MS });
    const reloaded = await assertMindmapReady(page, "reload");
    await waitForMindmapText(page, mindmapId, editedText, "reload");
    const reloadStats = await readMindmapSnapshotStats(page, mindmapId);
    const expectedReloadNodeCount = contextMenuActions?.afterInsertNodeCount ?? toolbarActions.afterDeleteNodeCount;
    assert(
      reloadStats.nodeCount === expectedReloadNodeCount,
      `reload_mismatch:toolbar_node_count expected=${expectedReloadNodeCount} actual=${reloadStats.nodeCount}`,
    );
    const reloadProjection = await fetchAdapterProjection(page, doc.documentId, mindmapId);
    assert(reloadProjection?.theme === "classic4", `reload_mismatch:theme actual=${JSON.stringify(reloadProjection?.theme)}`);
    assert(reloadProjection?.layout === "mindMap", `reload_mismatch:layout actual=${JSON.stringify(reloadProjection?.layout)}`);
    const reloadNodeStyleFill = findNodeFillColorByUid(reloadProjection?.root, sidebarActions.nodeStyleTargetNodeId);
    assert(
      reloadNodeStyleFill === "#dbeafe",
      `reload_mismatch:node_style active=${JSON.stringify(sidebarActions.nodeStyleTargetNodeId)} actual=${JSON.stringify(reloadProjection?.root?.data)}`,
    );
    assert(
      reloadProjection?.compatPayload?.style?.map?.lineStyle === "curve",
      `reload_mismatch:base_style actual=${JSON.stringify(reloadProjection?.compatPayload?.style)}`,
    );
    screenshots.push(await screenshot(page, "04-after-reload"));

    result = {
      ...result,
      ok: true,
      nodeCount: reloaded.nodeCount,
      edgeCount: reloaded.edgeCount,
      toolbarActions,
      keyboardActions,
      sidebarActions,
      navigatorActions,
      contextMenuActions,
      kernelRevision: result.kernelRevision,
      adapterSource: result.adapterSource,
      viewScale: navigatorActions.zoomScale,
    };
    await writeResult(result);
    process.stdout.write(`${JSON.stringify({ ...result, resultPath: RESULT_PATH }, null, 2)}\n`);
  } catch (error) {
    const metrics = await readMindmapMetrics(page).catch(() => null);
    const failureStage =
      metrics?.errorStage ||
      (error instanceof Error && /projection_load_failed|adapter_init_failed|runtime_render_failed|ui_shell_missing|command_failed|reload_mismatch/.test(error.message)
        ? error.message
        : "runtime_render_failed");
    result = {
      ...result,
      ok: false,
      error: error instanceof Error ? error.message : String(error),
      failureStage,
      nodeCount: metrics?.nodeCount ?? result.nodeCount,
      edgeCount: metrics?.edgeCount ?? result.edgeCount,
    };
    screenshots.push(await screenshot(page, "99-failure").catch(() => null));
    await writeResult(result);
    throw error;
  } finally {
    if (createdIds.length > 0) {
      await cleanupDocuments(context.request, createdIds).catch(() => undefined);
    }
    await page.close().catch(() => undefined);
    await context.close().catch(() => undefined);
    await browser.close().catch(() => undefined);
  }
}

if (require.main === module) {
  main().catch((error) => {
    console.error(error instanceof Error ? error.stack || error.message : String(error));
    process.exit(1);
  });
}
