"use client";

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import type {
  DocumentEditorHostProps,
  EditorHostFallbackReason,
} from "@/components/editor/editor-host-types";
import { useDebouncedCallback } from "@/hooks/use-debounced-callback";
import { useEditorBridgeStore } from "@/store/editor-bridge";
import type { EditorReferenceBridge } from "@/store/editor-bridge";
import type { Json } from "@/types/supabase";
import type { DocumentStats } from "@/types/page-options";
import { pickLeptosTiptapRuntimePageOptions } from "@/lib/documents/page-option-semantics";
import {
  blocksFromTiptapDoc,
  editorBlockDocumentFromTiptapDoc,
  tiptapDocFromBlocks,
} from "@/lib/documents/tiptap-content-converter";
import { buildDocumentSavePayload } from "@/lib/documents/save-contract";
import { executePageBodySavePayload } from "@/lib/documents/page-command-client";
import {
  loadLeptosTiptapIslandAssets,
} from "@/components/editor/leptos-tiptap-island-loader";

const EVENT_PREFIX = "mnote:leptos-tiptap-spike";
const PROTOCOL = "mnote.leptos_tiptap.bridge.v1";
const READY_EVENT = `${EVENT_PREFIX}:ready`;
const CHANGE_EVENT = `${EVENT_PREFIX}:change`;
const STATE_EVENT = `${EVENT_PREFIX}:state`;
const STATUS_EVENT = `${EVENT_PREFIX}:status`;
const SELECTION_EVENT = `${EVENT_PREFIX}:selection`;
const HEIGHT_EVENT = `${EVENT_PREFIX}:height`;
const ERROR_EVENT = `${EVENT_PREFIX}:error`;
const COMMAND_EVENT = `${EVENT_PREFIX}:command`;
const FALLBACK_MIN_HEIGHT = 720;
const SAVE_DEBOUNCE_MS = 900;

type IslandRuntimeModule = {
  default: (input?: RequestInfo | URL | Response | BufferSource | WebAssembly.Module) => Promise<unknown>;
  mount: (container: Element, options: unknown) => number;
  unmount: (mountId: number) => void;
};

type RuntimeEnvelope<T = unknown> = {
  protocol?: string;
  runtime?: string;
  version?: string;
  source?: string;
  event?: string;
  payload?: T;
};

type ChangePayload = {
  documentId?: string | null;
  workspaceId?: string | null;
  title?: string;
  content?: unknown;
  meta?: {
    dirtyCount?: number;
    editorFocused?: boolean;
    slashOpen?: boolean;
    toolbarOpen?: boolean;
    selectedBlockIndex?: number | null;
    revision?: number | null;
    conflictDetectionKey?: string | null;
    readOnly?: boolean;
  };
};

type StatePayload = {
  title?: string;
  dirtyCount?: number;
  selectedBlockIndex?: number | null;
  editorFocused?: boolean;
  slashOpen?: boolean;
  toolbarOpen?: boolean;
  readOnly?: boolean;
};

type StatusPayload = {
  currentBlockId?: string | null;
  selectedBlockIndex?: number | null;
};

type SelectionPayload = {
  currentBlockId?: string | null;
  currentBlockIndex?: number | null;
};

type HeightPayload = {
  height?: number;
};

type ErrorPayload = {
  message?: string;
};

type RuntimeBridgeState = {
  ready: boolean;
  runtimeName: string;
  runtimeVersion: string;
  runtimeUrl: string;
  documentId: string;
  workspaceId: string;
  status: string;
  lastChangeAt?: string | null;
  lastSaveRequestAt?: string | null;
  lastError?: string | null;
};

type IslandBootstrapPayload = {
  documentId: string;
  workspaceId: string;
  title: string | null;
  content: unknown;
  revision: number | null;
  conflictDetectionKey: string | null;
  readOnly: boolean;
  pageOptions: RuntimePageOptionsPayload;
};
type RuntimePageOptionsPayload = ReturnType<typeof pickLeptosTiptapRuntimePageOptions>;

