#!/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,
  openFilesystemView,
  renameDocument,
} = require("./tree-shell-smoke-helpers");

const TASK = "task169-mindmap-realtime-smoke";
const OUTPUT_DIR = path.join(process.cwd(), "tmp", TASK);
const RESULT_PATH = path.join(OUTPUT_DIR, "result.json");
const LIVE_WAIT_MS = Number(process.env.MNOTE_MINDMAP_REALTIME_WAIT_MS || 12_000);
const BAD_TEXT_PATTERN = /ArgumentValidationError|domainEventHint|domainEventPlan|streamDeltaHint|command_failed|502 Bad Gateway/i;

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 installTreeEventRecorder(page) {
  await page.addInitScript(() => {
    window.__MNOTE_SMOKE_TREE_EVENTS__ = [];
    const record = (name, event) => {
      const detail = event && event.detail ? event.detail : null;
      window.__MNOTE_SMOKE_TREE_EVENTS__.push({
        name,
        at: Date.now(),
        revision: detail && detail.revision ? String(detail.revision) : "",
        data: detail && detail.payload && detail.payload.data ? detail.payload.data : null,
        eventType:
          detail &&
          detail.payload &&
          detail.payload.overview &&
          Array.isArray(detail.payload.overview.domain_events) &&
          detail.payload.overview.domain_events[0]
            ? detail.payload.overview.domain_events[0].event_type || ""
            : "",
      });
    };
    window.addEventListener("tree:snapshot", (event) => record("tree:snapshot", event));
    window.addEventListener("tree:delta", (event) => record("tree:delta", event));
    window.addEventListener("tree:resync", (event) => record("tree:resync", event));
  });
}

async function installMindmapLoadingRecorder(page) {
  await page.addInitScript(() => {
    window.__MNOTE_MINDMAP_LOADING_EVENTS__ = [];
    const recordLoading = (node, reason) => {
      if (!(node instanceof HTMLElement)) return;
      const loading = node.matches?.('[data-testid="mindmap-scene-loading"]')
        ? node
        : node.querySelector?.('[data-testid="mindmap-scene-loading"]');
      if (!(loading instanceof HTMLElement)) return;
      window.__MNOTE_MINDMAP_LOADING_EVENTS__.push({
        at: Date.now(),
        reason,
        text: loading.textContent || "",
        url: window.location.href,
      });
    };
    const start = () => {
      if (window.__MNOTE_MINDMAP_LOADING_OBSERVER__) return;
      const target = document.documentElement || document.body;
      if (!target) {
        window.setTimeout(start, 0);
        return;
      }
      recordLoading(target, "initial-scan");
      const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
          mutation.addedNodes.forEach((node) => recordLoading(node, "added-node"));
        });
      });
      observer.observe(target, { childList: true, subtree: true });
      window.__MNOTE_MINDMAP_LOADING_OBSERVER__ = observer;
    };
    start();
  });
}

function attachNetworkCapture(page, label, records) {
  page.on("request", (request) => {
    const url = request.url();
    if (url.includes("/api/tree/events")) {
      records.push({ type: "request", label, method: request.method(), url });
    }
  });
  page.on("response", async (response) => {
    const url = response.url();
    if (
      !url.includes("/api/tree/events") &&
      !url.includes("/api/mindmap/") &&
      !url.includes("/mindmap/") &&
      !url.includes("/api/documents/save")
    ) {
      return;
    }
    const request = response.request();
    const method = request.method();
    const status = response.status();
    let responseText = null;
    if (method !== "GET" || status >= 400 || url.includes("/api/documents/save")) {
      responseText = await response.text().catch((error) => `<<read_response_failed:${error.message}>>`);
    }
    records.push({
      type: "response",
      label,
      method,
      url,
      status,
      requestBody: request.postData() || null,
      responseText: responseText ? responseText.slice(0, 12000) : null,
    });
  });
  page.on("requestfailed", (request) => {
    const url = request.url();
    if (url.includes("/api/tree/events") || url.includes("/api/mindmap/") || url.includes("/api/documents/save")) {
      records.push({
        type: "requestfailed",
        label,
        method: request.method(),
        url,
        failure: request.failure()?.errorText || null,
        requestBody: request.postData() || null,
      });
    }
  });
  page.on("console", (message) => {
    const text = message.text();
    if (message.type() === "error" || /mindmap|tree live|EventSource|502|command_failed/i.test(text)) {
      records.push({
        type: "console",
        label,
        level: message.type(),
        text: text.slice(0, 2000),
      });
    }
  });
}

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 readPageState(page) {
  return page.evaluate(() => {
    const html = document.documentElement;
    const root = document.querySelector('[data-testid="mnote-mindmap-editor-root"]');
    const runtime = document.querySelector('[data-testid="simple-mind-map-runtime"]');
    const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
    const error = document.querySelector('[data-testid="leptos-mindmap-error"]');
    const loading = document.querySelector('[data-testid="mindmap-scene-loading"]');
    const assetRows = Array.from(document.querySelectorAll("#sidebar-file-tree-root [data-asset-id]"))
      .map((node) => (node instanceof HTMLElement ? node.getAttribute("data-asset-id") || "" : ""))
      .filter(Boolean);
    const fileTreeAssetRowElements = Array.from(document.querySelectorAll("#sidebar-file-tree-root [data-asset-id]"))
      .map((node) => (node instanceof HTMLElement ? node.closest(".tree-row") || node : null))
      .filter((node, index, rows) => node instanceof HTMLElement && rows.indexOf(node) === index);
    const mindmapRows = fileTreeAssetRowElements
      .filter((node) => {
        if (!(node instanceof HTMLElement)) return false;
        const objectKind = node.getAttribute("data-object-kind") || "";
        const objectIdentity = node.getAttribute("data-object-identity") || "";
        const assetId = node.getAttribute("data-asset-id") || "";
        return objectKind === "mindmap" || objectIdentity.includes('"objectKind":"mindmap"') || assetId.startsWith("mindmap");
      })
      .map((node) => {
        const element = node;
        const objectIdentity = element.getAttribute("data-object-identity") || "";
        let parsedDocumentId = "";
        try {
          parsedDocumentId = JSON.parse(objectIdentity).documentId || "";
        } catch {
          parsedDocumentId = "";
        }
        return {
          rowId: element.getAttribute("data-row-id") || "",
          documentId: element.getAttribute("data-document-id") || element.getAttribute("data-doc-id") || parsedDocumentId,
          assetId: element.getAttribute("data-asset-id") || "",
          objectKind: element.getAttribute("data-object-kind") || "",
          objectIdentity,
          title: element.textContent || "",
        };
      });
    return {
      url: window.location.href,
      bodyText: (document.body?.innerText || "").slice(0, 8000),
      mindmapId: root instanceof HTMLElement ? root.dataset.mnoteMindmapId || null : null,
      runtimeReady: runtime instanceof HTMLElement ? runtime.dataset.runtimeReady === "true" : false,
      runtimeMountCount: scene instanceof HTMLElement ? Number(scene.dataset.runtimeMountCount || "0") : 0,
      runtimeProjectionApplyCount:
        scene instanceof HTMLElement ? Number(scene.dataset.runtimeProjectionApplyCount || "0") : 0,
      lastRuntimeMountReason: scene instanceof HTMLElement ? scene.dataset.lastRuntimeMountReason || "" : "",
      lastFetchSceneReason: scene instanceof HTMLElement ? scene.dataset.lastFetchSceneReason || "" : "",
      backgroundProjectionRefresh: scene instanceof HTMLElement ? scene.dataset.backgroundProjectionRefresh || "" : "",
      hasMindmapError: Boolean(error),
      hasMindmapLoading: Boolean(loading),
      commandStatus: scene instanceof HTMLElement ? scene.dataset.commandStatus || "" : "",
      treeLiveStatus: html.getAttribute("data-mnote-tree-live-status") || "",
      treeLiveApplied: html.getAttribute("data-mnote-tree-live-applied") || "",
      treeLiveRevision: html.getAttribute("data-mnote-tree-live-revision") || "",
      treeLiveApplyError: html.getAttribute("data-mnote-tree-live-apply-error") || "",
      lastMindmapAssetOpenMode: html.getAttribute("data-mnote-last-mindmap-asset-open-mode") || "",
      lastMindmapAssetId: html.getAttribute("data-mnote-last-mindmap-asset-id") || "",
      objectEditor:
        document.querySelector("[data-mnote-object-editor]") instanceof HTMLElement
          ? document.querySelector("[data-mnote-object-editor]").getAttribute("data-mnote-object-editor") || ""
          : "",
      objectIdentity:
        document.querySelector("[data-mnote-object-identity]") instanceof HTMLElement
          ? document.querySelector("[data-mnote-object-identity]").getAttribute("data-mnote-object-identity") || ""
          : "",
      localStorageKeys: Object.keys(window.localStorage || {}).filter((key) =>
        /mnote\.leptos-tiptap-spike\.document|__mindmap_object__|mindmap-object/.test(key),
      ),
      mindmapLoadingEvents: window.__MNOTE_MINDMAP_LOADING_EVENTS__ || [],
      fileTreeText: (document.getElementById("sidebar-file-tree-root")?.textContent || "").slice(0, 4000),
      fileTreeAssetIds: assetRows,
      fileTreeMindmapRows: mindmapRows,
      treeEvents: window.__MNOTE_SMOKE_TREE_EVENTS__ || [],
    };
  });
}

