import { describe, expect, it, vi } from "vitest";
import { streamTreeFrames } from "./server";
import type { TreeStreamCommandLogCursorRow } from "./server";

function buildOverview(rows: TreeStreamCommandLogCursorRow[]) {
  return {
    command_logs: rows,
    domain_events: [],
    has_more: false,
    next_cursor: null,
    generated_at: "2026-04-24T00:00:00Z",
  };
}

async function collectFrames<T>(generator: AsyncGenerator<T>) {
  const frames: T[] = [];
  for await (const frame of generator) {
    frames.push(frame);
  }
  return frames;
}

describe("tree-stream/server", () => {
  it("workspace scope 首帧应发 snapshot，并固定 sidebar_tree + cursor", async () => {
    const frames = await collectFrames(
      streamTreeFrames({
        workspaceId: "ws_1",
        pollMs: 1,
        maxPolls: 0,
        loadOverview: vi.fn().mockResolvedValue(
          buildOverview([{ id: "clog_2", created_at: "2026-04-24T00:00:01Z" }]),
        ),
        loadSnapshot: vi.fn().mockResolvedValue({
          requestId: "req_1",
          traceId: "trace_1",
          data: { activeWorkspaceId: "ws_1", documents: [] },
          snapshot: { dataset: { active_workspace_id: "ws_1", documents: [] }, tree: { items: [] } },
        }),
        sleep: vi.fn().mockResolvedValue(undefined),
      }),
    );

    expect(frames).toHaveLength(1);
    expect(frames[0]).toMatchObject({
      event: "snapshot",
      payload: {
        kind: "snapshot",
        stream: "workspace",
        workspaceId: "ws_1",
        rootNodeId: null,
        projection: "sidebar_tree",
        cursor: JSON.stringify({
          createdAt: "2026-04-24T00:00:01Z",
          id: "clog_2",
        }),
      },
    });
  });

  it("subtree scope 首帧应切到 subtree + page_tree", async () => {
    const frames = await collectFrames(
      streamTreeFrames({
        workspaceId: "ws_1",
        rootNodeId: "page_root",
        pollMs: 1,
        maxPolls: 0,
        loadOverview: vi.fn().mockResolvedValue(
          buildOverview([{ id: "clog_2", created_at: "2026-04-24T00:00:01Z" }]),
        ),
        loadSnapshot: vi.fn().mockResolvedValue({
          requestId: "req_subtree_1",
          traceId: "trace_subtree_1",
          data: { nodes: [] },
          snapshot: { dataset: { active_workspace_id: "ws_1", documents: [] }, tree: { nodes: [] } },
        }),
        sleep: vi.fn().mockResolvedValue(undefined),
      }),
    );

    expect(frames).toHaveLength(1);
    expect(frames[0]).toMatchObject({
      event: "snapshot",
      payload: {
        kind: "snapshot",
        stream: "subtree",
        workspaceId: "ws_1",
        rootNodeId: "page_root",
        projection: "page_tree",
      },
    });
  });

  it("检测到 cursor 之后出现新命令时，应发 resync 而不是静默结束", async () => {
    const loadOverview = vi
      .fn()
      .mockResolvedValueOnce(
        buildOverview([{ id: "clog_1", created_at: "2026-04-24T00:00:01Z" }]),
      )
      .mockResolvedValueOnce(
        buildOverview([
          { id: "clog_2", created_at: "2026-04-24T00:00:02Z" },
          { id: "clog_1", created_at: "2026-04-24T00:00:01Z" },
        ]),
      );
    const loadSnapshot = vi
      .fn()
      .mockResolvedValueOnce({
        requestId: "req_1",
        traceId: "trace_1",
        data: { activeWorkspaceId: "ws_1", documents: [{ id: "page_1" }] },
        snapshot: { dataset: { active_workspace_id: "ws_1", documents: [{ id: "page_1" }] }, tree: { items: [] } },
      })
      .mockResolvedValueOnce({
        requestId: "req_2",
        traceId: "trace_2",
        data: { activeWorkspaceId: "ws_1", documents: [{ id: "page_1" }, { id: "page_2" }] },
        snapshot: {
          dataset: { active_workspace_id: "ws_1", documents: [{ id: "page_1" }, { id: "page_2" }] },
          tree: { items: [] },
        },
      });

    const frames = await collectFrames(
      streamTreeFrames({
        workspaceId: "ws_1",
        pollMs: 1,
        maxPolls: 1,
        loadOverview,
        loadSnapshot,
        sleep: vi.fn().mockResolvedValue(undefined),
      }),
    );

    expect(frames).toHaveLength(2);
    expect(frames[0]).toMatchObject({ event: "snapshot" });
    expect(frames[1]).toMatchObject({
      event: "resync",
      payload: {
        kind: "resync",
        stream: "workspace",
        workspaceId: "ws_1",
        projection: "sidebar_tree",
        cursor: JSON.stringify({
          createdAt: "2026-04-24T00:00:02Z",
          id: "clog_2",
        }),
      },
    });
    expect(loadSnapshot).toHaveBeenCalledTimes(2);
  });

  it("检测到带 streamDelta 的单条新命令时，应直接发 delta", async () => {
    const loadOverview = vi
      .fn()
      .mockResolvedValueOnce(
        buildOverview([{ id: "clog_1", created_at: "2026-04-24T00:00:01Z" }]),
      )
      .mockResolvedValueOnce(
        buildOverview([
          {
            id: "clog_2",
            created_at: "2026-04-24T00:00:02Z",
            command_name: "tree.node.archive",
            payload: {
              documentId: "page_2",
              streamDelta: {
                op: "remove_document",
                documentId: "page_2",
              },
            },
          },
          { id: "clog_1", created_at: "2026-04-24T00:00:01Z" },
        ]),
      );
    const loadSnapshot = vi.fn().mockResolvedValue({
      requestId: "req_1",
      traceId: "trace_1",
      data: { activeWorkspaceId: "ws_1", documents: [{ id: "page_1" }] },
      snapshot: { dataset: { active_workspace_id: "ws_1", documents: [{ id: "page_1" }] }, tree: { items: [] } },
    });

    const frames = await collectFrames(
      streamTreeFrames({
        workspaceId: "ws_1",
        pollMs: 1,
        maxPolls: 1,
        loadOverview,
        loadSnapshot,
        sleep: vi.fn().mockResolvedValue(undefined),
      }),
    );

    expect(frames).toHaveLength(2);
    expect(frames[1]).toMatchObject({
      event: "delta",
      payload: {
        kind: "delta",
        cursor: JSON.stringify({
          createdAt: "2026-04-24T00:00:02Z",
          id: "clog_2",
        }),
        data: {
          op: "remove_document",
          documentId: "page_2",
        },
      },
    });
    expect(loadSnapshot).toHaveBeenCalledTimes(1);
  });

  it("只有 domain event 推进时，也应刷新 cursor 并触发 resync", async () => {
    const loadOverview = vi
      .fn()
      .mockResolvedValueOnce(
        buildOverview([{ id: "clog_1", created_at: "2026-04-24T00:00:01Z" }]),
      )
      .mockResolvedValueOnce({
        command_logs: [{ id: "clog_1", created_at: "2026-04-24T00:00:01Z" }],
        domain_events: [
          {
            event_id: "evt_2",
            created_at: "2026-04-24T00:00:02Z",
          },
        ],
        has_more: false,
        next_cursor: null,
        generated_at: "2026-04-24T00:00:02Z",
      });
    const loadSnapshot = vi
      .fn()
      .mockResolvedValueOnce({
        requestId: "req_1",
        traceId: "trace_1",
        data: { activeWorkspaceId: "ws_1", documents: [{ id: "page_1" }] },
        snapshot: { dataset: { active_workspace_id: "ws_1", documents: [{ id: "page_1" }] }, tree: { items: [] } },
      })
      .mockResolvedValueOnce({
        requestId: "req_2",
        traceId: "trace_2",
        data: { activeWorkspaceId: "ws_1", documents: [{ id: "page_1" }] },
        snapshot: { dataset: { active_workspace_id: "ws_1", documents: [{ id: "page_1" }] }, tree: { items: [] } },
      });

    const frames = await collectFrames(
      streamTreeFrames({
        workspaceId: "ws_1",
        pollMs: 1,
        maxPolls: 1,
        loadOverview,
        loadSnapshot,
        sleep: vi.fn().mockResolvedValue(undefined),
      }),
    );

    expect(frames).toHaveLength(2);
    expect(frames[1]).toMatchObject({
      event: "resync",
      payload: {
        kind: "resync",
        cursor: JSON.stringify({
          createdAt: "2026-04-24T00:00:02Z",
          id: "domain_event:evt_2",
        }),
      },
    });
    expect(loadSnapshot).toHaveBeenCalledTimes(2);
  });

  it("单条新 domain event 携带 streamDelta 时，应直接发 delta", async () => {
    const loadOverview = vi
      .fn()
      .mockResolvedValueOnce({
        command_logs: [],
        domain_events: [
          {
            event_id: "evt_1",
            created_at: "2026-04-24T00:00:01Z",
          },
        ],
        has_more: false,
        next_cursor: null,
        generated_at: "2026-04-24T00:00:01Z",
      })
      .mockResolvedValueOnce({
        command_logs: [],
        domain_events: [
          {
            event_id: "evt_2",
            created_at: "2026-04-24T00:00:02Z",
            payload: {
              command_name: "tree.node.rename",
              streamDelta: {
                op: "upsert_document",
                document: {
                  id: "page_2",
                  title: "新标题",
                },
              },
            },
          },
          {
            event_id: "evt_1",
            created_at: "2026-04-24T00:00:01Z",
          },
        ],
        has_more: false,
        next_cursor: null,
        generated_at: "2026-04-24T00:00:02Z",
      });
    const loadSnapshot = vi.fn().mockResolvedValue({
      requestId: "req_1",
      traceId: "trace_1",
      data: { activeWorkspaceId: "ws_1", documents: [{ id: "page_1" }] },
      snapshot: { dataset: { active_workspace_id: "ws_1", documents: [{ id: "page_1" }] }, tree: { items: [] } },
    });

    const frames = await collectFrames(
      streamTreeFrames({
        workspaceId: "ws_1",
        pollMs: 1,
        maxPolls: 1,
        loadOverview,
        loadSnapshot,
        sleep: vi.fn().mockResolvedValue(undefined),
      }),
    );

    expect(frames).toHaveLength(2);
    expect(frames[1]).toMatchObject({
      event: "delta",
      payload: {
        kind: "delta",
        cursor: JSON.stringify({
          createdAt: "2026-04-24T00:00:02Z",
          id: "domain_event:evt_2",
        }),
        data: {
          op: "upsert_document",
          document: {
            id: "page_2",
            title: "新标题",
          },
        },
      },
    });
    expect(loadSnapshot).toHaveBeenCalledTimes(1);
  });

  it("单条资源 domain event 携带 upsert_assets 时，应直接发 delta", async () => {
    const streamDelta = {
      op: "upsert_assets",
      upsertAssets: [
        {
          id: "asset_1",
          workspace_id: "ws_1",
          document_id: "doc_target",
          asset_type: "file",
          file_url: "/file.pdf",
          thumbnail_url: "/file.pdf",
          file_name: "file.pdf",
          file_size: 1024,
          mime_type: "application/pdf",
          created_at: "2026-04-26T00:00:00Z",
          updated_at: "2026-04-26T00:00:00Z",
        },
      ],
    };
    const loadOverview = vi
      .fn()
      .mockResolvedValueOnce({
        command_logs: [],
        domain_events: [
          {
            event_id: "evt_1",
            created_at: "2026-04-24T00:00:01Z",
          },
        ],
        has_more: false,
        next_cursor: null,
        generated_at: "2026-04-24T00:00:01Z",
      })
      .mockResolvedValueOnce({
        command_logs: [],
        domain_events: [
          {
            event_id: "evt_2",
            created_at: "2026-04-24T00:00:02Z",
            payload: {
              schema: "mnote.tree.domain_event",
              eventType: "tree.resource.moved",
              streamDelta,
            },
          },
          {
            event_id: "evt_1",
            created_at: "2026-04-24T00:00:01Z",
          },
        ],
        has_more: false,
        next_cursor: null,
        generated_at: "2026-04-24T00:00:02Z",
      });
    const loadSnapshot = vi.fn().mockResolvedValue({
      requestId: "req_1",
      traceId: "trace_1",
      data: { activeWorkspaceId: "ws_1", documents: [{ id: "page_1" }] },
      snapshot: { dataset: { active_workspace_id: "ws_1", documents: [{ id: "page_1" }] }, tree: { items: [] } },
    });

    const frames = await collectFrames(
      streamTreeFrames({
        workspaceId: "ws_1",
        pollMs: 1,
        maxPolls: 1,
        loadOverview,
        loadSnapshot,
        sleep: vi.fn().mockResolvedValue(undefined),
      }),
    );

    expect(frames).toHaveLength(2);
    expect(frames[1]).toMatchObject({
      event: "delta",
      payload: {
        kind: "delta",
        data: streamDelta,
      },
    });
    expect(loadSnapshot).toHaveBeenCalledTimes(1);
  });

  it("单条新 domain event 缺少可识别 streamDelta 时，应保守回退 resync", async () => {
    const loadOverview = vi
      .fn()
      .mockResolvedValueOnce({
        command_logs: [],
        domain_events: [
          {
            event_id: "evt_1",
            created_at: "2026-04-24T00:00:01Z",
          },
        ],
        has_more: false,
        next_cursor: null,
        generated_at: "2026-04-24T00:00:01Z",
      })
      .mockResolvedValueOnce({
        command_logs: [],
        domain_events: [
          {
            event_id: "evt_2",
            created_at: "2026-04-24T00:00:02Z",
            payload: {
              schema: "mnote.tree.domain_event",
              schemaVersion: 1,
              eventType: "tree.node.unknown",
            },
          },
          {
            event_id: "evt_1",
            created_at: "2026-04-24T00:00:01Z",
          },
        ],
        has_more: false,
        next_cursor: null,
        generated_at: "2026-04-24T00:00:02Z",
      });
    const loadSnapshot = vi
      .fn()
      .mockResolvedValueOnce({
        requestId: "req_1",
        traceId: "trace_1",
        data: { activeWorkspaceId: "ws_1", documents: [{ id: "page_1" }] },
        snapshot: { dataset: { active_workspace_id: "ws_1", documents: [{ id: "page_1" }] }, tree: { items: [] } },
      })
      .mockResolvedValueOnce({
        requestId: "req_2",
        traceId: "trace_2",
        data: { activeWorkspaceId: "ws_1", documents: [{ id: "page_2" }] },
        snapshot: { dataset: { active_workspace_id: "ws_1", documents: [{ id: "page_2" }] }, tree: { items: [] } },
      });

    const frames = await collectFrames(
      streamTreeFrames({
        workspaceId: "ws_1",
        pollMs: 1,
        maxPolls: 1,
        loadOverview,
        loadSnapshot,
        sleep: vi.fn().mockResolvedValue(undefined),
      }),
    );

    expect(frames).toHaveLength(2);
    expect(frames[1]).toMatchObject({
      event: "resync",
      payload: {
        kind: "resync",
        cursor: JSON.stringify({
          createdAt: "2026-04-24T00:00:02Z",
          id: "domain_event:evt_2",
        }),
      },
    });
    expect(loadSnapshot).toHaveBeenCalledTimes(2);
  });

  it("同一命令的 command log 与 domain event 同时推进且 delta 一致时，应发一次 delta", async () => {
    const streamDelta = {
      op: "upsert_document",
      document: { id: "page_2", title: "同一标题" },
    };
    const loadOverview = vi
      .fn()
      .mockResolvedValueOnce(
        buildOverview([{ id: "clog_1", command_id: "cmd_1", created_at: "2026-04-24T00:00:01Z" }]),
      )
      .mockResolvedValueOnce({
        command_logs: [
          {
            id: "clog_2",
            command_id: "cmd_2",
            created_at: "2026-04-24T00:00:02Z",
            command_name: "tree.node.rename",
            payload: { streamDelta },
          },
          { id: "clog_1", command_id: "cmd_1", created_at: "2026-04-24T00:00:01Z" },
        ],
        domain_events: [
          {
            event_id: "evt_2",
            command_id: "cmd_2",
            created_at: "2026-04-24T00:00:02Z",
            payload: { streamDelta },
          },
        ],
        has_more: false,
        next_cursor: null,
        generated_at: "2026-04-24T00:00:02Z",
      });
    const loadSnapshot = vi.fn().mockResolvedValue({
      requestId: "req_1",
      traceId: "trace_1",
      data: { activeWorkspaceId: "ws_1", documents: [{ id: "page_1" }] },
      snapshot: { dataset: { active_workspace_id: "ws_1", documents: [{ id: "page_1" }] }, tree: { items: [] } },
    });

    const frames = await collectFrames(
      streamTreeFrames({
        workspaceId: "ws_1",
        pollMs: 1,
        maxPolls: 1,
        loadOverview,
        loadSnapshot,
        sleep: vi.fn().mockResolvedValue(undefined),
      }),
    );

    expect(frames).toHaveLength(2);
    expect(frames[1]).toMatchObject({
      event: "delta",
      payload: {
        kind: "delta",
        cursor: JSON.stringify({
          createdAt: "2026-04-24T00:00:02Z",
          id: "clog_2",
        }),
        data: streamDelta,
      },
    });
    expect(loadSnapshot).toHaveBeenCalledTimes(1);
  });

  it("上一帧 cursor 来自 command log 时，应按时间排除旧 domain event 后再做双写去重", async () => {
    const streamDelta = {
      op: "move_document",
      documentId: "page_2",
      parentId: "page_1",
      sortOrder: 2,
    };
    const loadOverview = vi
      .fn()
      .mockResolvedValueOnce(
        buildOverview([{ id: "clog_1", command_id: "cmd_1", created_at: "2026-04-24T00:00:01Z" }]),
      )
      .mockResolvedValueOnce({
        command_logs: [
          {
            id: "clog_2",
            command_id: "cmd_2",
            created_at: "2026-04-24T00:00:02Z",
            command_name: "tree.subtree.move",
            payload: { streamDelta },
          },
          { id: "clog_1", command_id: "cmd_1", created_at: "2026-04-24T00:00:01Z" },
        ],
        domain_events: [
          {
            event_id: "evt_2",
            command_id: "cmd_2",
            created_at: "2026-04-24T00:00:02Z",
            payload: { streamDelta },
          },
          {
            event_id: "evt_1",
            command_id: "cmd_1",
            created_at: "2026-04-24T00:00:01Z",
            payload: {
              streamDelta: {
                op: "noop",
              },
            },
          },
        ],
        has_more: false,
        next_cursor: null,
        generated_at: "2026-04-24T00:00:02Z",
      });
    const loadSnapshot = vi.fn().mockResolvedValue({
      requestId: "req_1",
      traceId: "trace_1",
      data: { activeWorkspaceId: "ws_1", documents: [{ id: "page_1" }] },
      snapshot: { dataset: { active_workspace_id: "ws_1", documents: [{ id: "page_1" }] }, tree: { items: [] } },
    });

    const frames = await collectFrames(
      streamTreeFrames({
        workspaceId: "ws_1",
        pollMs: 1,
        maxPolls: 1,
        loadOverview,
        loadSnapshot,
        sleep: vi.fn().mockResolvedValue(undefined),
      }),
    );

    expect(frames).toHaveLength(2);
    expect(frames[1]).toMatchObject({
      event: "delta",
      payload: {
        kind: "delta",
        data: streamDelta,
      },
    });
    expect(loadSnapshot).toHaveBeenCalledTimes(1);
  });

  it("command log 与 domain event 同时推进且 delta 不一致时，应回退 resync 避免漏发", async () => {
    const loadOverview = vi
      .fn()
      .mockResolvedValueOnce(
        buildOverview([{ id: "clog_1", created_at: "2026-04-24T00:00:01Z" }]),
      )
      .mockResolvedValueOnce({
        command_logs: [
          {
            id: "clog_2",
            created_at: "2026-04-24T00:00:03Z",
            command_name: "tree.node.rename",
            payload: {
              streamDelta: {
                op: "upsert_document",
                document: { id: "page_2", title: "命令标题" },
              },
            },
          },
          { id: "clog_1", created_at: "2026-04-24T00:00:01Z" },
        ],
        domain_events: [
          {
            event_id: "evt_2",
            created_at: "2026-04-24T00:00:02Z",
            payload: {
              streamDelta: {
                op: "remove_document",
                documentId: "page_3",
              },
            },
          },
        ],
        has_more: false,
        next_cursor: null,
        generated_at: "2026-04-24T00:00:03Z",
      });
    const loadSnapshot = vi
      .fn()
      .mockResolvedValueOnce({
        requestId: "req_1",
        traceId: "trace_1",
        data: { activeWorkspaceId: "ws_1", documents: [{ id: "page_1" }] },
        snapshot: { dataset: { active_workspace_id: "ws_1", documents: [{ id: "page_1" }] }, tree: { items: [] } },
      })
      .mockResolvedValueOnce({
        requestId: "req_2",
        traceId: "trace_2",
        data: { activeWorkspaceId: "ws_1", documents: [{ id: "page_2" }] },
        snapshot: { dataset: { active_workspace_id: "ws_1", documents: [{ id: "page_2" }] }, tree: { items: [] } },
      });

    const frames = await collectFrames(
      streamTreeFrames({
        workspaceId: "ws_1",
        pollMs: 1,
        maxPolls: 1,
        loadOverview,
        loadSnapshot,
        sleep: vi.fn().mockResolvedValue(undefined),
      }),
    );

    expect(frames).toHaveLength(2);
    expect(frames[1]).toMatchObject({
      event: "resync",
      payload: {
        kind: "resync",
      },
    });
    expect(loadSnapshot).toHaveBeenCalledTimes(2);
  });

  it("单条新命令缺少可稳定解释的 streamDelta 时，应回退 resync", async () => {
    const loadOverview = vi
      .fn()
      .mockResolvedValueOnce(
        buildOverview([{ id: "clog_1", created_at: "2026-04-24T00:00:01Z" }]),
      )
      .mockResolvedValueOnce(
        buildOverview([
          {
            id: "clog_2",
            created_at: "2026-04-24T00:00:02Z",
            command_name: "tree.subtree.move",
            payload: {
              documentId: "page_2",
            },
          },
          { id: "clog_1", created_at: "2026-04-24T00:00:01Z" },
        ]),
      );
    const loadSnapshot = vi
      .fn()
      .mockResolvedValueOnce({
        requestId: "req_1",
        traceId: "trace_1",
        data: { activeWorkspaceId: "ws_1", documents: [{ id: "page_1" }] },
        snapshot: { dataset: { active_workspace_id: "ws_1", documents: [{ id: "page_1" }] }, tree: { items: [] } },
      })
      .mockResolvedValueOnce({
        requestId: "req_2",
        traceId: "trace_2",
        data: { activeWorkspaceId: "ws_1", documents: [{ id: "page_1" }, { id: "page_2" }] },
        snapshot: {
          dataset: { active_workspace_id: "ws_1", documents: [{ id: "page_1" }, { id: "page_2" }] },
          tree: { items: [] },
        },
      });

    const frames = await collectFrames(
      streamTreeFrames({
        workspaceId: "ws_1",
        pollMs: 1,
        maxPolls: 1,
        loadOverview,
        loadSnapshot,
        sleep: vi.fn().mockResolvedValue(undefined),
      }),
    );

    expect(frames).toHaveLength(2);
    expect(frames[1]).toMatchObject({
      event: "resync",
      payload: {
        kind: "resync",
      },
    });
    expect(loadSnapshot).toHaveBeenCalledTimes(2);
  });

  it("正文保存这类无树结构影响的命令应降级为 noop delta，而不是触发 resync", async () => {
    const loadOverview = vi
      .fn()
      .mockResolvedValueOnce(
        buildOverview([{ id: "clog_1", created_at: "2026-04-24T00:00:01Z" }]),
      )
      .mockResolvedValueOnce(
        buildOverview([
          {
            id: "clog_2",
            created_at: "2026-04-24T00:00:02Z",
            command_name: "page.body.save",
            payload: {
              documentId: "page_1",
            },
          },
          { id: "clog_1", created_at: "2026-04-24T00:00:01Z" },
        ]),
      );
    const loadSnapshot = vi.fn().mockResolvedValue({
      requestId: "req_1",
      traceId: "trace_1",
      data: { activeWorkspaceId: "ws_1", documents: [{ id: "page_1" }] },
      snapshot: { dataset: { active_workspace_id: "ws_1", documents: [{ id: "page_1" }] }, tree: { items: [] } },
    });

    const frames = await collectFrames(
      streamTreeFrames({
        workspaceId: "ws_1",
        pollMs: 1,
        maxPolls: 1,
        loadOverview,
        loadSnapshot,
        sleep: vi.fn().mockResolvedValue(undefined),
      }),
    );

    expect(frames).toHaveLength(2);
    expect(frames[1]).toMatchObject({
      event: "delta",
      payload: {
        kind: "delta",
        data: {
          op: "noop",
        },
      },
    });
    expect(loadSnapshot).toHaveBeenCalledTimes(1);
  });

  it("move 这类附带 move_document 的新命令应直接发 delta，而不是触发 resync", async () => {
    const sidebarSnapshot = {
      activeWorkspaceId: "ws_1",
      workspaces: [],
      documents: [
        {
          id: "page_1",
          workspace_id: "ws_1",
          title: "页面 1",
          parent_id: null,
          sort_order: 0,
          access_scope: "private",
          is_starred: false,
          is_template: false,
          created_at: "2026-04-24T00:00:00Z",
          updated_at: "2026-04-24T00:01:00Z",
        },
      ],
      kernelSidebarProjection: {
        projectionId: "kernel_projection:sidebar_tree:workspace_root",
        projection: "sidebar_tree",
        rootNodeId: null,
        items: [],
        edges: [],
      },
      kernelFileTreeProjection: {
        projectionId: "kernel_projection:file_tree:workspace_root",
        projection: "file_tree",
        rootNodeId: null,
        items: [],
        edges: [],
      },
      kernelSidebarTree: [],
      trashedDocuments: [],
      mediaAssets: [],
      mindmapDocs: [],
      mindmapAssets: [],
      mindmapAssetChildren: {},
      tableAssets: [],
    };
    const loadOverview = vi
      .fn()
      .mockResolvedValueOnce(
        buildOverview([{ id: "clog_1", created_at: "2026-04-24T00:00:01Z" }]),
      )
      .mockResolvedValueOnce(
        buildOverview([
          {
            id: "clog_2",
            created_at: "2026-04-24T00:00:02Z",
            command_name: "tree.subtree.move",
            payload: {
              documentId: "page_1",
              streamDelta: {
                op: "move_document",
                documentId: "page_1",
                parentId: null,
                sortOrder: 0,
                updatedAt: "2026-04-24T00:01:00Z",
              },
            },
          },
          { id: "clog_1", created_at: "2026-04-24T00:00:01Z" },
        ]),
      );
    const loadSnapshot = vi.fn().mockResolvedValue({
      requestId: "req_1",
      traceId: "trace_1",
      data: { activeWorkspaceId: "ws_1", documents: [] },
      snapshot: { dataset: { active_workspace_id: "ws_1", documents: [] }, tree: { items: [] } },
    });

    const frames = await collectFrames(
      streamTreeFrames({
        workspaceId: "ws_1",
        pollMs: 1,
        maxPolls: 1,
        loadOverview,
        loadSnapshot,
        sleep: vi.fn().mockResolvedValue(undefined),
      }),
    );

    expect(frames).toHaveLength(2);
    expect(frames[1]).toMatchObject({
      event: "delta",
      payload: {
        kind: "delta",
        data: {
          op: "move_document",
          documentId: "page_1",
          parentId: null,
          sortOrder: 0,
          updatedAt: "2026-04-24T00:01:00Z",
        },
      },
    });
    expect(loadSnapshot).toHaveBeenCalledTimes(1);
  });

  it("copy 这类附带 upsert_documents 的新命令应保留批量文档字段", async () => {
    const loadOverview = vi
      .fn()
      .mockResolvedValueOnce(
        buildOverview([{ id: "clog_1", created_at: "2026-04-24T00:00:01Z" }]),
      )
      .mockResolvedValueOnce(
        buildOverview([
          {
            id: "clog_2",
            created_at: "2026-04-24T00:00:02Z",
            command_name: "tree.subtree.copy",
            payload: {
              streamDelta: {
                op: "upsert_documents",
                upsertDocuments: [
                  {
                    id: "copy_1",
                    workspace_id: "ws_1",
                    title: "Copy",
                    parent_id: null,
                    sort_order: 2,
                    is_starred: false,
                    access_scope: "private",
                    is_template: false,
                    created_at: "2026-04-24T00:00:02Z",
                    updated_at: "2026-04-24T00:00:02Z",
                  },
                ],
              },
            },
          },
          { id: "clog_1", created_at: "2026-04-24T00:00:01Z" },
        ]),
      );
    const loadSnapshot = vi.fn().mockResolvedValue({
      requestId: "req_1",
      traceId: "trace_1",
      data: { activeWorkspaceId: "ws_1", documents: [] },
      snapshot: { dataset: { active_workspace_id: "ws_1", documents: [] }, tree: { items: [] } },
    });

    const frames = await collectFrames(
      streamTreeFrames({
        workspaceId: "ws_1",
        pollMs: 1,
        maxPolls: 1,
        loadOverview,
        loadSnapshot,
        sleep: vi.fn().mockResolvedValue(undefined),
      }),
    );

    expect(frames[1]).toMatchObject({
      event: "delta",
      payload: {
        kind: "delta",
        data: {
          op: "upsert_documents",
          upsertDocuments: [
            expect.objectContaining({
              id: "copy_1",
              workspace_id: "ws_1",
            }),
          ],
        },
      },
    });
    expect(loadSnapshot).toHaveBeenCalledTimes(1);
  });

  it("轮询期间没有新 cursor 时，不应额外发 resync", async () => {
    const loadOverview = vi
      .fn()
      .mockResolvedValue(buildOverview([{ id: "clog_1", created_at: "2026-04-24T00:00:01Z" }]));

    const frames = await collectFrames(
      streamTreeFrames({
        workspaceId: "ws_1",
        pollMs: 1,
        maxPolls: 1,
        loadOverview,
        loadSnapshot: vi.fn().mockResolvedValue({
          requestId: "req_1",
          traceId: "trace_1",
          data: { activeWorkspaceId: "ws_1", documents: [] },
          snapshot: { dataset: { active_workspace_id: "ws_1", documents: [] }, tree: { items: [] } },
        }),
        sleep: vi.fn().mockResolvedValue(undefined),
      }),
    );

    expect(frames).toHaveLength(1);
    expect(frames[0]).toMatchObject({ event: "snapshot" });
  });
});
