import { describe, expect, it } from "vitest";
import type { Json } from "@/types/supabase";
import { buildPageAggregate } from "@/lib/documents/page-aggregate";
import type { PageSubtreeProjection } from "@/lib/documents/page-subtree";
import {
  createPageAggregateClientState,
  pageAggregateClientStateReducer,
  selectPageAggregateClientAiSnapshot,
  selectPageAggregateClientPageSubtree,
} from "@/components/editor/page-aggregate-client-state";
import type { PageOptionsState } from "@/types/page-options";

const pageOptions: PageOptionsState = {
  wideLayout: false,
  smallText: false,
  showHeadingNumbers: true,
  showToc: false,
  showStructure: false,
  protectEditing: false,
  showWordCount: true,
  collapseBacklinks: false,
  pageFont: "default",
  layoutDensity: "normal",
  hideChildPages: false,
  showBlockRefCount: false,
  embedDefaultBlockId: null,
};

function createPageSubtree(title: string): PageSubtreeProjection {
  return {
    projectionId: "projection:page_tree:doc_1",
    projection: "page_tree",
    rootNodeId: "doc_1",
    rootNode: {
      id: "doc_1",
      parentNodeId: null,
      nodeType: "page",
      blockId: null,
      anchorBlockId: null,
      depth: 0,
      metadata: {
        title,
        textSnippet: null,
        blockType: null,
        headingLevel: null,
        numbering: null,
        childCount: 0,
        order: 0,
        path: ["doc_1"],
      },
    },
    subtree: {
      rootNodeId: "doc_1",
      nodes: [],
    },
    outline: [],
    evidence: [],
    stats: {
      blockCount: 0,
      headingCount: 0,
      evidenceCount: 0,
      maxDepth: 0,
    },
  };
}

function createPageAggregate(input?: {
  title?: string;
  content?: unknown;
  pageSubtree?: PageSubtreeProjection | null;
  pageOptionsPatch?: Partial<PageOptionsState>;
  revision?: number | null;
  conflictDetectionKey?: string | null;
}) {
  const content =
    input?.content ??
    [
      {
        id: "block_1",
        type: "paragraph",
        content: [{ type: "text", text: "正文" }],
      },
    ];

  return buildPageAggregate({
    documentId: "doc_1",
    workspaceId: "ws_1",
    title: input?.title ?? "页面标题",
    pageOptions: {
      ...pageOptions,
      ...input?.pageOptionsPatch,
    },
    content,
    revision: input?.revision ?? 3,
    conflictDetectionKey: input?.conflictDetectionKey ?? "doc_1:3",
    pageSubtree: input?.pageSubtree ?? createPageSubtree("页面标题"),
  });
}

