import { describe, expect, it, vi } from "vitest";
import type { Json } from "@/types/supabase";
import { applyPageBodyCommand } from "./page-body-command";

describe("applyPageBodyCommand", () => {
  it("应先保存 page body，再回显编辑器快照并回传持久化元信息", async () => {
    const blocks = [{ id: "block_1", type: "paragraph", content: "AI 生成正文" }] as Json;
    const applyEditorSnapshot = vi.fn();
    const onPersistedMetaChange = vi.fn();
    const fetchImpl = vi.fn(async () =>
      new Response(JSON.stringify({ ok: true, revision: 5, conflictDetectionKey: "doc-1:5" }), {
        status: 200,
        headers: { "Content-Type": "application/json" },
      }),
    );

    const result = await applyPageBodyCommand({
      documentId: "doc-1",
      workspaceId: "ws-1",
      revision: 4,
      conflictDetectionKey: "doc-1:4",
      blocks,
      applyEditorSnapshot,
      onPersistedMetaChange,
      fetchImpl,
    });

    expect(fetchImpl).toHaveBeenCalledTimes(1);
    const [url, init] = fetchImpl.mock.calls[0] ?? [];
    expect(url).toBe("/api/documents/save");
    expect(init?.method).toBe("POST");
    expect(init?.headers).toEqual({ "Content-Type": "application/json" });

    const body = JSON.parse(String(init?.body ?? "{}")) as {
      documentId: string;
      workspaceId: string | null;
      revision: number | null;
      conflictDetectionKey: string | null;
      content: Json;
      blockCount: number | null;
    };
    expect(body.documentId).toBe("doc-1");
    expect(body.workspaceId).toBe("ws-1");
    expect(body.revision).toBe(4);
    expect(body.conflictDetectionKey).toBe("doc-1:4");
    expect(body.content).toEqual(blocks);
    expect(body.blockCount).toBe(1);

    expect(result).toEqual({ revision: 5, conflictDetectionKey: "doc-1:5" });
    expect(applyEditorSnapshot).toHaveBeenCalledWith(blocks);
    expect(onPersistedMetaChange).toHaveBeenCalledWith({
      revision: 5,
      conflictDetectionKey: "doc-1:5",
    });
  });

  it("保存失败时不应回显未持久化的正文", async () => {
    const blocks = [{ id: "block_1", type: "paragraph", content: "失败正文" }] as Json;
    const applyEditorSnapshot = vi.fn();
    const onPersistedMetaChange = vi.fn();
    const fetchImpl = vi.fn(async () =>
      new Response(JSON.stringify({ error: "conflict" }), {
        status: 409,
        headers: { "Content-Type": "application/json" },
      }),
    );

    await expect(
      applyPageBodyCommand({
        documentId: "doc-1",
        workspaceId: "ws-1",
        revision: 4,
        conflictDetectionKey: "doc-1:4",
        blocks,
        applyEditorSnapshot,
        onPersistedMetaChange,
        fetchImpl,
      }),
    ).rejects.toThrow("conflict");

    expect(applyEditorSnapshot).not.toHaveBeenCalled();
    expect(onPersistedMetaChange).not.toHaveBeenCalled();
  });
});