function toIsoNow(): string {
  return new Date().toISOString();
}

function flattenText(value: unknown): string {
  if (typeof value === "string") return value;
  if (Array.isArray(value)) return value.map(flattenText).join("");
  if (value && typeof value === "object") {
    const record = value as { text?: unknown; content?: unknown };
    return `${flattenText(record.text)}${flattenText(record.content)}`;
  }
  return "";
}

function serializeHostSyncValue(value: unknown): string {
  try {
    return JSON.stringify(value) ?? "null";
  } catch {
    return String(value);
  }
}

function normalizeRuntimeValue(value: unknown): unknown {
  if (value instanceof Map) {
    return Object.fromEntries(
      Array.from(value.entries()).map(([key, nestedValue]) => [
        key,
        normalizeRuntimeValue(nestedValue),
      ]),
    );
  }
  if (Array.isArray(value)) {
    return value.map((item) => normalizeRuntimeValue(item));
  }
  if (value && typeof value === "object") {
    return Object.fromEntries(
      Object.entries(value as Record<string, unknown>).map(([key, nestedValue]) => [
        key,
        normalizeRuntimeValue(nestedValue),
      ]),
    );
  }
  return value;
}

function buildHostSyncKey(input: {
  documentId: string;
  workspaceId: string;
  title: string | null;
  content: unknown;
  readOnly: boolean;
}): string {
  return serializeHostSyncValue({
    documentId: input.documentId,
    workspaceId: input.workspaceId,
    title: input.title,
    content: input.content,
    readOnly: input.readOnly,
  });
}

function canonicalizeTiptapDoc(value: unknown): Json {
  const normalizedValue = normalizeRuntimeValue(value);
  if (
    normalizedValue &&
    typeof normalizedValue === "object" &&
    (normalizedValue as { type?: unknown }).type === "doc"
  ) {
    return tiptapDocFromBlocks(blocksFromTiptapDoc(normalizedValue) as Json) as Json;
  }
  return tiptapDocFromBlocks(normalizedValue as Json) as Json;
}

function buildStats(blocks: Json): DocumentStats {
  const items = Array.isArray(blocks) ? blocks : [];
  const text = items
    .map((item) =>
      item && typeof item === "object"
        ? flattenText((item as { content?: unknown }).content)
        : "",
    )
    .join("\n")
    .trim();
  const todoItems = items.filter(
    (item) => item && typeof item === "object" && (item as { type?: unknown }).type === "todo",
  );
  const todoDone = todoItems.filter(
    (item) =>
      item &&
      typeof item === "object" &&
      Boolean((item as { props?: { checked?: unknown } }).props?.checked),
  ).length;
  return {
    wordCount: text ? text.split(/\s+/).filter(Boolean).length : 0,
    characterCount: text.length,
    blockCount: items.length,
    todoTotal: todoItems.length,
    todoDone,
  };
}

function isRuntimeEnvelope(value: unknown): value is RuntimeEnvelope {
  if (!value || typeof value !== "object") {
    return false;
  }
  const maybe = value as RuntimeEnvelope;
  return maybe.protocol === PROTOCOL && maybe.source === EVENT_PREFIX;
}

async function loadIslandRuntime(): Promise<{
  runtimeModule: IslandRuntimeModule;
  entryAssetUrl: string;
  wasmAssetUrl: string | null;
}> {
  const { entryAssetUrl, wasmAssetUrl } = await loadLeptosTiptapIslandAssets();
  if (!entryAssetUrl) {
    throw new Error("island manifest 缺少 entryAssetPath");
  }
  const runtimeModule = (await import(
    /* webpackIgnore: true */ entryAssetUrl
  )) as IslandRuntimeModule;
  if (typeof runtimeModule.default !== "function") {
    throw new Error("island entry 缺少默认 wasm 初始化函数");
  }
  if (typeof runtimeModule.mount !== "function") {
    throw new Error("island entry 缺少 mount 导出");
  }
  if (typeof runtimeModule.unmount !== "function") {
    throw new Error("island entry 缺少 unmount 导出");
  }
  await runtimeModule.default(wasmAssetUrl ?? undefined);
  return {
    runtimeModule,
    entryAssetUrl,
    wasmAssetUrl,
  };
}