async function readMindmapRuntimeStabilityState(page, mindmapId) {
  return page.evaluate(
    ({ mindmapId }) => {
      const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
      const registry = window.__MNOTE_LEPTOS_MINDMAP_BRIDGES__ || {};
      const bridge = registry[mindmapId];
      const instance = bridge?.instance;
      const topicNode = instance?.renderer?.findNodeByUid?.("topic") || null;
      let topicRect = null;
      if (typeof topicNode?.getRect === "function") {
        try {
          topicRect = topicNode.getRect();
        } catch (error) {
          topicRect = null;
        }
      }
      const viewTransform = instance?.view?.getTransformData?.() || null;
      return {
        runtimeMountCount: scene instanceof HTMLElement ? Number(scene.dataset.runtimeMountCount || "0") : 0,
        runtimeProjectionApplyCount:
          scene instanceof HTMLElement ? Number(scene.dataset.runtimeProjectionApplyCount || "0") : 0,
        lastRuntimeMountReason: scene instanceof HTMLElement ? scene.dataset.lastRuntimeMountReason || "" : "",
        lastRuntimeProjectionApplyReason:
          scene instanceof HTMLElement ? scene.dataset.lastRuntimeProjectionApplyReason || "" : "",
        runtimeProjectionDeferred:
          scene instanceof HTMLElement ? scene.dataset.runtimeProjectionDeferred || "" : "",
        lastRuntimeProjectionDeferReason:
          scene instanceof HTMLElement ? scene.dataset.lastRuntimeProjectionDeferReason || "" : "",
        backgroundProjectionRefresh: scene instanceof HTMLElement ? scene.dataset.backgroundProjectionRefresh || "" : "",
        commandStatus: scene instanceof HTMLElement ? scene.dataset.commandStatus || "" : "",
        commandApplyMode: scene instanceof HTMLElement ? scene.dataset.commandApplyMode || "" : "",
        topicRect: topicRect
          ? {
              x: Number(topicRect.x ?? topicRect.left ?? 0),
              y: Number(topicRect.y ?? topicRect.top ?? 0),
              width: Number(topicRect.width ?? 0),
              height: Number(topicRect.height ?? 0),
            }
          : null,
        viewTransform,
      };
    },
    { mindmapId },
  );
}

function stableJson(value) {
  return JSON.stringify(value ?? null);
}

async function waitForMindmapRuntimeViewSettled(page, mindmapId, label) {
  let previous = await readMindmapRuntimeStabilityState(page, mindmapId);
  for (let index = 0; index < 12; index += 1) {
    await page.waitForTimeout(350);
    const current = await readMindmapRuntimeStabilityState(page, mindmapId);
    if (
      stableJson(current.viewTransform) === stableJson(previous.viewTransform) &&
      stableJson(current.topicRect) === stableJson(previous.topicRect) &&
      current.runtimeMountCount === previous.runtimeMountCount &&
      current.runtimeProjectionApplyCount === previous.runtimeProjectionApplyCount
    ) {
      return current;
    }
    previous = current;
  }
  throw new Error(`mindmap_runtime_view_not_settled:${label}`);
}

function rectCenter(rect) {
  if (!rect) return null;
  return {
    x: rect.x + rect.width / 2,
    y: rect.y + rect.height / 2,
  };
}

function centerDistance(a, b) {
  const ca = rectCenter(a);
  const cb = rectCenter(b);
  if (!ca || !cb) return 0;
  return Math.hypot(ca.x - cb.x, ca.y - cb.y);
}

async function dispatchSyntheticMindmapTreeSignal(page, documentId, mindmapId, eventName) {
  return page.evaluate(
    ({ documentId, mindmapId, eventName }) => {
      const cursorId = `smoke-command-${Date.now()}`;
      const payload =
        eventName === "tree:delta"
          ? {
              kind: "delta",
              revision: JSON.stringify({ id: cursorId, createdAt: new Date().toISOString() }),
              data: {
                op: "resync_required",
                reason: "mindmap.put",
                documentId,
                blockId: mindmapId,
              },
            }
          : {
              kind: "resync",
              revision: JSON.stringify({ id: cursorId, createdAt: new Date().toISOString() }),
              overview: {
                command_logs: [
                  {
                    id: cursorId,
                    command_id: cursorId,
                    target_page_id: documentId,
                    target_block_id: mindmapId,
                    aggregate_type: "block",
                    aggregate_id: mindmapId,
                    payload: {
                      streamDelta: {
                        op: "resync_required",
                        reason: "mindmap.put",
                        documentId,
                        blockId: mindmapId,
                      },
                    },
                  },
                ],
                domain_events: [],
              },
            };
      window.dispatchEvent(new CustomEvent(eventName, { detail: { payload, revision: payload.revision } }));
      return payload;
    },
    { documentId, mindmapId, eventName },
  );
}

