"use client";

import Link from "next/link";
import { useCallback, useRef, useState } from "react";
import {
  DndContext,
  PointerSensor,
  closestCenter,
  useSensor,
  useSensors,
  type DragEndEvent,
  type DragStartEvent,
} from "@dnd-kit/core";
import { SortableContext, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import { useVirtualizer, type VirtualItem } from "@tanstack/react-virtual";
import { ChevronRight, GripVertical, MoreHorizontal, Plus } from "lucide-react";
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
import type { SidebarTreeNode } from "@/lib/kernel-sidebar";
import type { PageTreeProjectionItem } from "@/lib/tree-projection";
import { cn } from "@/lib/utils";

interface PrivateTreeProps {
  rows: PageTreeProjectionItem[];
  expanded: Set<string>;
  activeId: string;
  onToggleExpand: (id: string) => void;
  onMove: (nodeId: string, parentId: string | null, index: number) => void;
  onCreateChild: (parentId: string | null) => void;
  onContextMenu: (event: React.MouseEvent, node: SidebarTreeNode) => void;
}

const ROW_HEIGHT = 36;

export function PrivateTree({
  rows,
  expanded,
  activeId,
  onToggleExpand,
  onMove,
  onCreateChild,
  onContextMenu,
}: PrivateTreeProps) {
  const scrollAreaRef = useRef<HTMLDivElement>(null);
  const [activeDragId, setActiveDragId] = useState<string | null>(null);

  const sensors = useSensors(
    useSensor(PointerSensor, {
      activationConstraint: { distance: 5 },
    }),
  );

  // eslint-disable-next-line react-hooks/incompatible-library
  const virtualizer = useVirtualizer({
    count: rows.length,
    getScrollElement: () => scrollAreaRef.current,
    estimateSize: () => ROW_HEIGHT,
    overscan: 10,
  });

  const handleDragStart = useCallback((event: DragStartEvent) => {
    setActiveDragId(event.active.id as string);
  }, []);

  const handleDragEnd = useCallback(
    (event: DragEndEvent) => {
      const activeId = event.active.id as string;
      const overId = event.over?.id as string | undefined;
      setActiveDragId(null);
      if (!overId || activeId === overId) {
        return;
      }
      const activeIndex = rows.findIndex((item) => item.nodeId === activeId);
      const overIndex = rows.findIndex((item) => item.nodeId === overId);
      if (activeIndex === -1 || overIndex === -1) {
        return;
      }
      const targetParent = rows[overIndex].parentNodeId;
      const siblingList = rows.filter((item) => item.parentNodeId === targetParent);
      const siblingIndex = siblingList.findIndex((item) => item.nodeId === overId);
      const position = siblingIndex === -1 ? siblingList.length : siblingIndex;
      onMove(activeId, targetParent, position);
    },
    [onMove, rows],
  );

  const handleDragCancel = useCallback(() => {
    setActiveDragId(null);
  }, []);

  if (rows.length === 0) {
    return <div className="px-4 py-6 text-sm text-gray-400">暂无页面，点击下方按钮创建</div>;
  }

  return (
    <ScrollAreaPrimitive.Root type="auto" className="relative h-full w-full">
      <ScrollAreaPrimitive.Viewport ref={scrollAreaRef} className="h-full w-full">
        <DndContext
          sensors={sensors}
          collisionDetection={closestCenter}
          onDragStart={handleDragStart}
          onDragEnd={handleDragEnd}
          onDragCancel={handleDragCancel}
        >
          <SortableContext items={rows.map((item) => item.nodeId)} strategy={verticalListSortingStrategy}>
            <div className="relative h-full">
              <div style={{ height: virtualizer.getTotalSize(), position: "relative" }}>
                {virtualizer.getVirtualItems().map((virtualRow) => {
                  const item = rows[virtualRow.index];
                  return (
                    <VirtualRow key={item.nodeId} virtualRow={virtualRow}>
                      <SortableTreeRow
                        node={item.node}
                        depth={item.depth}
                        expanded={expanded.has(item.nodeId)}
                        hasChildren={item.childCount > 0}
                        activeId={activeId}
                        isDragging={activeDragId === item.nodeId}
                        onToggleExpand={() => onToggleExpand(item.nodeId)}
                        onCreateChild={() => onCreateChild(item.nodeId)}
                        onContextMenu={(event) => onContextMenu(event, item.node)}
                      />
                    </VirtualRow>
                  );
                })}
              </div>
            </div>
          </SortableContext>
        </DndContext>
      </ScrollAreaPrimitive.Viewport>
      <ScrollAreaPrimitive.ScrollAreaScrollbar
        orientation="vertical"
        className="flex w-2.5 touch-none select-none border-l border-l-transparent bg-transparent px-0.5 py-2"
      >
        <ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-[#c9d6f8]" />
      </ScrollAreaPrimitive.ScrollAreaScrollbar>
      <ScrollAreaPrimitive.Corner />
    </ScrollAreaPrimitive.Root>
  );
}

function VirtualRow({
  children,
  virtualRow,
}: {
  children: React.ReactNode;
  virtualRow: VirtualItem;
}) {
  return (
    <div
      className="absolute left-0 right-0"
      style={{
        transform: `translateY(${virtualRow.start}px)`,
        height: `${virtualRow.size}px`,
      }}
    >
      {children}
    </div>
  );
}

interface SortableTreeRowProps {
  node: SidebarTreeNode;
  depth: number;
  expanded: boolean;
  hasChildren: boolean;
  activeId: string;
  isDragging: boolean;
  onToggleExpand: () => void;
  onCreateChild: () => void;
  onContextMenu: (event: React.MouseEvent) => void;
}

function SortableTreeRow({
  node,
  depth,
  expanded,
  hasChildren,
  activeId,
  isDragging,
  onToggleExpand,
  onCreateChild,
  onContextMenu,
}: SortableTreeRowProps) {
  const { attributes, listeners, setNodeRef, transform, transition } = useSortable({
    id: node.id,
  });

  const style = {
    transform: CSS.Translate.toString(transform),
    transition,
  };

  return (
    <div
      ref={setNodeRef}
      style={style}
      className={cn(
        "group flex items-center gap-2 px-3 py-[2px] min-h-[27px] w-full cursor-pointer rounded-[3px] text-wolai-text-primary text-[14px] font-medium hover:bg-wolai-bg-hover transition-colors duration-150",
        activeId === node.id && "bg-wolai-bg-active text-[#2563eb]",
        isDragging && "opacity-60",
      )}
      data-testid="page-tree-row"
      data-node-id={node.id}
      data-active={activeId === node.id}
      onContextMenu={onContextMenu}
    >
      <button
        type="button"
        aria-label="拖拽排序"
        className="flex h-6 w-6 items-center justify-center rounded-md text-wolai-text-secondary hover:text-wolai-text-primary shrink-0"
        {...listeners}
        {...attributes}
      >
        <GripVertical className="w-4 h-4" />
      </button>
      <div
        className="flex flex-1 items-center gap-2"
        style={{ paddingLeft: depth * 12 }}
      >
        {hasChildren ? (
          <button
            type="button"
            aria-label="展开或折叠"
            data-testid="page-tree-toggle"
            onClick={onToggleExpand}
            className="flex h-5 w-5 items-center justify-center rounded-md hover:bg-gray-100 shrink-0"
          >
            <ChevronRight className={cn("w-4 h-4 text-wolai-text-secondary transition-transform group-hover:text-wolai-text-primary", expanded && "rotate-90")} />
          </button>
        ) : (
          <span className="w-5 h-5 shrink-0" />
        )}
        <Link
          href={`/documents/${node.id}`}
          data-testid="page-tree-open"
          className="flex-1 truncate text-left"
        >
          {node.title || "无标题"}
        </Link>
      </div>
      <button
        type="button"
        aria-label="新建子页面"
        data-testid="page-tree-create"
        onClick={onCreateChild}
        className="rounded-md p-1 text-gray-400 hover:bg-gray-100 hover:text-gray-700 shrink-0"
      >
        <Plus className="w-4 h-4" />
      </button>
      <button
        type="button"
        aria-label="更多操作"
        onClick={(event) => {
          event.preventDefault();
          onContextMenu(event);
        }}
        className="rounded-md p-1 text-gray-400 hover:bg-gray-100 hover:text-gray-700 shrink-0"
      >
        <MoreHorizontal className="w-4 h-4" />
      </button>
    </div>
  );
}