function dispatchRuntimeCommand(target: EventTarget, payload: unknown) {
  const envelope: RuntimeEnvelope = {
    protocol: PROTOCOL,
    runtime: "leptos-tiptap-island-host",
    version: "1.0.0",
    source: EVENT_PREFIX,
    event: COMMAND_EVENT,
    payload,
  };
  const event = new CustomEvent(COMMAND_EVENT, {
    bubbles: true,
    detail: envelope,
  });
  target.dispatchEvent(event);
}

export function LeptosTiptapIslandEditorHost(props: DocumentEditorHostProps) {
  const mountRef = useRef<HTMLDivElement | null>(null);
  const mountIdRef = useRef<number | null>(null);
  const runtimeModuleRef = useRef<IslandRuntimeModule | null>(null);
  const runtimeTargetRef = useRef<EventTarget | null>(null);
  const latestDocRef = useRef<Json>(tiptapDocFromBlocks(props.initialContent as Json) as Json);
  const latestBlocksRef = useRef<Json>(props.initialContent as Json);
  const currentBlockIdRef = useRef<string | null>(null);
  const hostIdentityRef = useRef({
    documentId: props.documentId,
    workspaceId: props.workspaceId,
    title: props.title ?? null,
    readOnly: Boolean(props.readOnly),
  });
  const revisionRef = useRef<number | null>(props.initialRevision ?? null);
  const conflictDetectionKeyRef = useRef<string | null>(props.initialConflictDetectionKey ?? null);
  const lastHostSyncKeyRef = useRef<string | null>(null);
  const onSnapshotRef = useRef(props.onSnapshot);
  const onStatsChangeRef = useRef(props.onStatsChange);
  const onPersistedMetaChangeRef = useRef(props.onPersistedMetaChange);
  const onHostEventRef = useRef(props.onHostEvent);
  const onRequestFallbackRef = useRef(props.onRequestFallback);
  const bootstrapPayloadRef = useRef<IslandBootstrapPayload>({
    documentId: props.documentId,
    workspaceId: props.workspaceId,
    title: props.title ?? null,
    content: tiptapDocFromBlocks(props.initialContent as Json) as Json,
    revision: props.initialRevision ?? null,
    conflictDetectionKey: props.initialConflictDetectionKey ?? null,
    readOnly: Boolean(props.readOnly),
    pageOptions: pickLeptosTiptapRuntimePageOptions(props.pageOptions),
  });
  const [editorHeight, setEditorHeight] = useState(FALLBACK_MIN_HEIGHT);
  const [bridgeState, setBridgeState] = useState<RuntimeBridgeState>({
    ready: false,
    runtimeName: "leptos-tiptap-island",
    runtimeVersion: "1.0.0",
    runtimeUrl: "",
    documentId: props.documentId,
    workspaceId: props.workspaceId,
    status: "booting",
    lastChangeAt: null,
    lastSaveRequestAt: null,
    lastError: null,
  });
  const debouncedPersistRef = useRef<ReturnType<typeof useDebouncedCallback> | null>(null);

  const mountIdentity = useMemo(
    () => `${props.workspaceId}:${props.documentId}`,
    [props.documentId, props.workspaceId],
  );

  useEffect(() => {
    onSnapshotRef.current = props.onSnapshot;
    onStatsChangeRef.current = props.onStatsChange;
    onPersistedMetaChangeRef.current = props.onPersistedMetaChange;
    onHostEventRef.current = props.onHostEvent;
    onRequestFallbackRef.current = props.onRequestFallback;
    hostIdentityRef.current = {
      documentId: props.documentId,
      workspaceId: props.workspaceId,
      title: props.title ?? null,
      readOnly: Boolean(props.readOnly),
    };
    revisionRef.current = props.initialRevision ?? null;
    conflictDetectionKeyRef.current = props.initialConflictDetectionKey ?? null;
  }, [
    props.documentId,
    props.initialConflictDetectionKey,
    props.initialRevision,
    props.onHostEvent,
    props.onPersistedMetaChange,
    props.onRequestFallback,
    props.onSnapshot,
    props.onStatsChange,
    props.readOnly,
    props.title,
    props.workspaceId,
  ]);

  useEffect(() => {
    bootstrapPayloadRef.current = {
      documentId: props.documentId,
      workspaceId: props.workspaceId,
      title: props.title ?? null,
      content: tiptapDocFromBlocks(props.initialContent as Json) as Json,
      revision: props.initialRevision ?? null,
      conflictDetectionKey: props.initialConflictDetectionKey ?? null,
      readOnly: Boolean(props.readOnly),
      pageOptions: pickLeptosTiptapRuntimePageOptions(props.pageOptions),
    };
  }, [
    mountIdentity,
    props.documentId,
    props.initialConflictDetectionKey,
    props.initialContent,
    props.initialRevision,
    props.pageOptions,
    props.readOnly,
    props.title,
    props.workspaceId,
  ]);

  const requestFallback = useCallback(
    (reason: EditorHostFallbackReason, error: string) => {
      const at = toIsoNow();
      if (reason !== "explicit_fallback") {
        onHostEventRef.current?.({
          kind:
            reason === "save_failed"
              ? "save_failed"
              : reason === "runtime_load_failed"
                ? "runtime_load_failed"
                : reason === "command_failed"
                  ? "command_failed"
                  : "host_init_failed",
          at,
          message: error,
        });
      }
      onRequestFallbackRef.current?.({
        reason,
        error,
        at,
      });
    },
    [],
  );

  const persistDocument = useCallback(async () => {
    const normalizedDoc = latestDocRef.current;
    const normalizedBlocks = blocksFromTiptapDoc(normalizedDoc) as Json;
    const persistedMeta = await executePageBodySavePayload(
      buildDocumentSavePayload({
        documentId: props.documentId,
        workspaceId: props.workspaceId,
        revision: revisionRef.current,
        editorDocument: editorBlockDocumentFromTiptapDoc(normalizedDoc, props.documentId),
        content: normalizedBlocks,
        tiptapDocument: normalizedDoc,
        conflictDetectionKey: conflictDetectionKeyRef.current,
        snapshotCapturedAt: toIsoNow(),
        blockCount: Array.isArray(normalizedBlocks) ? normalizedBlocks.length : 0,
      }),
    );
    revisionRef.current = persistedMeta.revision ?? revisionRef.current;
    conflictDetectionKeyRef.current =
      persistedMeta.conflictDetectionKey ?? conflictDetectionKeyRef.current;
    onPersistedMetaChangeRef.current?.({
      revision: revisionRef.current,
      conflictDetectionKey: conflictDetectionKeyRef.current,
    });
    setBridgeState((prev) => ({
      ...prev,
      ready: true,
      status: "saved",
      lastSaveRequestAt: toIsoNow(),
      lastError: null,
    }));
  }, [props.documentId, props.workspaceId]);

  const debouncedPersist = useDebouncedCallback(() => {
    void persistDocument().catch((error) => {
      const message = error instanceof Error ? error.message : "保存失败";
      setBridgeState((prev) => ({
        ...prev,
        status: "error",
        lastError: message,
      }));
      requestFallback("save_failed", message);
    });
  }, SAVE_DEBOUNCE_MS);

  useEffect(() => {
    debouncedPersistRef.current = debouncedPersist;
  }, [debouncedPersist]);

  useEffect(() => {
    const container = mountRef.current;
    if (!container) {
      return;
    }
    const bootstrapPayload = bootstrapPayloadRef.current;

    let disposed = false;
    let removeListeners: Array<() => void> = [];

    const attachEvent = <T,>(eventName: string, handler: (payload: T) => void) => {
      const listener = (event: Event) => {
        const customEvent = event as CustomEvent<RuntimeEnvelope<T>>;
        if (!isRuntimeEnvelope(customEvent.detail)) {
          return;
        }
        handler((customEvent.detail.payload ?? {}) as T);
      };
      container.addEventListener(eventName, listener);
      removeListeners.push(() => container.removeEventListener(eventName, listener));
    };

    void loadIslandRuntime()
      .then(({ runtimeModule, entryAssetUrl }) => {
        if (disposed) {
          return;
        }
        runtimeModuleRef.current = runtimeModule;
        runtimeTargetRef.current = container;
        container.dataset.editorHostKind = "leptos_tiptap_island";
        container.dataset.mnoteRuntime = "leptos_tiptap_island";
        container.dataset.mnoteRuntimeBridge = "island";
        container.dataset.mnoteRuntimeUrl = entryAssetUrl;

        attachEvent<ChangePayload>(CHANGE_EVENT, (payload) => {
          const hostIdentity = hostIdentityRef.current;
          const nextDoc = canonicalizeTiptapDoc(payload.content ?? latestDocRef.current);
          const nextBlocks = blocksFromTiptapDoc(nextDoc) as Json;
          const nextStats = buildStats(nextBlocks);
          const nextReadOnly = payload.meta?.readOnly ?? hostIdentity.readOnly;
          const nextTitle = payload.title ?? hostIdentity.title;
          latestDocRef.current = nextDoc;
          latestBlocksRef.current = nextBlocks;
          lastHostSyncKeyRef.current = buildHostSyncKey({
            documentId: hostIdentity.documentId,
            workspaceId: hostIdentity.workspaceId,
            title: nextTitle,
            content: nextDoc,
            readOnly: nextReadOnly,
          });
          onSnapshotRef.current?.({ blocks: nextBlocks, stats: nextStats });
          onStatsChangeRef.current?.(nextStats);
          if (payload.meta) {
            revisionRef.current =
              typeof payload.meta.revision === "number"
                ? payload.meta.revision
                : revisionRef.current;
            conflictDetectionKeyRef.current =
              typeof payload.meta.conflictDetectionKey === "string"
                ? payload.meta.conflictDetectionKey
                : conflictDetectionKeyRef.current;
          }
          setBridgeState((prev) => ({
            ...prev,
            ready: true,
            status: "dirty",
            lastChangeAt: toIsoNow(),
            lastError: null,
          }));
          debouncedPersistRef.current?.();
        });

        attachEvent<StatePayload>(STATE_EVENT, (payload) => {
          setBridgeState((prev) => ({
            ...prev,
            ready: true,
            status:
              payload.readOnly === true
                ? "read_only"
                : payload.slashOpen || payload.toolbarOpen
                  ? "interacting"
                  : "ready",
            lastError: null,
          }));
          onHostEventRef.current?.({
            kind: "status_changed",
            status:
              payload.readOnly === true
                ? "read_only"
                : payload.slashOpen || payload.toolbarOpen
                  ? "interacting"
                  : "ready",
            at: toIsoNow(),
            message: null,
          });
        });

        attachEvent<StatusPayload>(STATUS_EVENT, (payload) => {
          currentBlockIdRef.current =
            typeof payload.currentBlockId === "string" ? payload.currentBlockId : null;
        });

        attachEvent<SelectionPayload>(SELECTION_EVENT, (payload) => {
          currentBlockIdRef.current =
            typeof payload.currentBlockId === "string" ? payload.currentBlockId : null;
        });

        attachEvent<HeightPayload>(HEIGHT_EVENT, (payload) => {
          const nextHeight = Number(payload.height);
          if (Number.isFinite(nextHeight)) {
            setEditorHeight(Math.max(FALLBACK_MIN_HEIGHT, Math.ceil(nextHeight)));
          }
        });

        attachEvent<ErrorPayload>(ERROR_EVENT, (payload) => {
          const message =
            typeof payload.message === "string" ? payload.message : "leptos-tiptap island 初始化失败";
          setBridgeState((prev) => ({
            ...prev,
            status: "error",
            lastError: message,
          }));
          requestFallback("host_init_failed", message);
        });

        attachEvent(READY_EVENT, () => {
          setBridgeState((prev) => ({
            ...prev,
            ready: true,
            status: "ready",
            lastError: null,
          }));
        });

        latestDocRef.current = bootstrapPayload.content as Json;
        latestBlocksRef.current = blocksFromTiptapDoc(bootstrapPayload.content) as Json;
        lastHostSyncKeyRef.current = buildHostSyncKey({
          documentId: bootstrapPayload.documentId,
          workspaceId: bootstrapPayload.workspaceId,
          title: bootstrapPayload.title,
          content: bootstrapPayload.content,
          readOnly: bootstrapPayload.readOnly,
        });
        mountIdRef.current = runtimeModule.mount(container, {
          documentId: bootstrapPayload.documentId,
          workspaceId: bootstrapPayload.workspaceId,
          title: bootstrapPayload.title,
          content: bootstrapPayload.content,
          readOnly: bootstrapPayload.readOnly,
          revision: bootstrapPayload.revision,
          conflictDetectionKey: bootstrapPayload.conflictDetectionKey,
          pageOptions: bootstrapPayload.pageOptions,
          editable: !bootstrapPayload.readOnly,
        });
        setBridgeState((prev) => ({
          ...prev,
          runtimeUrl: entryAssetUrl,
          status: "mounting",
          lastError: null,
        }));
      })
      .catch((error) => {
        if (disposed) {
          return;
        }
        const message = error instanceof Error ? error.message : "加载 leptos-tiptap island 失败";
        setBridgeState((prev) => ({
          ...prev,
          status: "error",
          lastError: message,
        }));
        requestFallback("runtime_load_failed", message);
      });

    return () => {
      disposed = true;
      debouncedPersistRef.current?.cancel();
      removeListeners.forEach((dispose) => dispose());
      removeListeners = [];
      if (mountIdRef.current != null && runtimeModuleRef.current) {
        try {
          runtimeModuleRef.current.unmount(mountIdRef.current);
        } catch {
          // 说明：页面卸载时不再追加错误提示，避免离场噪音。
        }
      }
      mountIdRef.current = null;
      runtimeTargetRef.current = null;
      runtimeModuleRef.current = null;
      useEditorBridgeStore.getState().registerBridge(null);
    };
  }, [
    mountIdentity,
    requestFallback,
  ]);

  useEffect(() => {
    const target = runtimeTargetRef.current;
    if (!target || mountIdRef.current == null) {
      return;
    }
    const nextDoc = tiptapDocFromBlocks(props.initialContent as Json);
    const nextHostSyncKey = buildHostSyncKey({
      documentId: props.documentId,
      workspaceId: props.workspaceId,
      title: props.title ?? null,
      content: nextDoc,
      readOnly: Boolean(props.readOnly),
    });
    if (lastHostSyncKeyRef.current === nextHostSyncKey) {
      return;
    }
    lastHostSyncKeyRef.current = nextHostSyncKey;
    dispatchRuntimeCommand(target, {
      command: "replaceContent",
      documentId: props.documentId,
      workspaceId: props.workspaceId,
      title: props.title ?? null,
      content: nextDoc,
      revision: props.initialRevision ?? null,
      conflictDetectionKey: props.initialConflictDetectionKey ?? null,
      readOnly: Boolean(props.readOnly),
      editable: !props.readOnly,
    });
  }, [
    props.documentId,
    props.initialConflictDetectionKey,
    props.initialContent,
    props.initialRevision,
    props.readOnly,
    props.title,
    props.workspaceId,
  ]);

  useEffect(() => {
    const target = runtimeTargetRef.current;
    if (!target || mountIdRef.current == null) {
      return;
    }
    dispatchRuntimeCommand(target, {
      command: "setPageOptions",
      pageOptions: pickLeptosTiptapRuntimePageOptions(props.pageOptions),
    });
  }, [props.pageOptions]);

  useEffect(() => {
    const target = runtimeTargetRef.current;
    if (!target || mountIdRef.current == null) {
      return;
    }
      const editorBridge: EditorReferenceBridge = {
      insertInlineReference: (targetDocument, aliasText) => {
        try {
          dispatchRuntimeCommand(target, {
            command: "insertInlineReference",
            referenceDocumentId: targetDocument.id,
            text: aliasText?.trim() || targetDocument.title || "无标题",
          });
        } catch (error) {
          requestFallback(
            "command_failed",
            error instanceof Error ? error.message : "插入行内引用失败",
          );
        }
        return { blockId: currentBlockIdRef.current };
      },
      insertEmbedReference: (targetDocument) => {
        try {
          dispatchRuntimeCommand(target, {
            command: "insertEmbedReference",
            referenceDocumentId: targetDocument.id,
            text: targetDocument.title || "无标题",
          });
        } catch (error) {
          requestFallback(
            "command_failed",
            error instanceof Error ? error.message : "插入嵌入引用失败",
          );
        }
        return { blockId: currentBlockIdRef.current };
      },
      undo: () => {
        try {
          dispatchRuntimeCommand(target, { command: "undo" });
        } catch (error) {
          requestFallback("command_failed", error instanceof Error ? error.message : "撤销失败");
        }
      },
      redo: () => {
        try {
          dispatchRuntimeCommand(target, { command: "redo" });
        } catch (error) {
          requestFallback("command_failed", error instanceof Error ? error.message : "重做失败");
        }
      },
      getCursorBlockId: () => currentBlockIdRef.current,
      replaceWithSnapshot: (blocks: Json) => {
        const hostIdentity = hostIdentityRef.current;
        const nextDoc = tiptapDocFromBlocks(blocks) as Json;
        latestDocRef.current = nextDoc;
        latestBlocksRef.current = Array.isArray(blocks) ? blocks : blocksFromTiptapDoc(nextDoc);
        lastHostSyncKeyRef.current = buildHostSyncKey({
          documentId: hostIdentity.documentId,
          workspaceId: hostIdentity.workspaceId,
          title: hostIdentity.title,
          content: nextDoc,
          readOnly: hostIdentity.readOnly,
        });
        try {
          dispatchRuntimeCommand(target, {
            command: "replaceContent",
            documentId: hostIdentity.documentId,
            workspaceId: hostIdentity.workspaceId,
            title: hostIdentity.title,
            content: nextDoc,
            revision: revisionRef.current,
            conflictDetectionKey: conflictDetectionKeyRef.current,
            readOnly: hostIdentity.readOnly,
            editable: !hostIdentity.readOnly,
          });
        } catch (error) {
          requestFallback(
            "command_failed",
            error instanceof Error ? error.message : "替换编辑器快照失败",
          );
        }
      },
      requestFallbackToBlockNote: () => {
        requestFallback("explicit_fallback", "通过页面壳显式切回 BlockNote");
      },
    };
    useEditorBridgeStore.getState().registerBridge(editorBridge);
    return () => {
      useEditorBridgeStore.getState().registerBridge(null);
    };
  }, [
    props.documentId,
    props.readOnly,
    props.title,
    props.workspaceId,
    requestFallback,
  ]);

  return (
    <div
      ref={mountRef}
      className="min-h-[720px] py-6"
      data-editor-host-kind="leptos_tiptap_island"
      data-runtime-editor-status={bridgeState.status}
      data-testid="mnote-leptos-tiptap-island-editor-root"
      style={{ minHeight: `${editorHeight}px` }}
    />
  );
}