async function assertMindmapRuntimeDoesNotRefreshForLiveSignals(page, documentId, mindmapId, failures, label) {
  await waitForMindmapRuntimeViewSettled(page, mindmapId, label);
  const before = await readPageState(page);
  const beforeRuntime = await readMindmapRuntimeStabilityState(page, mindmapId);
  if (before.hasMindmapError || before.hasMindmapLoading || !before.runtimeReady) {
    failures.push({
      code: "mindmap_unstable_before_live_signal",
      label,
      state: before,
    });
    return { before, afterResync: before, afterDelta: before };
  }

  const resyncPayload = await dispatchSyntheticMindmapTreeSignal(page, documentId, mindmapId, "tree:resync");
  await page.waitForTimeout(2_500);
  const afterResync = await readPageState(page);
  const afterResyncRuntime = await readMindmapRuntimeStabilityState(page, mindmapId);
  if (afterResync.runtimeMountCount !== before.runtimeMountCount) {
    failures.push({
      code: "mindmap_resync_remounted_runtime",
      label,
      before,
      after: afterResync,
      payload: resyncPayload,
    });
  }
  if (afterResync.runtimeProjectionApplyCount !== before.runtimeProjectionApplyCount) {
    failures.push({
      code: "mindmap_resync_applied_projection_despite_usability_first",
      label,
      before,
      after: afterResync,
      payload: resyncPayload,
    });
  }
  if (stableJson(afterResyncRuntime.viewTransform) !== stableJson(beforeRuntime.viewTransform)) {
    failures.push({
      code: "mindmap_resync_changed_view_transform",
      label,
      before: beforeRuntime,
      after: afterResyncRuntime,
      payload: resyncPayload,
    });
  }
  if (centerDistance(beforeRuntime.topicRect, afterResyncRuntime.topicRect) > 2) {
    failures.push({
      code: "mindmap_resync_moved_topic_node",
      label,
      before: beforeRuntime,
      after: afterResyncRuntime,
      payload: resyncPayload,
    });
  }

  const deltaPayload = await dispatchSyntheticMindmapTreeSignal(page, documentId, mindmapId, "tree:delta");
  await page.waitForTimeout(2_500);
  const afterDelta = await readPageState(page);
  const afterDeltaRuntime = await readMindmapRuntimeStabilityState(page, mindmapId);
  if (afterDelta.runtimeMountCount !== afterResync.runtimeMountCount) {
    failures.push({
      code: "mindmap_delta_remounted_runtime",
      label,
      before: afterResync,
      after: afterDelta,
      payload: deltaPayload,
    });
  }
  if (afterDelta.runtimeProjectionApplyCount !== afterResync.runtimeProjectionApplyCount) {
    failures.push({
      code: "mindmap_delta_applied_projection_despite_usability_first",
      label,
      before: afterResync,
      after: afterDelta,
      payload: deltaPayload,
    });
  }
  if (stableJson(afterDeltaRuntime.viewTransform) !== stableJson(afterResyncRuntime.viewTransform)) {
    failures.push({
      code: "mindmap_delta_changed_view_transform",
      label,
      before: afterResyncRuntime,
      after: afterDeltaRuntime,
      payload: deltaPayload,
    });
  }
  if (centerDistance(afterResyncRuntime.topicRect, afterDeltaRuntime.topicRect) > 2) {
    failures.push({
      code: "mindmap_delta_moved_topic_node",
      label,
      before: afterResyncRuntime,
      after: afterDeltaRuntime,
      payload: deltaPayload,
    });
  }
  if (afterDelta.hasMindmapError || afterDelta.hasMindmapLoading) {
    failures.push({
      code: "mindmap_live_signal_left_error_or_loading",
      label,
      after: afterDelta,
    });
  }

  return { before, beforeRuntime, afterResync, afterResyncRuntime, afterDelta, afterDeltaRuntime };
}

async function waitForMindmapReady(page, stage) {
  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__ || {};
        return (
          root instanceof HTMLElement &&
          runtime instanceof HTMLElement &&
          runtime.dataset.runtimeReady === "true" &&
          Boolean(mindmapId) &&
          Boolean(registry[mindmapId])
        );
      },
      null,
      { timeout: UI_TIMEOUT_MS },
    )
    .catch((error) => {
      throw new Error(`${stage}:mindmap_not_ready:${error.message}`);
    });
}

async function waitForMindmapId(page) {
  await waitForMindmapReady(page, "mindmap-id");
  const state = await readPageState(page);
  assert(state.mindmapId, `mindmap_id_missing:${JSON.stringify(state)}`);
  return state.mindmapId;
}

async function waitForDocumentContentToIncludeMindmap(requestContext, documentId, workspaceId, mindmapId) {
  let lastText = "";
  for (let index = 0; index < 45; index += 1) {
    const response = await requestContext.fetch(
      `${BASE_URL}/api/documents/content?documentId=${encodeURIComponent(documentId)}&workspaceId=${encodeURIComponent(workspaceId)}`,
      { method: "GET", timeout: 10_000 },
    );
    lastText = await response.text();
    if (response.ok() && lastText.includes(mindmapId)) {
      return lastText;
    }
    await new Promise((resolve) => setTimeout(resolve, 500));
  }
  throw new Error(`document_content_missing_mindmap:${lastText.slice(0, 3000)}`);
}