describe("page-aggregate-client-state", () => {
  it("应从 page aggregate 初始化 body/layout/tree 本地真相", () => {
    const page = createPageAggregate();

    const state = createPageAggregateClientState(page);

    expect(state.options).toEqual(page.layout.pageOptions);
    expect(state.content).toBe(page.body.content);
    expect(state.serverContentSnapshot).toBe(page.body.content);
    expect(state.serverPageSubtreeSnapshot).toBe(page.tree.pageSubtree);
    expect(state.serverPageSubtreeTitle).toBe("页面标题");
    expect(state.contentRevision).toBe(3);
    expect(state.conflictDetectionKey).toBe("doc_1:3");
  });

  it("路由 reload 后应整体替换 body/layout/tree 的服务端快照", () => {
    const initialPage = createPageAggregate();
    const reloadedContent = [
      {
        id: "block_2",
        type: "paragraph",
        content: [{ type: "text", text: "刷新后的正文" }],
      },
    ];
    const reloadedPage = createPageAggregate({
      title: "刷新后的标题",
      content: reloadedContent,
      pageSubtree: createPageSubtree("刷新后的标题"),
      pageOptionsPatch: { wideLayout: true, showToc: true },
      revision: 9,
      conflictDetectionKey: "doc_1:9",
    });

    const next = pageAggregateClientStateReducer(createPageAggregateClientState(initialPage), {
      type: "hydrate_from_page",
      page: reloadedPage,
    });

    expect(next.options.wideLayout).toBe(true);
    expect(next.options.showToc).toBe(true);
    expect(next.content).toBe(reloadedContent);
    expect(next.serverContentSnapshot).toBe(reloadedContent);
    expect(next.serverPageSubtreeSnapshot).toBe(reloadedPage.tree.pageSubtree);
    expect(next.serverPageSubtreeTitle).toBe("刷新后的标题");
    expect(next.contentRevision).toBe(9);
    expect(next.conflictDetectionKey).toBe("doc_1:9");
  });

  it("正文保存元信息回写时只更新 persisted meta，不覆盖本地内容快照", () => {
    const page = createPageAggregate();
    const localContent = [
      {
        id: "block_local",
        type: "paragraph",
        content: [{ type: "text", text: "本地正文" }],
      },
    ];
    const withLocalSnapshot = pageAggregateClientStateReducer(createPageAggregateClientState(page), {
      type: "apply_local_content_snapshot",
      content: localContent,
    });

    const next = pageAggregateClientStateReducer(withLocalSnapshot, {
      type: "apply_persisted_body_meta",
      meta: {
        revision: 10,
        conflictDetectionKey: "doc_1:10",
      },
    });

    expect(next.content).toBe(localContent);
    expect(next.serverContentSnapshot).toBe(page.body.content);
    expect(next.contentRevision).toBe(10);
    expect(next.conflictDetectionKey).toBe("doc_1:10");
  });

  it("本地标题或正文与服务端快照不一致时，不应继续复用旧 pageSubtree", () => {
    const page = createPageAggregate();
    const initialState = createPageAggregateClientState(page);

    expect(selectPageAggregateClientPageSubtree(initialState, "页面标题")).toBe(page.tree.pageSubtree);

    const localContentState = pageAggregateClientStateReducer(initialState, {
      type: "apply_local_content_snapshot",
      content: [{ id: "block_local", type: "paragraph", content: [] }],
    });
    expect(selectPageAggregateClientPageSubtree(localContentState, "页面标题")).toBeNull();

    const retitledState = pageAggregateClientStateReducer(initialState, {
      type: "update_server_page_subtree_title",
      title: "持久化后的标题",
    });
    expect(selectPageAggregateClientPageSubtree(retitledState, "页面标题")).toBeNull();
    expect(selectPageAggregateClientPageSubtree(retitledState, "持久化后的标题")).toBe(page.tree.pageSubtree);
  });

  it("页面设置 patch 应只合并局部字段，不重建整份页面状态", () => {
    const page = createPageAggregate();

    const next = pageAggregateClientStateReducer(createPageAggregateClientState(page), {
      type: "patch_page_options",
      patch: {
        showToc: true,
        layoutDensity: "compact",
      },
    });

    expect(next.options).toEqual({
      ...page.layout.pageOptions,
      showToc: true,
      layoutDensity: "compact",
    });
    expect(next.content).toBe(page.body.content);
    expect(next.serverPageSubtreeSnapshot).toBe(page.tree.pageSubtree);
  });

  it("应能从统一 client state 导出 AI 所需的页面聚合快照", () => {
    const page = createPageAggregate({
      pageOptionsPatch: {
        wideLayout: true,
        smallText: true,
      },
    });

    const snapshot = selectPageAggregateClientAiSnapshot(createPageAggregateClientState(page), {
      workspaceId: "ws_1",
      pageTitle: "页面标题",
    });

    expect(snapshot).toEqual({
      blocks: page.body.content as Json,
      pageSubtree: page.tree.pageSubtree,
      persistedMeta: {
        workspaceId: "ws_1",
        revision: 3,
        conflictDetectionKey: "doc_1:3",
      },
      pageOptions: {
        ...pageOptions,
        wideLayout: true,
        smallText: true,
      },
    });
  });
});
