import { describe, expect, it } from "vitest";
import type { KernelFileTreeProjectionItem } from "@/lib/kernel-file-tree";
import type { SidebarTreeNode } from "@/lib/kernel-sidebar";
import type { MediaAsset } from "@/types/media";
import {
  buildFileTreeShellDeletePreflightPayload,
  buildFileTreeShellInternalDropPreflightPayload,
  buildFileTreeShellPastePreflightPayload,
  buildFileTreeShellUploadTargetPreflightPayload,
  buildFileTreeShellRowById,
  buildFileTreeShellVisibleRowIds,
  collectFileTreeShellAssetHints,
  getOrderedFileTreeShellRows,
  inferFileTreeShellTargetDocumentId,
  resolveFileTreeShellMindmapTargetId,
} from "./shell";

describe("file-tree shell helpers", () => {
  const nodeById = new Map<string, SidebarTreeNode>([
    [
      "doc_root",
      {
        id: "doc_root",
        title: "根页面",
      } as SidebarTreeNode,
    ],
  ]);

  const assetById = new Map<string, MediaAsset>([
    [
      "mind_1",
      {
        id: "mind_1",
        document_id: "doc_root",
        workspace_id: "ws_1",
        asset_type: "mindmap",
        file_name: "mindmap.json",
        storage_path: "mindmaps/mind_1/mindmap.json",
      } as MediaAsset,
    ],
    [
      "asset_child_1",
      {
        id: "asset_child_1",
        document_id: "doc_root",
        workspace_id: "ws_1",
        asset_type: "file",
        file_name: "node.png",
        storage_path: "mindmaps/mind_1/assets/node.png",
      } as MediaAsset,
    ],
    [
      "pdf_1",
      {
        id: "pdf_1",
        document_id: "doc_root",
        workspace_id: "ws_1",
        asset_type: "file",
        file_name: "guide.pdf",
        storage_path: "uploads/guide.pdf",
      } as MediaAsset,
    ],
  ]);

  const fileTreeItems: KernelFileTreeProjectionItem[] = [
    {
      rowId: "doc:doc_root",
      rowKind: "document",
      nodeId: "doc_root",
      parentNodeId: null,
      nodeType: "page",
      projectionKind: "file_tree",
      title: "根页面",
      depth: 0,
      position: 0,
      childCount: 3,
      expandable: true,
      expandedByDefault: true,
      capabilities: ["expand", "open", "select"],
      resourceMeta: {
        resourceKind: "document",
        documentId: "doc_root",
        workspaceId: "ws_1",
        iconHint: "page",
      },
      iconHint: "page",
    },
    {
      rowId: "index:doc_root",
      rowKind: "index",
      nodeId: "index:doc_root",
      parentNodeId: "doc_root",
      nodeType: "index",
      projectionKind: "file_tree",
      title: "index.md",
      depth: 1,
      position: 0,
      childCount: 0,
      expandable: false,
      expandedByDefault: false,
      capabilities: ["open", "select"],
      resourceMeta: {
        resourceKind: "index",
        documentId: "doc_root",
        workspaceId: "ws_1",
        iconHint: "index",
      },
      iconHint: "index",
    },
    {
      rowId: "asset-folder:mind_1",
      rowKind: "asset_folder",
      nodeId: "asset-folder:mind_1",
      parentNodeId: "doc_root",
      nodeType: "mindmap",
      projectionKind: "file_tree",
      title: "mindmap",
      depth: 1,
      position: 1,
      childCount: 1,
      expandable: true,
      expandedByDefault: false,
      capabilities: ["expand", "open-asset", "select"],
      resourceMeta: {
        resourceKind: "mindmap",
        documentId: "doc_root",
        assetId: "mind_1",
        workspaceId: "ws_1",
        assetKind: "mindmap",
        iconHint: "mindmap",
      },
      iconHint: "mindmap",
    },
    {
      rowId: "asset:asset_child_1",
      rowKind: "asset",
      nodeId: "asset:asset_child_1",
      parentNodeId: "asset-folder:mind_1",
      nodeType: "asset",
      projectionKind: "file_tree",
      title: "node.png",
      depth: 2,
      position: 0,
      childCount: 0,
      expandable: false,
      expandedByDefault: false,
      capabilities: ["open-asset", "select"],
      resourceMeta: {
        resourceKind: "asset",
        documentId: "doc_root",
        assetId: "asset_child_1",
        workspaceId: "ws_1",
        assetKind: "image",
        iconHint: "image",
      },
      iconHint: "image",
    },
    {
      rowId: "asset:pdf_1",
      rowKind: "asset",
      nodeId: "asset:pdf_1",
      parentNodeId: "doc_root",
      nodeType: "pdf",
      projectionKind: "file_tree",
      title: "guide.pdf",
      depth: 1,
      position: 2,
      childCount: 0,
      expandable: false,
      expandedByDefault: false,
      capabilities: ["open-asset", "select"],
      resourceMeta: {
        resourceKind: "pdf",
        documentId: "doc_root",
        assetId: "pdf_1",
        workspaceId: "ws_1",
        assetKind: "pdf",
        iconHint: "pdf",
      },
      iconHint: "pdf",
    },
  ];

  it("应直接从 kernel file_tree items 构造宿主 row map", () => {
    const rowById = buildFileTreeShellRowById({
      fileTreeItems: [...fileTreeItems],
      nodeById,
      assetById,
    });

    expect(buildFileTreeShellVisibleRowIds([...fileTreeItems])).toEqual([
      "doc:doc_root",
      "index:doc_root",
      "asset-folder:mind_1",
      "asset:asset_child_1",
      "asset:pdf_1",
    ]);

    expect(rowById.get("doc:doc_root")).toMatchObject({
      rowId: "doc:doc_root",
      rowKind: "doc",
      documentId: "doc_root",
      node: expect.objectContaining({
        id: "doc_root",
      }),
    });
    expect(rowById.get("asset-folder:mind_1")).toMatchObject({
      rowId: "asset-folder:mind_1",
      rowKind: "asset-folder",
      documentId: "doc_root",
      assetId: "mind_1",
      asset: expect.objectContaining({
        id: "mind_1",
      }),
    });
  });

  it("应正确解析 file tree shell 的导图投放目标", () => {
    const rowById = buildFileTreeShellRowById({
      fileTreeItems: [...fileTreeItems],
      nodeById,
      assetById,
    });

    expect(resolveFileTreeShellMindmapTargetId(rowById.get("asset-folder:mind_1") ?? null)).toBe(
      "mind_1",
    );
    expect(resolveFileTreeShellMindmapTargetId(rowById.get("asset:asset_child_1") ?? null)).toBe(
      "mind_1",
    );
    expect(resolveFileTreeShellMindmapTargetId(rowById.get("asset:pdf_1") ?? null)).toBeNull();
  });

  it("应能仅凭 focusedRowId 从 shell row map 推回目标页面", () => {
    const rowById = buildFileTreeShellRowById({
      fileTreeItems: [...fileTreeItems],
      nodeById,
      assetById,
    });

    expect(
      inferFileTreeShellTargetDocumentId({
        focusedRowId: "asset-folder:mind_1",
        rowById,
        activeDocId: null,
      }),
    ).toBe("doc_root");
    expect(
      inferFileTreeShellTargetDocumentId({
        focusedRowId: "asset:pdf_1",
        rowById,
        activeDocId: null,
      }),
    ).toBe("doc_root");
    expect(
      inferFileTreeShellTargetDocumentId({
        focusedRowId: null,
        rowById,
        activeDocId: "doc_root",
      }),
    ).toBe("doc_root");
  });

  it("应按当前可见顺序返回选中的 shell rows", () => {
    const rowById = buildFileTreeShellRowById({
      fileTreeItems: [...fileTreeItems],
      nodeById,
      assetById,
    });

    expect(
      getOrderedFileTreeShellRows({
        rowIds: ["asset:pdf_1", "doc:doc_root", "missing"],
        visibleRowIds: buildFileTreeShellVisibleRowIds([...fileTreeItems]),
        rowById,
      }).map((row) => row.rowId),
    ).toEqual(["doc:doc_root", "asset:pdf_1"]);
  });

  it("内部拖放 preflight payload 应只收集 Rust 所需的行与父子快照", () => {
    const rowById = buildFileTreeShellRowById({
      fileTreeItems: [...fileTreeItems],
      nodeById,
      assetById,
    });

    const result = buildFileTreeShellInternalDropPreflightPayload({
      workspaceId: "ws_1",
      copy: false,
      targetDocumentId: null,
      targetRowId: "asset-folder:mind_1",
      focusedRowId: null,
      activeDocId: null,
      rowIds: ["asset:asset_child_1", "doc:doc_root", "asset:pdf_1", "asset:pdf_1"],
      rowById,
      parentById: new Map([
        ["doc_root", null],
        ["doc_child", "doc_root"],
      ]),
    });

    expect(result).toEqual({
      workspaceId: "ws_1",
      copy: false,
      targetDocumentId: null,
      targetRowId: "asset-folder:mind_1",
      focusedRowId: null,
      activeDocumentId: null,
      rowIds: ["asset:asset_child_1", "doc:doc_root", "asset:pdf_1", "asset:pdf_1"],
      rows: [
        {
          rowId: "asset-folder:mind_1",
          rowKind: "asset-folder",
          documentId: "doc_root",
          assetId: "mind_1",
          assetDocumentId: "doc_root",
          assetType: "mindmap",
          storagePath: "mindmaps/mind_1/mindmap.json",
        },
        {
          rowId: "asset:asset_child_1",
          rowKind: "asset",
          documentId: "doc_root",
          assetId: "asset_child_1",
          assetDocumentId: "doc_root",
          assetType: "file",
          storagePath: "mindmaps/mind_1/assets/node.png",
        },
        {
          rowId: "doc:doc_root",
          rowKind: "doc",
          documentId: "doc_root",
          assetId: null,
          assetDocumentId: null,
          assetType: null,
          storagePath: null,
        },
        {
          rowId: "asset:pdf_1",
          rowKind: "asset",
          documentId: "doc_root",
          assetId: "pdf_1",
          assetDocumentId: "doc_root",
          assetType: "file",
          storagePath: "uploads/guide.pdf",
        },
      ],
      documentParents: [
        { documentId: "doc_root", parentId: null },
        { documentId: "doc_child", parentId: "doc_root" },
      ],
    });
  });

  it("删除 preflight payload 应只收集选中行与父子快照", () => {
    const rowById = buildFileTreeShellRowById({
      fileTreeItems: [...fileTreeItems],
      nodeById,
      assetById,
    });

    const result = buildFileTreeShellDeletePreflightPayload({
      workspaceId: "ws_1",
      rowIds: ["doc:doc_root", "asset:pdf_1", "missing"],
      rowById,
      parentById: new Map([
        ["doc_root", null],
        ["doc_child", "doc_root"],
      ]),
    });

    expect(result).toEqual({
      workspaceId: "ws_1",
      rowIds: ["doc:doc_root", "asset:pdf_1", "missing"],
      rows: [
        {
          rowId: "doc:doc_root",
          rowKind: "doc",
          documentId: "doc_root",
          assetId: null,
          assetDocumentId: null,
          assetType: null,
          storagePath: null,
        },
        {
          rowId: "asset:pdf_1",
          rowKind: "asset",
          documentId: "doc_root",
          assetId: "pdf_1",
          assetDocumentId: "doc_root",
          assetType: "file",
          storagePath: "uploads/guide.pdf",
        },
      ],
      documentParents: [
        { documentId: "doc_root", parentId: null },
        { documentId: "doc_child", parentId: "doc_root" },
      ],
    });
  });

  it("粘贴 preflight payload 应只收集剪贴板行与当前 focused 目标行", () => {
    const rowById = buildFileTreeShellRowById({
      fileTreeItems: [...fileTreeItems],
      nodeById,
      assetById,
    });

    const result = buildFileTreeShellPastePreflightPayload({
      workspaceId: "ws_1",
      targetDocumentId: null,
      focusedRowId: "asset-folder:mind_1",
      activeDocId: "doc_active",
      rowIds: ["index:doc_root", "asset:pdf_1", "missing"],
      rowById,
    });

    expect(result).toEqual({
      workspaceId: "ws_1",
      targetDocumentId: null,
      focusedRowId: "asset-folder:mind_1",
      activeDocumentId: "doc_active",
      rowIds: ["index:doc_root", "asset:pdf_1", "missing"],
      rows: [
        {
          rowId: "asset-folder:mind_1",
          rowKind: "asset-folder",
          documentId: "doc_root",
          assetId: "mind_1",
          assetDocumentId: "doc_root",
          assetType: "mindmap",
          storagePath: "mindmaps/mind_1/mindmap.json",
        },
        {
          rowId: "index:doc_root",
          rowKind: "index",
          documentId: "doc_root",
          assetId: null,
          assetDocumentId: null,
          assetType: null,
          storagePath: null,
        },
        {
          rowId: "asset:pdf_1",
          rowKind: "asset",
          documentId: "doc_root",
          assetId: "pdf_1",
          assetDocumentId: "doc_root",
          assetType: "file",
          storagePath: "uploads/guide.pdf",
        },
      ],
    });
  });

  it("上传目标 preflight payload 应只收集目标行、focused 行与文档工作区快照", () => {
    const rowById = buildFileTreeShellRowById({
      fileTreeItems: [...fileTreeItems],
      nodeById,
      assetById,
    });

    const result = buildFileTreeShellUploadTargetPreflightPayload({
      workspaceId: "ws_fallback",
      targetDocumentId: null,
      targetRowId: "asset:asset_child_1",
      focusedRowId: "asset-folder:mind_1",
      activeDocId: "doc_active",
      rowById,
      documentWorkspaceById: new Map([
        ["doc_root", "ws_1"],
        ["doc_active", "ws_active"],
      ]),
    });

    expect(result).toEqual({
      workspaceId: "ws_fallback",
      targetDocumentId: null,
      targetRowId: "asset:asset_child_1",
      focusedRowId: "asset-folder:mind_1",
      activeDocumentId: "doc_active",
      rows: [
        {
          rowId: "asset:asset_child_1",
          rowKind: "asset",
          documentId: "doc_root",
          assetId: "asset_child_1",
          assetDocumentId: "doc_root",
          assetType: "file",
          storagePath: "mindmaps/mind_1/assets/node.png",
        },
        {
          rowId: "asset-folder:mind_1",
          rowKind: "asset-folder",
          documentId: "doc_root",
          assetId: "mind_1",
          assetDocumentId: "doc_root",
          assetType: "mindmap",
          storagePath: "mindmaps/mind_1/mindmap.json",
        },
      ],
      documentWorkspaces: [
        { documentId: "doc_root", workspaceId: "ws_1" },
        { documentId: "doc_active", workspaceId: "ws_active" },
      ],
    });
  });

  it("应能按 assetId 从 shell row map 回填 asset 与 asset-folder 的提示元数据", () => {
    const rowById = buildFileTreeShellRowById({
      fileTreeItems: [...fileTreeItems],
      nodeById,
      assetById,
    });

    expect(
      collectFileTreeShellAssetHints({
        rowById,
        assetIds: ["mind_1", "pdf_1", "missing"],
      }).map((asset) => asset.id),
    ).toEqual(["mind_1", "pdf_1"]);
  });
});