async function assertFileTreeMindmapOpenUsesResourceTab(page, documentId, mindmapId, failures) {
  await openFilesystemView(page);
  const opened = await page.evaluate(
    ({ documentId, mindmapId }) => {
      const rows = Array.from(document.querySelectorAll("#sidebar-file-tree-root [data-asset-id]"));
      const row = rows.find((node) => {
        if (!(node instanceof HTMLElement)) return false;
        const assetId = node.getAttribute("data-asset-id") || "";
        const objectIdentity = node.getAttribute("data-object-identity") || "";
        let parsedDocumentId = "";
        try {
          parsedDocumentId = JSON.parse(objectIdentity).documentId || "";
        } catch {
          parsedDocumentId = "";
        }
        const rowDocumentId = node.getAttribute("data-document-id") || node.getAttribute("data-doc-id") || parsedDocumentId;
        return assetId === mindmapId && rowDocumentId === documentId;
      });
      if (!(row instanceof HTMLElement)) {
        return { clicked: false, reason: "mindmap_asset_row_missing" };
      }
      const button = row.querySelector('[data-rust-action="open"], .tree-link');
      if (!(button instanceof HTMLElement)) {
        return { clicked: false, reason: "mindmap_asset_open_button_missing" };
      }
      button.click();
      return {
        clicked: true,
        assetId: row.getAttribute("data-asset-id") || "",
        rowId: row.getAttribute("data-row-id") || "",
        objectIdentity: row.getAttribute("data-object-identity") || "",
        objectKind: row.getAttribute("data-object-kind") || "",
      };
    },
    { documentId, mindmapId },
  );
  if (!opened.clicked) {
    failures.push({ code: "filetree_mindmap_asset_open_row_missing", opened });
    return opened;
  }
  if (!opened.objectIdentity.includes(`"objectKind":"mindmap"`) || !opened.objectIdentity.includes(`"assetId":"${mindmapId}"`)) {
    failures.push({
      code: "filetree_mindmap_asset_row_missing_object_identity",
      opened,
    });
  }
  await page.waitForFunction(
    (mindmapId) => {
      return document.documentElement.getAttribute("data-mnote-last-mindmap-asset-open-mode") === "mindmap-resource-tab"
        && document.documentElement.getAttribute("data-mnote-last-mindmap-asset-id") === mindmapId
        && Boolean(document.querySelector('.mnote-main-tab.is-active[data-mnote-tab-kind="mindmap"]'));
    },
    mindmapId,
    { timeout: UI_TIMEOUT_MS },
  ).catch(() => null);
  const state = await readPageState(page);
  const url = new URL(state.url);
  const tabState = await page.evaluate(({ documentId, mindmapId }) => {
    const identity = `resource:mindmap:${documentId}:${mindmapId}`;
    const tab = document.querySelector(`.mnote-main-tab[data-mnote-main-tab="${CSS.escape(identity)}"]`);
    const panel = document.querySelector(`.mnote-resource-tab-panel[data-mnote-resource-tab-panel="${CSS.escape(identity)}"]`);
    const root = panel?.querySelector('[data-testid="mnote-mindmap-editor-root"]');
    return {
      identity,
      tabExists: tab instanceof HTMLElement,
      tabActive: tab instanceof HTMLElement && tab.classList.contains("is-active"),
      panelVisible: panel instanceof HTMLElement && !panel.hidden,
      objectEditor: panel instanceof HTMLElement ? panel.getAttribute("data-mnote-object-editor") || "" : "",
      rootMindmapId: root instanceof HTMLElement ? root.getAttribute("data-mnote-mindmap-id") || "" : "",
      openMode: document.documentElement.getAttribute("data-mnote-last-mindmap-asset-open-mode") || "",
    };
  }, { documentId, mindmapId });
  if (url.pathname.includes(`/mindmap/${encodeURIComponent(documentId)}/${encodeURIComponent(mindmapId)}`)) {
    failures.push({
      code: "filetree_mindmap_asset_open_used_retired_object_shell",
      opened,
      state,
      tabState,
    });
  }
  if (!tabState.tabExists || !tabState.tabActive || !tabState.panelVisible || tabState.objectEditor !== "mindmap" || tabState.rootMindmapId !== mindmapId) {
    failures.push({
      code: "filetree_mindmap_asset_open_did_not_use_resource_tab",
      opened,
      state,
      tabState,
    });
  }
  await waitForMindmapReady(page, "filetree-resource-tab-open");
  const readyState = await readPageState(page);
  if (readyState.mindmapId !== mindmapId || !readyState.runtimeReady || readyState.hasMindmapError) {
    failures.push({
      code: "filetree_mindmap_asset_resource_tab_not_ready",
      opened,
      readyState,
    });
  }
  return { opened, state: readyState };
}

async function readMindmapResourceTabState(page, documentId, mindmapId) {
  return page.evaluate(
    ({ documentId, mindmapId }) => {
      const identity = `resource:mindmap:${documentId}:${mindmapId}`;
      const tab = document.querySelector(`.mnote-main-tab[data-mnote-main-tab="${CSS.escape(identity)}"]`);
      const activeTab = document.querySelector(".mnote-main-tab.is-active");
      const panel = document.querySelector(
        `.mnote-resource-tab-panel[data-mnote-resource-tab-panel="${CSS.escape(identity)}"]`,
      );
      const root = panel?.querySelector('[data-testid="mnote-mindmap-editor-root"]');
      const pageTab = document.querySelector('[data-mnote-main-tab="page"]');
      const pagePanel = document.querySelector("[data-mnote-page-tab-panel]");
      const resourceHost = document.querySelector("[data-mnote-resource-tab-host]");
      return {
        identity,
        activeTabIdentity: activeTab instanceof HTMLElement ? activeTab.getAttribute("data-mnote-main-tab") || "" : "",
        activeTabKind: activeTab instanceof HTMLElement ? activeTab.getAttribute("data-mnote-tab-kind") || "" : "",
        activeMindmapSelector: Boolean(document.querySelector('.mnote-main-tab.is-active[data-mnote-tab-kind="mindmap"]')),
        tabExists: tab instanceof HTMLElement,
        tabActive: tab instanceof HTMLElement && tab.classList.contains("is-active"),
        tabKind: tab instanceof HTMLElement ? tab.getAttribute("data-mnote-tab-kind") || "" : "",
        panelExists: panel instanceof HTMLElement,
        panelVisible: panel instanceof HTMLElement && !panel.hidden,
        panelObjectEditor: panel instanceof HTMLElement ? panel.getAttribute("data-mnote-object-editor") || "" : "",
        panelObjectIdentity: panel instanceof HTMLElement ? panel.getAttribute("data-mnote-object-identity") || "" : "",
        panelMindmapId: panel instanceof HTMLElement ? panel.getAttribute("data-mnote-mindmap-id") || "" : "",
        rootExists: root instanceof HTMLElement,
        rootObjectEditor: root instanceof HTMLElement ? root.getAttribute("data-mnote-object-editor") || "" : "",
        rootObjectIdentity: root instanceof HTMLElement ? root.getAttribute("data-mnote-object-identity") || "" : "",
        rootMindmapId: root instanceof HTMLElement ? root.getAttribute("data-mnote-mindmap-id") || "" : "",
        pageTabActive: pageTab instanceof HTMLElement && pageTab.classList.contains("is-active"),
        pagePanelVisible: pagePanel instanceof HTMLElement && !pagePanel.hidden,
        resourceHostVisible: resourceHost instanceof HTMLElement && !resourceHost.hidden,
      };
    },
    { documentId, mindmapId },
  );
}

