import { act } from "react";
import { createRoot, type Root } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { ReactNode } from "react";
import { MoveEmbedPickerDialog } from "./move-embed-picker-dialog";

(globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;

const sidebarData = {
  activeWorkspaceId: "ws_test",
  workspaces: [],
  documents: [],
  kernelSidebarProjection: {
    projectionId: "kernel_projection:sidebar_tree:workspace_root",
    projection: "sidebar_tree",
    rootNodeId: null,
    items: [],
    edges: [],
  },
  kernelSidebarTree: [],
  trashedDocuments: [],
};

vi.mock("@tanstack/react-query", () => ({
  useQuery: ({ queryKey }: { queryKey: unknown[] }) => {
    const key = Array.isArray(queryKey) ? queryKey[0] : queryKey;
    if (key === "move-embed-picker-sidebar") {
      return {
        data: sidebarData,
        isLoading: false,
        error: null,
      };
    }
    return {
      data: null,
      isLoading: false,
      error: null,
    };
  },
}));

const mockUseDocumentSearch = vi.fn(() => ({
  data: null,
  isLoading: false,
  error: null,
}));

vi.mock("@/hooks/use-document-search", () => ({
  useDocumentSearch: (...args: unknown[]) => mockUseDocumentSearch(...args),
}));

vi.mock("@/components/ui/dialog", () => ({
  Dialog: ({ open, children }: { open: boolean; children: ReactNode }) => (open ? <div>{children}</div> : null),
  DialogContent: ({ children, className }: { children: ReactNode; className?: string }) => (
    <div className={className}>{children}</div>
  ),
  DialogTitle: ({ children, className }: { children: ReactNode; className?: string }) => (
    <div className={className}>{children}</div>
  ),
}));

vi.mock("@/components/ui/input", () => ({
  Input: (props: React.InputHTMLAttributes<HTMLInputElement>) => <input {...props} />,
}));

vi.mock("@/components/ui/tabs", () => ({
  Tabs: ({ children }: { children: ReactNode }) => <div>{children}</div>,
  TabsList: ({ children, className }: { children: ReactNode; className?: string }) => (
    <div className={className}>{children}</div>
  ),
  TabsTrigger: ({
    children,
    className,
    value,
  }: {
    children: ReactNode;
    className?: string;
    value: string;
  }) => (
    <button type="button" className={className} data-value={value}>
      {children}
    </button>
  ),
  TabsContent: ({ children, className }: { children: ReactNode; className?: string }) => (
    <div className={className}>{children}</div>
  ),
}));

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

  beforeEach(() => {
    container = document.createElement("div");
    document.body.appendChild(container);
    root = createRoot(container);
  });

  afterEach(() => {
    act(() => {
      root.unmount();
    });
    container.remove();
    vi.clearAllMocks();
    mockUseDocumentSearch.mockReset();
    mockUseDocumentSearch.mockReturnValue({
      data: null,
      isLoading: false,
      error: null,
    });
    delete window.__MNOTE_RUNTIME_CONFIG__;
  });

  it("空查询时会使用统一 picker surface 并透传根目录选择", async () => {
    const onPick = vi.fn(async () => undefined);
    const onOpenChange = vi.fn();

    await act(async () => {
      root.render(
        <MoveEmbedPickerDialog
          open
          onOpenChange={onOpenChange}
          workspaceId="ws_test"
          defaultMode="move"
          allowRoot
          excludeIds={["doc_hidden"]}
          onPick={onPick}
        />,
      );
    });

    const shellPickButton = container.querySelector('[data-testid="tree-picker-root"]');
    expect(shellPickButton).not.toBeNull();

    await act(async () => {
      shellPickButton?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
    });

    expect(onPick).toHaveBeenCalledTimes(1);
    expect(onPick).toHaveBeenCalledWith("move", null);
    expect(onOpenChange).toHaveBeenCalledWith(false);
  });

  it("搜索结果也应继续复用统一 picker surface", async () => {
    mockUseDocumentSearch.mockReturnValue({
      data: {
        results: [
          {
            id: "doc_target",
            title: "目标页面",
            matchField: "title",
          },
        ],
      },
      isLoading: false,
      error: null,
    });

    const onPick = vi.fn(async () => undefined);
    const onOpenChange = vi.fn();

    await act(async () => {
      root.render(
        <MoveEmbedPickerDialog
          open
          onOpenChange={onOpenChange}
          workspaceId="ws_test"
          defaultMode="move"
          allowRoot
          excludeIds={[]}
          onPick={onPick}
        />,
      );
    });

    const input = container.querySelector("input");
    expect(input).not.toBeNull();

    await act(async () => {
      input?.dispatchEvent(new Event("input", { bubbles: true }));
      Object.defineProperty(input as HTMLInputElement, "value", {
        configurable: true,
        value: "目标",
      });
      input?.dispatchEvent(new Event("change", { bubbles: true }));
    });

    const pickerSurface = container.querySelector('[data-testid="tree-picker-surface"]');
    const pickerRows = container.querySelectorAll('[data-testid="tree-picker-row"]');
    expect(pickerSurface).not.toBeNull();
    expect(pickerRows).toHaveLength(1);

    await act(async () => {
      pickerRows[0]?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
    });

    expect(onPick).toHaveBeenCalledWith("move", "doc_target");
    expect(onOpenChange).toHaveBeenCalledWith(false);
  });

  it("rust_family 配置下，picker 空态与结果态都应进入统一 host", async () => {
    window.__MNOTE_RUNTIME_CONFIG__ = {
      treeRendererFamily: "rust_family",
    };

    const onPick = vi.fn(async () => undefined);
    const onOpenChange = vi.fn();

    await act(async () => {
      root.render(
        <MoveEmbedPickerDialog
          open
          onOpenChange={onOpenChange}
          workspaceId="ws_test"
          defaultMode="move"
          allowRoot
          excludeIds={[]}
          onPick={onPick}
        />,
      );
    });

    const emptySurface = container.querySelector('[data-testid="tree-picker-surface"]');
    expect(emptySurface?.getAttribute("data-tree-host-kind")).toBe("rust_family");
    expect(emptySurface?.getAttribute("data-tree-host-implementation")).toBe("mnote_web_iframe_proxy");
    expect(
      container.querySelector('[data-testid="tree-picker-surface-rust-host"]'),
    ).not.toBeNull();
    expect(
      container.querySelector('[data-testid="tree-picker-surface-rust-iframe"]'),
    ).not.toBeNull();

    mockUseDocumentSearch.mockReturnValue({
      data: {
        results: [
          {
            id: "doc_target",
            title: "目标页面",
            matchField: "title",
          },
        ],
      },
      isLoading: false,
      error: null,
    });

    const input = container.querySelector("input");
    expect(input).not.toBeNull();

    await act(async () => {
      Object.defineProperty(input as HTMLInputElement, "value", {
        configurable: true,
        value: "目标",
      });
      input?.dispatchEvent(new Event("input", { bubbles: true }));
      input?.dispatchEvent(new Event("change", { bubbles: true }));
    });

    const resultSurface = container.querySelector('[data-testid="tree-picker-surface"]');
    expect(resultSurface?.getAttribute("data-tree-host-kind")).toBe("rust_family");
    expect(resultSurface?.getAttribute("data-tree-host-implementation")).toBe("mnote_web_iframe_proxy");
    expect(
      container.querySelector('[data-testid="tree-picker-surface-rust-host"]'),
    ).not.toBeNull();
    expect(
      container.querySelector('[data-testid="tree-picker-surface-rust-iframe"]'),
    ).not.toBeNull();
  });
});
