import { act } from "react";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { createRoot, type Root } from "react-dom/client";
import type { SidebarInitialData } from "@/components/sidebar/types";
import { usePreferredSidebarSnapshotData } from "@/components/sidebar/preferred-sidebar-snapshot-context";
import { buildSidebarInitialData } from "@/lib/sidebar-data";
import type { DocumentRecord } from "@/lib/documents";
import { AppLayoutShell } from "./app-layout-shell";

const mockUseSidebarData = vi.fn();
const mockUseSidebarTreeStream = vi.fn();
const mockUsePreferredSidebarSnapshot = vi.fn();

let capturedSidebarProps: Record<string, unknown> | null = null;
let capturedBreadcrumbProps: Record<string, unknown> | null = null;
let capturedSearchPaletteProps: Record<string, unknown> | null = null;

vi.mock("@/hooks/use-sidebar-data", () => ({
  useSidebarData: (...args: unknown[]) => mockUseSidebarData(...args),
}));

vi.mock("@/lib/tree-stream/use-sidebar-tree-stream", () => ({
  useSidebarTreeStream: (...args: unknown[]) => mockUseSidebarTreeStream(...args),
}));

vi.mock("@/components/sidebar/use-preferred-sidebar-snapshot", () => ({
  usePreferredSidebarSnapshot: (...args: unknown[]) => mockUsePreferredSidebarSnapshot(...args),
}));

vi.mock("@/components/sidebar/sidebar", () => ({
  Sidebar: (props: Record<string, unknown>) => {
    capturedSidebarProps = props;
    return <div data-testid="sidebar" />;
  },
}));

vi.mock("@/components/breadcrumb", () => ({
  Breadcrumb: (props: Record<string, unknown>) => {
    capturedBreadcrumbProps = props;
    return <div data-testid="breadcrumb" />;
  },
}));

vi.mock("@/components/mobile-sidebar-trigger", () => ({
  MobileSidebarTrigger: () => <div data-testid="mobile-trigger" />,
}));

vi.mock("@/components/search/search-palette", () => ({
  SearchPalette: (props: Record<string, unknown>) => {
    capturedSearchPaletteProps = props;
    return <div data-testid="search-palette" />;
  },
}));

function buildDocument(overrides: Partial<DocumentRecord> = {}): DocumentRecord {
  return {
    access_scope: "private",
    id: "doc-1",
    workspace_id: "ws-1",
    title: "标题 A",
    parent_id: null,
    sort_order: 0,
    is_starred: false,
    is_template: false,
    created_at: "2026-04-21T00:00:00.000Z",
    updated_at: "2026-04-21T00:00:00.000Z",
    ...overrides,
  };
}

function buildSidebarData(documents: DocumentRecord[]): SidebarInitialData {
  return buildSidebarInitialData({
    activeWorkspaceId: "ws-1",
    workspaces: [],
    documents,
    trashedDocuments: [],
    mindmaps: [],
    mediaAssets: [],
    trashedMediaAssets: [],
    tables: [],
  });
}

function SnapshotProbe() {
  const snapshot = usePreferredSidebarSnapshotData();
  return <div data-testid="snapshot-probe">{snapshot.documents[0]?.title ?? "空"}</div>;
}

describe("AppLayoutShell", () => {
  let container: HTMLDivElement;
  let root: Root;

  beforeEach(() => {
    (globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT =
      true;
    container = document.createElement("div");
    document.body.appendChild(container);
    root = createRoot(container);
    capturedSidebarProps = null;
    capturedBreadcrumbProps = null;
    capturedSearchPaletteProps = null;
    mockUseSidebarData.mockReset();
    mockUseSidebarTreeStream.mockReset();
    mockUsePreferredSidebarSnapshot.mockReset();
  });

  afterEach(() => {
    act(() => {
      root.unmount();
    });
    container.remove();
  });

  it("应把同一份 preferred sidebar snapshot 同时提供给 Sidebar 与 Breadcrumb", async () => {
    const initialData = buildSidebarData([buildDocument({ title: "标题 A" })]);
    const preferredData = buildSidebarData([
      buildDocument({
        title: "标题 B",
        updated_at: "2026-04-21T00:00:01.000Z",
      }),
    ]);
    const sidebarQuery = {
      data: preferredData,
      isLoading: false,
      error: null,
      refetch: vi.fn(async () => preferredData),
      source: "convex-live" as const,
    };
    const treeStream = {
      data: preferredData,
      status: "live" as const,
      cursor: "evt-1",
      error: null,
    };

    mockUseSidebarData.mockReturnValue(sidebarQuery);
    mockUseSidebarTreeStream.mockReturnValue(treeStream);
    mockUsePreferredSidebarSnapshot.mockReturnValue({
      data: preferredData,
      source: "tree_stream",
      syncKey: "sync-key-1",
    });

    await act(async () => {
      root.render(
        <AppLayoutShell initialData={initialData}>
          <div>正文</div>
        </AppLayoutShell>,
      );
    });

    expect(capturedSidebarProps).toMatchObject({
      initialData,
      sidebarQuery,
      sidebarData: preferredData,
      treeStream,
    });
    expect(capturedBreadcrumbProps).toMatchObject({
      documents: preferredData.documents,
    });
    expect(capturedSearchPaletteProps).toMatchObject({
      workspaceId: "ws-1",
    });
  });

  it("应把同一份 preferred sidebar snapshot 继续提供给页面 children", async () => {
    const initialData = buildSidebarData([buildDocument({ title: "标题 A" })]);
    const preferredData = buildSidebarData([
      buildDocument({
        title: "标题 B",
        updated_at: "2026-04-21T00:00:01.000Z",
      }),
    ]);

    mockUseSidebarData.mockReturnValue({
      data: preferredData,
      isLoading: false,
      error: null,
      refetch: vi.fn(async () => preferredData),
      source: "convex-live" as const,
    });
    mockUseSidebarTreeStream.mockReturnValue({
      data: preferredData,
      status: "live" as const,
      cursor: "evt-1",
      error: null,
    });
    mockUsePreferredSidebarSnapshot.mockReturnValue({
      data: preferredData,
      source: "tree_stream",
      syncKey: "sync-key-2",
    });

    await act(async () => {
      root.render(
        <AppLayoutShell initialData={initialData}>
          <SnapshotProbe />
        </AppLayoutShell>,
      );
    });

    const probe = container.querySelector("[data-testid='snapshot-probe']");
    expect(probe?.textContent).toBe("标题 B");
  });
});