async function assertMindmapResourceTabCanRoundtripWithPageTab(page, documentId, mindmapId, failures, label) {
  const before = await readMindmapResourceTabState(page, documentId, mindmapId);
  const expectedIdentity = `resource:mindmap:${documentId}:${mindmapId}`;
  if (
    before.identity !== expectedIdentity ||
    !before.activeMindmapSelector ||
    !before.tabExists ||
    !before.tabActive ||
    before.tabKind !== "mindmap" ||
    !before.panelVisible ||
    before.panelObjectEditor !== "mindmap" ||
    before.panelObjectIdentity !== expectedIdentity ||
    before.panelMindmapId !== mindmapId ||
    before.rootObjectEditor !== "mindmap" ||
    before.rootObjectIdentity !== expectedIdentity ||
    before.rootMindmapId !== mindmapId
  ) {
    failures.push({
      code: "mindmap_resource_tab_identity_or_panel_invalid",
      label,
      expectedIdentity,
      state: before,
    });
    return { before, skippedRoundtrip: true };
  }

  await page.locator('[data-mnote-main-tab="page"]').first().click({ timeout: UI_TIMEOUT_MS });
  await page.waitForFunction(
    () => {
      const pageTab = document.querySelector('[data-mnote-main-tab="page"]');
      const pagePanel = document.querySelector("[data-mnote-page-tab-panel]");
      const resourceHost = document.querySelector("[data-mnote-resource-tab-host]");
      return (
        pageTab instanceof HTMLElement &&
        pageTab.classList.contains("is-active") &&
        pagePanel instanceof HTMLElement &&
        !pagePanel.hidden &&
        resourceHost instanceof HTMLElement &&
        resourceHost.hidden
      );
    },
    null,
    { timeout: UI_TIMEOUT_MS },
  );
  const afterPageTab = await readMindmapResourceTabState(page, documentId, mindmapId);
  if (!afterPageTab.pageTabActive || !afterPageTab.pagePanelVisible || afterPageTab.resourceHostVisible) {
    failures.push({
      code: "mindmap_resource_tab_page_roundtrip_failed_to_show_page",
      label,
      expectedIdentity,
      state: afterPageTab,
    });
  }

  await page.evaluate(
    ({ identity }) => {
      const tab = document.querySelector(`.mnote-main-tab[data-mnote-main-tab="${CSS.escape(identity)}"]`);
      if (!(tab instanceof HTMLElement)) return false;
      tab.click();
      return true;
    },
    { identity: expectedIdentity },
  );
  await page.waitForFunction(
    ({ identity }) => {
      const tab = document.querySelector(`.mnote-main-tab[data-mnote-main-tab="${CSS.escape(identity)}"]`);
      const panel = document.querySelector(
        `.mnote-resource-tab-panel[data-mnote-resource-tab-panel="${CSS.escape(identity)}"]`,
      );
      return (
        tab instanceof HTMLElement &&
        tab.classList.contains("is-active") &&
        tab.getAttribute("data-mnote-tab-kind") === "mindmap" &&
        panel instanceof HTMLElement &&
        !panel.hidden
      );
    },
    { identity: expectedIdentity },
    { timeout: UI_TIMEOUT_MS },
  );
  const afterMindmapTab = await readMindmapResourceTabState(page, documentId, mindmapId);
  if (
    !afterMindmapTab.activeMindmapSelector ||
    !afterMindmapTab.tabActive ||
    !afterMindmapTab.panelVisible ||
    afterMindmapTab.panelObjectIdentity !== expectedIdentity ||
    afterMindmapTab.rootObjectIdentity !== expectedIdentity ||
    afterMindmapTab.rootMindmapId !== mindmapId
  ) {
    failures.push({
      code: "mindmap_resource_tab_page_roundtrip_failed_to_restore_mindmap",
      label,
      expectedIdentity,
      state: afterMindmapTab,
    });
  }

  return { before, afterPageTab, afterMindmapTab };
}

async function assertSingleMindmapAssetRowStable(page, documentId, mindmapId, expectedObjectIdentity, failures, label) {
  await openFilesystemView(page);
  const state = await readPageState(page);
  const rows = state.fileTreeMindmapRows.filter((row) => row.documentId === documentId);
  if (rows.length !== 1) {
    failures.push({
      code: "filetree_mindmap_asset_row_count_changed",
      label,
      expectedCount: 1,
      actualCount: rows.length,
      rows,
      state,
    });
    return { ok: false, rows, state, objectIdentity: expectedObjectIdentity };
  }
  const row = rows[0];
  if (row.assetId !== mindmapId) {
    failures.push({
      code: "filetree_mindmap_asset_id_changed",
      label,
      expectedAssetId: mindmapId,
      row,
      state,
    });
  }
  if (!row.objectIdentity.includes(`"objectKind":"mindmap"`) || !row.objectIdentity.includes(`"assetId":"${mindmapId}"`)) {
    failures.push({
      code: "filetree_mindmap_asset_identity_invalid",
      label,
      row,
      state,
    });
  }
  if (expectedObjectIdentity && row.objectIdentity !== expectedObjectIdentity) {
    failures.push({
      code: "filetree_mindmap_asset_identity_changed",
      label,
      expectedObjectIdentity,
      row,
      state,
    });
  }
  return {
    ok: failures.length === 0,
    rows,
    state,
    objectIdentity: row.objectIdentity,
  };
}

async function assertFileTreePageMarkdownOpenUsesPageAggregate(page, documentId, mindmapId, failures) {
  await openFilesystemView(page);
  const opened = await page.evaluate(
    ({ documentId }) => {
      const row =
        document.querySelector(`#sidebar-file-tree-root [data-row-id="doc:${CSS.escape(documentId)}"]`) ||
        Array.from(document.querySelectorAll("#sidebar-file-tree-root [data-row-kind='document']")).find((node) => {
          if (!(node instanceof HTMLElement)) return false;
          const rowDocumentId = node.getAttribute("data-document-id") || node.getAttribute("data-doc-id") || "";
          return rowDocumentId === documentId;
        });
      if (!(row instanceof HTMLElement)) {
        return { clicked: false, reason: "page_markdown_row_missing" };
      }
      const button = row.querySelector('[data-rust-action="open"], .tree-link');
      if (!(button instanceof HTMLElement)) {
        return { clicked: false, reason: "page_markdown_open_button_missing" };
      }
      button.click();
      return {
        clicked: true,
        rowId: row.getAttribute("data-row-id") || "",
        objectIdentity: row.getAttribute("data-object-identity") || "",
      };
    },
    { documentId },
  );
  if (!opened.clicked) {
    failures.push({ code: "filetree_page_markdown_open_row_missing", opened });
    return opened;
  }
  if (!opened.objectIdentity.includes(`"objectKind":"page"`) || !opened.objectIdentity.includes(`"documentId":"${documentId}"`)) {
    failures.push({
      code: "filetree_page_markdown_row_missing_object_identity",
      opened,
    });
  }
  await page.waitForURL((url) => url.pathname.includes(`/documents/${encodeURIComponent(documentId)}`), {
    timeout: UI_TIMEOUT_MS,
  }).catch(() => null);
  const state = await readPageState(page);
  const url = new URL(state.url);
  if (!url.pathname.includes(`/documents/${encodeURIComponent(documentId)}`)) {
    failures.push({
      code: "filetree_page_markdown_open_did_not_return_document_page",
      opened,
      state,
    });
  }
  const tabState = await readMindmapResourceTabState(page, documentId, mindmapId);
  if (!tabState.pageTabActive || !tabState.pagePanelVisible || tabState.resourceHostVisible || tabState.activeTabKind === "mindmap") {
    failures.push({
      code: "filetree_page_markdown_open_did_not_activate_page_tab",
      opened,
      state,
      tabState,
    });
  }
  return { opened, state, tabState };
}

function readMindmapBlocksFromDocumentContentText(text) {
  const payload = JSON.parse(text);
  const content = Array.isArray(payload?.content)
    ? payload.content
    : Array.isArray(payload?.result?.content)
      ? payload.result.content
    : Array.isArray(payload?.data?.content)
      ? payload.data.content
      : Array.isArray(payload?.body?.content)
        ? payload.body.content
        : [];
  return content.filter((block) => block?.type === "mindmap" || block?.blockType === "mindmap");
}

