import { beforeEach, describe, expect, it, vi } from "vitest";

const mockIsConvexEnabled = vi.fn();
const mockGetAuthedConvexClient = vi.fn();
const mockBuildDocumentBridgeContext = vi.fn();
const mockBuildDocumentQueryEnvelope = vi.fn();
const mockResolveRustBridgeQueryPlan = vi.fn();
const mockExecuteRustBridgeQueryTransport = vi.fn();
const mockResolveKernelFileTreeProjection = vi.fn();
const mockDocumentBridgeErrorResponse = vi.fn((error: unknown) =>
  Response.json(
    {
      error: error instanceof Error ? error.message : String(error),
    },
    { status: 500 },
  ),
);

vi.mock("@/lib/convex/enabled", () => ({
  isConvexEnabled: () => mockIsConvexEnabled(),
}));

vi.mock("@/lib/convex/route", () => ({
  getAuthedConvexClient: () => mockGetAuthedConvexClient(),
}));

vi.mock("@/lib/documents/bridge", () => ({
  buildDocumentBridgeContext: (...args: unknown[]) => mockBuildDocumentBridgeContext(...args),
  buildDocumentQueryEnvelope: (...args: unknown[]) => mockBuildDocumentQueryEnvelope(...args),
  documentBridgeErrorResponse: (...args: unknown[]) => mockDocumentBridgeErrorResponse(...args),
}));

vi.mock("@/lib/documents/rust-runtime", () => ({
  executeRustBridgeQueryTransport: (...args: unknown[]) =>
    mockExecuteRustBridgeQueryTransport(...args),
  resolveRustBridgeQueryPlan: (...args: unknown[]) => mockResolveRustBridgeQueryPlan(...args),
}));

vi.mock("@/lib/server/kernel-file-tree", async () => {
  const actual = await vi.importActual<typeof import("@/lib/server/kernel-file-tree")>(
    "@/lib/server/kernel-file-tree",
  );
  return {
    ...actual,
    resolveKernelFileTreeProjection: (...args: unknown[]) =>
      mockResolveKernelFileTreeProjection(...args),
  };
});

describe("/api/tree/projections/file route", () => {
  beforeEach(() => {
    vi.resetModules();
    mockIsConvexEnabled.mockReset().mockReturnValue(true);
    mockGetAuthedConvexClient.mockReset().mockResolvedValue({
      auth: {
        userId: "user_1",
      },
      client: {
        query: vi.fn(),
        mutation: vi.fn(),
      },
    });
    mockBuildDocumentBridgeContext.mockReset().mockResolvedValue({
      requestId: "req_1",
      traceId: "trace_1",
    });
    mockBuildDocumentQueryEnvelope.mockReset().mockImplementation((input) => input);
    mockResolveRustBridgeQueryPlan.mockReset().mockResolvedValue({
      functionName: "sidebar:datasetList",
      argsJson: {
        workspaceId: "ws_1",
      },
    });
    mockExecuteRustBridgeQueryTransport.mockReset().mockResolvedValue({
      active_workspace_id: "ws_1",
      documents: [],
      media_assets: [],
      mindmap_assets: [],
      table_assets: [],
      mindmap_asset_children: {},
    });
    mockResolveKernelFileTreeProjection.mockReset().mockResolvedValue({
      projectionId: "kernel_projection:file_tree:page_root",
      projection: "file_tree",
      rootNodeId: "page_root",
      items: [
        {
          rowId: "doc:page_root",
          nodeId: "page_root",
          projectionKind: "file_tree",
          rowKind: "document",
        },
        {
          rowId: "asset:table_1",
          nodeId: "asset:table_1",
          projectionKind: "file_tree",
          rowKind: "asset",
        },
      ],
      edges: [],
      meta: {
        search: {
          indexingVisibility: {
            schema: "mnote.file_tree.indexing_visibility",
            schemaVersion: 1,
            source: "kernel.project_view",
            status: "visible",
            requestKey: "page_root:预算",
            indexedResourceKinds: ["document", "index", "asset"],
            visibleResourceKinds: ["document", "index", "asset"],
            metrics: {
              visibleRows: 2,
              visibleEdges: 0,
            },
          },
        },
      },
    });
    mockDocumentBridgeErrorResponse.mockClear();
  });

  it("通过 3000 同源 route 返回 Rust file_tree 搜索 projection", async () => {
    const fetchSpy = vi.spyOn(globalThis, "fetch");

    const { GET } = await import("./route");
    const response = await GET(
      new Request(
        "http://127.0.0.1:3000/api/tree/projections/file?workspaceId=ws_1&rootNodeId=page_root&depth=3&query=%E9%A2%84%E7%AE%97&maxResults=12",
        { method: "GET" },
      ),
    );

    expect(response.status).toBe(200);
    expect(fetchSpy).not.toHaveBeenCalled();
    expect(mockResolveKernelFileTreeProjection).toHaveBeenCalledWith(
      expect.objectContaining({
        workspaceId: "ws_1",
        rootNodeId: "page_root",
        depth: 3,
        query: "预算",
        maxResults: 12,
      }),
    );
    const body = await response.json();
    expect(body).toMatchObject({
      ok: true,
      result: {
        projection: "file_tree",
        rootNodeId: "page_root",
        meta: {
          search: {
            indexingVisibility: {
              schema: "mnote.file_tree.indexing_visibility",
              status: "visible",
              requestKey: "page_root:预算",
            },
          },
        },
      },
    });
    expect(body.result.items.map((item: { rowId: string }) => item.rowId)).toEqual([
      "doc:page_root",
      "asset:table_1",
    ]);
  });

  it("Convex 未启用时返回 501", async () => {
    mockIsConvexEnabled.mockReturnValue(false);

    const { GET } = await import("./route");
    const response = await GET(
      new Request("http://127.0.0.1:3000/api/tree/projections/file?workspaceId=ws_1"),
    );

    expect(response.status).toBe(501);
    expect(await response.json()).toEqual({ error: "当前仅支持 Convex 模式" });
  });
});
