import { afterEach, describe, expect, it, vi } from "vitest";
import type { Json } from "@/types/supabase";
import {
  executePageBodyCommand,
  executePageBodySavePayload,
  executePageHeadCommand,
  executePageLayoutCommand,
} from "./page-command-client";
import { buildDocumentSavePayload } from "./save-contract";

describe("page-command-client", () => {
  afterEach(() => {
    vi.restoreAllMocks();
  });

  it("标题命令应走统一 page head command", async () => {
    const fetchMock = vi.spyOn(globalThis, "fetch").mockResolvedValue({
      ok: true,
      json: async () => ({ ok: true, meta: { commandName: "page.head.updateTitle" } }),
    } as Response);

    await executePageHeadCommand({
      documentId: "doc-1",
      workspaceId: "ws-1",
      title: "页面标题",
    });

    expect(fetchMock).toHaveBeenCalledWith(
      "/api/documents/title",
      expect.objectContaining({
        method: "POST",
        headers: { "Content-Type": "application/json" },
      }),
    );

    const [, init] = fetchMock.mock.calls[0] ?? [];
    expect(JSON.parse(String(init?.body ?? "{}"))).toEqual({
      documentId: "doc-1",
      workspaceId: "ws-1",
      title: "页面标题",
      commandName: "page.head.updateTitle",
    });
  });

  it("页面设置命令应走统一 page layout command", async () => {
    const fetchMock = vi.spyOn(globalThis, "fetch").mockResolvedValue({
      ok: true,
      json: async () => ({ ok: true, meta: { commandName: "page.layout.updateOptions" } }),
    } as Response);

    await executePageLayoutCommand({
      documentId: "doc-1",
      workspaceId: "ws-1",
      pageOptions: { wideLayout: true },
    });

    expect(fetchMock).toHaveBeenCalledWith(
      "/api/documents/options",
      expect.objectContaining({
        method: "POST",
        headers: { "Content-Type": "application/json" },
      }),
    );

    const [, init] = fetchMock.mock.calls[0] ?? [];
    expect(JSON.parse(String(init?.body ?? "{}"))).toEqual({
      documentId: "doc-1",
      workspaceId: "ws-1",
      options: { wideLayout: true },
      commandName: "page.layout.updateOptions",
    });
  });

  it("正文保存 payload 应走统一 page body command", async () => {
    const fetchMock = vi.spyOn(globalThis, "fetch").mockResolvedValue({
      ok: true,
      json: async () => ({ ok: true, revision: 5, conflictDetectionKey: "doc-1:5" }),
    } as Response);
    const payload = buildDocumentSavePayload({
      documentId: "doc-1",
      workspaceId: "ws-1",
      revision: 4,
      conflictDetectionKey: "doc-1:4",
      content: [{ id: "block_1", type: "paragraph", content: "正文" }] as Json,
      blockCount: 1,
    });

    await expect(executePageBodySavePayload(payload)).resolves.toEqual({
      revision: 5,
      conflictDetectionKey: "doc-1:5",
    });

    expect(fetchMock).toHaveBeenCalledWith(
      "/api/documents/save",
      expect.objectContaining({
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(payload),
      }),
    );
  });

  it("高层正文命令应在保存成功后再回显快照并回传元信息", async () => {
    const applyEditorSnapshot = vi.fn();
    const onPersistedMetaChange = vi.fn();
    const fetchImpl = vi.fn(async () =>
      new Response(JSON.stringify({ ok: true, revision: 9, conflictDetectionKey: "doc-1:9" }), {
        status: 200,
        headers: { "Content-Type": "application/json" },
      }),
    );
    const blocks = [{ id: "block_1", type: "paragraph", content: "统一正文" }] as Json;

    await expect(
      executePageBodyCommand({
        documentId: "doc-1",
        workspaceId: "ws-1",
        revision: 8,
        conflictDetectionKey: "doc-1:8",
        blocks,
        applyEditorSnapshot,
        onPersistedMetaChange,
        fetchImpl,
      }),
    ).resolves.toEqual({
      revision: 9,
      conflictDetectionKey: "doc-1:9",
    });

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