async function assertDocumentMindmapBlockUsesReferenceSource(requestContext, documentId, workspaceId, mindmapId, failures, label) {
  const text = await waitForDocumentContentToIncludeMindmap(requestContext, documentId, workspaceId, mindmapId);
  const blocks = readMindmapBlocksFromDocumentContentText(text);
  const target = blocks.find((block) => {
    const props = block?.props && typeof block.props === "object" ? block.props : {};
    return props.mindmapId === mindmapId || props.mindmap_id === mindmapId || block.id === mindmapId || block.blockId === mindmapId;
  });
  if (!target) {
    failures.push({
      code: "document_mindmap_block_reference_missing",
      label,
      mindmapId,
      blocks,
      responseText: text.slice(0, 3000),
    });
    return { ok: false, blocks };
  }
  const props = target.props && typeof target.props === "object" ? target.props : {};
  if (!props.mindmapId || props.rootNodeId !== "root" || Object.prototype.hasOwnProperty.call(props, "data")) {
    failures.push({
      code: "document_mindmap_block_uses_wrong_source",
      label,
      mindmapId,
      props,
      target,
    });
    return { ok: false, target };
  }
  return { ok: true, target };
}

async function waitForMindmapProjectionText(requestContext, documentId, mindmapId, expectedText) {
  let lastText = "";
  for (let index = 0; index < 45; index += 1) {
    const response = await requestContext.fetch(
      `${BASE_URL}/api/mindmap/${encodeURIComponent(documentId)}/${encodeURIComponent(mindmapId)}?view=simple_mind_map_scene&queryName=mindmap.simple_mind_map_scene.get`,
      { method: "GET", timeout: 10_000 },
    );
    lastText = await response.text();
    if (response.ok() && lastText.includes(expectedText)) return lastText;
    await new Promise((resolve) => setTimeout(resolve, 500));
  }
  throw new Error(`mindmap_projection_missing_text:${expectedText}:${lastText.slice(0, 3000)}`);
}

async function readMindmapRuntimeTextState(page, mindmapId, expectedText) {
  return page.evaluate(
    ({ mindmapId, expectedText }) => {
      const registry = window.__MNOTE_LEPTOS_MINDMAP_BRIDGES__ || {};
      const bridge = registry[mindmapId];
      const snapshot = bridge?.getSnapshot?.() ?? bridge?.instance?.getData?.(true) ?? null;
      const root = snapshot && typeof snapshot === "object" && "root" in snapshot ? snapshot.root : snapshot;
      const texts = [];
      const visit = (node) => {
        if (!node || typeof node !== "object") return;
        const data = node.data && typeof node.data === "object" ? node.data : {};
        if (typeof data.text === "string") texts.push(data.text);
        if (Array.isArray(node.children)) node.children.forEach(visit);
      };
      visit(root);
      return {
        texts,
        includesExpectedText: texts.some((text) => text.includes(expectedText)),
        snapshot,
      };
    },
    { mindmapId, expectedText },
  );
}

async function readMindmapProjectionText(requestContext, documentId, mindmapId) {
  const response = await requestContext.fetch(
    `${BASE_URL}/api/mindmap/${encodeURIComponent(documentId)}/${encodeURIComponent(mindmapId)}?view=simple_mind_map_scene&queryName=mindmap.simple_mind_map_scene.get`,
    { method: "GET", timeout: 10_000 },
  );
  return {
    ok: response.ok(),
    status: response.status(),
    text: await response.text(),
  };
}

async function editTopicTextThroughRuntime(page, mindmapId, text) {
  const result = await page.evaluate(
    ({ mindmapId, text }) => {
      const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
      if (scene instanceof HTMLElement) {
        scene.dataset.commandStatus = "smoke-waiting-topic-edit";
      }
      const registry = window.__MNOTE_LEPTOS_MINDMAP_BRIDGES__ || {};
      const bridge = registry[mindmapId];
      const instance = bridge?.instance;
      const topicNode = instance?.renderer?.findNodeByUid?.("topic") || null;
      if (!topicNode || typeof topicNode !== "object") return { ok: false, reason: "topic_node_missing" };
      if (typeof topicNode.setData === "function") {
        topicNode.setData({ text });
      } else if (topicNode.data && typeof topicNode.data === "object") {
        topicNode.data.text = text;
      } else {
        return { ok: false, reason: "topic_node_not_mutable" };
      }
      const snapshot = typeof bridge.getSnapshot === "function" ? bridge.getSnapshot() : instance?.getData?.(true);
      return {
        ok: true,
        snapshotText: snapshot?.children?.[0]?.data?.text ?? null,
        commandStatus: scene instanceof HTMLElement ? scene.dataset.commandStatus || null : null,
      };
    },
    { mindmapId, text },
  );
  assert(result.ok, `topic_runtime_edit_failed:${JSON.stringify(result)}`);
  await page.waitForFunction(
    ({ text }) => {
      const bodyText = document.body?.innerText || "";
      const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
      return bodyText.includes(text) || (scene instanceof HTMLElement && scene.dataset.commandStatus !== "smoke-waiting-topic-edit");
    },
    { text },
    { timeout: UI_TIMEOUT_MS },
  );
  return result;
}

async function readRuntimeTextEditState(page) {
  return page.evaluate(() => {
    const edit = document.querySelector(".smm-node-edit-wrap[contenteditable=\"true\"]");
    const scene = document.querySelector('[data-testid="leptos-mindmap-island"]');
    const active = document.activeElement;
    return {
      exists: edit instanceof HTMLElement,
      visible:
        edit instanceof HTMLElement &&
        edit.style.display !== "none" &&
        edit.getClientRects().length > 0,
      text: edit instanceof HTMLElement ? edit.innerText || edit.textContent || "" : "",
      active:
        edit instanceof HTMLElement &&
        (active === edit || (active instanceof Node && edit.contains(active))),
      runtimeMountCount: scene instanceof HTMLElement ? Number(scene.dataset.runtimeMountCount || "0") : 0,
      runtimeProjectionApplyCount:
        scene instanceof HTMLElement ? Number(scene.dataset.runtimeProjectionApplyCount || "0") : 0,
      runtimeProjectionDeferred:
        scene instanceof HTMLElement ? scene.dataset.runtimeProjectionDeferred || "" : "",
      lastRuntimeProjectionDeferReason:
        scene instanceof HTMLElement ? scene.dataset.lastRuntimeProjectionDeferReason || "" : "",
      backgroundProjectionRefresh:
        scene instanceof HTMLElement ? scene.dataset.backgroundProjectionRefresh || "" : "",
    };
  });
}

async function openTopicTextEdit(page, mindmapId) {
  const result = await page.evaluate(
    ({ mindmapId }) => {
      const registry = window.__MNOTE_LEPTOS_MINDMAP_BRIDGES__ || {};
      const bridge = registry[mindmapId];
      const instance = bridge?.instance;
      const topicNode = instance?.renderer?.findNodeByUid?.("topic") || null;
      const textEdit = instance?.renderer?.textEdit;
      if (!topicNode) return { ok: false, reason: "topic_node_missing" };
      if (typeof textEdit?.show !== "function") return { ok: false, reason: "text_edit_show_missing" };
      textEdit.show({ node: topicNode, isFromKeyDown: false });
      return { ok: true };
    },
    { mindmapId },
  );
  assert(result.ok, `topic_text_edit_open_failed:${JSON.stringify(result)}`);
  const edit = page.locator(".smm-node-edit-wrap[contenteditable=\"true\"]").first();
  await edit.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
  await edit.focus();
  await page.keyboard.press("Control+A");
  await page.keyboard.press("Backspace");
}

async function enterTopicTextDraftWithoutCommit(page, mindmapId, text) {
  await openTopicTextEdit(page, mindmapId);
  await page.keyboard.insertText(text);
  await page.waitForFunction(
    ({ text }) => {
      const edit = document.querySelector(".smm-node-edit-wrap[contenteditable=\"true\"]");
      return edit instanceof HTMLElement && (edit.innerText || edit.textContent || "").includes(text);
    },
    { text },
    { timeout: UI_TIMEOUT_MS },
  );
  return readRuntimeTextEditState(page);
}

async function assertLongLanguageEditSurvivesLiveRefresh(page, requestContext, documentId, mindmapId, failures) {
  const longText =
    `长文本编辑-LIVE-${Date.now().toString().slice(-6)}：` +
    "第一段用于覆盖真实中文连续输入，包含标点、换行前的较长句子，确保编辑框不会因为后台实时刷新而丢焦或闪烁。";
  const secondHalf = "第二段继续输入，验证 live signal 之后仍然可以稳定完成编辑并保存到投影。";
  await openTopicTextEdit(page, mindmapId);
  const beforeEditRuntime = await readMindmapRuntimeStabilityState(page, mindmapId);
  await page.keyboard.insertText(longText);
  const beforeLive = await readRuntimeTextEditState(page);
  const resyncPayload = await dispatchSyntheticMindmapTreeSignal(page, documentId, mindmapId, "tree:resync");
  await page.waitForTimeout(2_500);
  const afterLive = await readRuntimeTextEditState(page);
  if (!afterLive.visible || !afterLive.active || !afterLive.text.includes(longText)) {
    failures.push({
      code: "mindmap_live_refresh_interrupted_long_text_edit",
      beforeLive,
      afterLive,
      payload: resyncPayload,
    });
    return { beforeLive, afterLive, committed: false, longText: longText + secondHalf };
  }
  if (afterLive.runtimeMountCount !== beforeLive.runtimeMountCount) {
    failures.push({
      code: "mindmap_live_refresh_remounted_during_long_text_edit",
      beforeLive,
      afterLive,
      payload: resyncPayload,
    });
  }
  if (afterLive.runtimeProjectionApplyCount !== beforeLive.runtimeProjectionApplyCount) {
    failures.push({
      code: "mindmap_live_refresh_applied_projection_during_long_text_edit",
      beforeLive,
      afterLive,
      payload: resyncPayload,
    });
  }
  await page.keyboard.insertText(secondHalf);
  await page.keyboard.press("Enter");
  await waitForMindmapProjectionText(requestContext, documentId, mindmapId, longText + secondHalf);
  await page.waitForTimeout(2_500);
  const afterCommitRuntime = await readMindmapRuntimeStabilityState(page, mindmapId);
  if (afterCommitRuntime.runtimeMountCount !== beforeEditRuntime.runtimeMountCount) {
    failures.push({
      code: "mindmap_long_text_commit_remounted_runtime",
      before: beforeEditRuntime,
      after: afterCommitRuntime,
    });
  }
  if (afterCommitRuntime.runtimeProjectionApplyCount !== beforeEditRuntime.runtimeProjectionApplyCount) {
    failures.push({
      code: "mindmap_long_text_commit_applied_projection_refresh",
      before: beforeEditRuntime,
      after: afterCommitRuntime,
    });
  }
  if (stableJson(afterCommitRuntime.viewTransform) !== stableJson(beforeEditRuntime.viewTransform)) {
    failures.push({
      code: "mindmap_long_text_commit_changed_view_transform",
      before: beforeEditRuntime,
      after: afterCommitRuntime,
    });
  }
  const postCommitLivePayload = await dispatchSyntheticMindmapTreeSignal(page, documentId, mindmapId, "tree:resync");
  await page.waitForTimeout(2_500);
  const afterPostCommitLiveRuntime = await readMindmapRuntimeStabilityState(page, mindmapId);
  if (afterPostCommitLiveRuntime.runtimeMountCount !== afterCommitRuntime.runtimeMountCount) {
    failures.push({
      code: "mindmap_post_commit_live_remounted_runtime",
      before: afterCommitRuntime,
      after: afterPostCommitLiveRuntime,
      payload: postCommitLivePayload,
    });
  }
  if (afterPostCommitLiveRuntime.runtimeProjectionApplyCount !== afterCommitRuntime.runtimeProjectionApplyCount) {
    failures.push({
      code: "mindmap_post_commit_live_applied_projection_refresh",
      before: afterCommitRuntime,
      after: afterPostCommitLiveRuntime,
      payload: postCommitLivePayload,
    });
  }
  if (stableJson(afterPostCommitLiveRuntime.viewTransform) !== stableJson(afterCommitRuntime.viewTransform)) {
    failures.push({
      code: "mindmap_post_commit_live_changed_view_transform",
      before: afterCommitRuntime,
      after: afterPostCommitLiveRuntime,
      payload: postCommitLivePayload,
    });
  }
  if (centerDistance(afterCommitRuntime.topicRect, afterPostCommitLiveRuntime.topicRect) > 2) {
    failures.push({
      code: "mindmap_post_commit_live_moved_topic_node",
      before: afterCommitRuntime,
      after: afterPostCommitLiveRuntime,
      payload: postCommitLivePayload,
    });
  }
  return {
    beforeEditRuntime,
    beforeLive,
    afterLive,
    committed: true,
    longText: longText + secondHalf,
    afterCommitRuntime,
    afterPostCommitLiveRuntime,
    afterCommit: await readPageState(page),
  };
}

async function waitForPageCondition(page, predicate, timeoutMs = LIVE_WAIT_MS) {
  const deadline = Date.now() + timeoutMs;
  let last = null;
  while (Date.now() < deadline) {
    last = await readPageState(page);
    if (predicate(last)) {
      return { ok: true, state: last };
    }
    await page.waitForTimeout(500);
  }
  return { ok: false, state: last || (await readPageState(page)) };
}

function findBadRecord(records) {
  return records.find((record) => {
    if (record.type === "response" && record.status >= 500) return true;
    return BAD_TEXT_PATTERN.test(`${record.responseText || ""}\n${record.text || ""}\n${record.failure || ""}`);
  });
}

function parseJsonMaybe(value) {
  if (typeof value !== "string" || !value.trim()) return null;
  try {
    return JSON.parse(value);
  } catch {
    return null;
  }
}

function assertMindmapCommandApplyArtifactsDoNotTouchTreeResource(records, failures) {
  const commandApplyResponses = records.filter((record) => {
    if (record.type !== "response" || record.method !== "POST" || !record.url.includes("/api/mindmap/")) {
      return false;
    }
    const requestBody = parseJsonMaybe(record.requestBody);
    return requestBody?.commandName === "mindmap.command.apply";
  });
  if (commandApplyResponses.length === 0) {
    failures.push({ code: "mindmap_command_apply_artifact_response_missing" });
    return { checked: 0, artifacts: [] };
  }

  const artifacts = [];
  let parsedCount = 0;
  let skippedReadFailures = 0;
  for (const record of commandApplyResponses) {
    const responseBody = parseJsonMaybe(record.responseText);
    const eventType = String(responseBody?.artifacts?.domainEvent?.eventType || "");
    const streamDelta = responseBody?.artifacts?.domainEvent?.payload?.streamDelta || null;
    const streamOp = String(streamDelta?.op || "");
    const summary = {
      url: record.url,
      commandName: responseBody?.commandName || "",
      eventType,
      streamOp,
    };
    artifacts.push(summary);
    if (!responseBody) {
      if (String(record.responseText || "").startsWith("<<read_response_failed:")) {
        skippedReadFailures += 1;
        continue;
      }
      failures.push({
        code: "mindmap_command_apply_artifact_response_unparseable",
        record,
      });
      continue;
    }
    parsedCount += 1;
    if (eventType.startsWith("tree.resource.")) {
      failures.push({
        code: "mindmap_command_apply_used_tree_resource_event",
        summary,
      });
    }
    if (streamOp === "resync_required") {
      failures.push({
        code: "mindmap_command_apply_used_tree_resync_delta",
        summary,
      });
    }
  }
  if (parsedCount === 0) {
    failures.push({
      code: "mindmap_command_apply_artifact_response_all_unparseable",
      skippedReadFailures,
    });
  }
  return { checked: parsedCount, skippedReadFailures, artifacts };
}

async function main() {
  await fs.mkdir(OUTPUT_DIR, { recursive: true });
  const browser = await chromium.launch({ headless: true });
  const contextA = await browser.newContext({ viewport: { width: 1440, height: 960 }, locale: "zh-CN" });
  const contextB = await browser.newContext({ viewport: { width: 1440, height: 960 }, locale: "zh-CN" });
  const pageA = await contextA.newPage();
  const pageB = await contextB.newPage();
  await installTreeEventRecorder(pageA);
  await installTreeEventRecorder(pageB);
  await installMindmapLoadingRecorder(pageA);
  await installMindmapLoadingRecorder(pageB);
  const records = [];
  attachNetworkCapture(pageA, "browser-a", records);
  attachNetworkCapture(pageB, "browser-b", records);
  const screenshots = [];
  const createdIds = [];
  const failures = [];
  const result = {
    ok: false,
    task: TASK,
    baseUrl: BASE_URL,
    documentId: null,
    workspaceId: null,
    mindmapId: null,
    liveWaitMs: LIVE_WAIT_MS,
    failures,
    network: records,
    screenshots,
  };

  try {
    await ensureAuthenticated(pageA, contextA.request);
    await ensureAuthenticated(pageB, contextB.request);

    const doc = await createTempDocument(contextA.request, null);
    createdIds.push(doc.documentId);
    const awayDoc = await createTempDocument(contextA.request, null);
    createdIds.push(awayDoc.documentId);
    result.documentId = doc.documentId;
    result.workspaceId = doc.workspaceId;
    await renameDocument(contextA.request, doc.workspaceId, doc.documentId, `task169-mindmap-live-${Date.now().toString().slice(-6)}`);
    await renameDocument(contextA.request, awayDoc.workspaceId, awayDoc.documentId, `task169-mindmap-away-${Date.now().toString().slice(-6)}`);

    await openDocument(pageA, doc.workspaceId, doc.documentId);
    await openDocument(pageB, doc.workspaceId, doc.documentId);
    result.browserBBeforeInsert = await readPageState(pageB);

    await insertMindmapThroughSlash(pageA);
    result.mindmapId = await waitForMindmapId(pageA);
    result.documentMindmapBlockAfterInsert = await assertDocumentMindmapBlockUsesReferenceSource(
      contextA.request,
      doc.documentId,
      doc.workspaceId,
      result.mindmapId,
      failures,
      "after-insert",
    );
    result.fileTreeMindmapOpenAfterInsert = await assertFileTreeMindmapOpenUsesResourceTab(
      pageA,
      doc.documentId,
      result.mindmapId,
      failures,
    );
    result.fileTreeMindmapRowsAfterInsert = await assertSingleMindmapAssetRowStable(
      pageA,
      doc.documentId,
      result.mindmapId,
      null,
      failures,
      "after-insert",
    );
    await waitForMindmapReady(pageA, "after-filetree-mindmap-open");
    result.resourceTabRoundtripAfterInsert = await assertMindmapResourceTabCanRoundtripWithPageTab(
      pageA,
      doc.documentId,
      result.mindmapId,
      failures,
      "after-insert",
    );
    await pageA.waitForTimeout(1000);
    screenshots.push(await screenshot(pageA, "01-browser-a-after-insert"));
    result.retiredRealtimeTopicEditing = {
      status: "skipped",
      reason:
        "task169 当前收窄为 main editor mindmap resource tab P1 smoke；旧 topic/runtime 实时编辑深测依赖 object shell 时代 runtime 行为，已退役为非必过链路。",
      retiredSteps: [
        "assertMindmapRuntimeDoesNotRefreshForLiveSignals",
        "editTopicTextThroughRuntime",
        "enterTopicTextDraftWithoutCommit",
        "assertLongLanguageEditSurvivesLiveRefresh",
        "assertMindmapCommandApplyArtifactsDoNotTouchTreeResource",
      ],
    };
    // 旧实时编辑深测不再作为 task169 的必过主链；下面只保留 resource tab 打开与切换口径。
    await openDocument(pageA, awayDoc.workspaceId, awayDoc.documentId);
    result.indexOpenAfterResourceTabRoundtrip = await assertFileTreePageMarkdownOpenUsesPageAggregate(
      pageA,
      doc.documentId,
      result.mindmapId,
      failures,
    );
    result.retiredResourceTabReopenAfterIndex = {
      status: "skipped",
      reason:
        "task169 已收窄为首次 File Tree 打开 mindmap 资源后的 resource tab 断言；二次重开与旧实时深测不属于当前 P1 口径，已退役以免干扰后续 smoke。",
    };

    const badRecord = findBadRecord(records);
    if (badRecord) {
      failures.push({ code: "mindmap_network_error_or_validator_leak", badRecord });
    }

    result.ok = failures.length === 0;
    await writeResult(result);
    if (!result.ok) {
      throw new Error(`mindmap_realtime_failed:${JSON.stringify(failures, null, 2).slice(0, 6000)}`);
    }
  } catch (error) {
    result.error = error instanceof Error ? error.stack || error.message : String(error);
    screenshots.push(await screenshot(pageA, "99-failure-browser-a").catch(() => null));
    screenshots.push(await screenshot(pageB, "99-failure-browser-b").catch(() => null));
    await writeResult(result);
    throw error;
  } finally {
    await cleanupDocuments(contextA.request, createdIds).catch(() => undefined);
    await contextA.close().catch(() => undefined);
    await contextB.close().catch(() => undefined);
    await browser.close();
  }
}

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