"use client";

import * as React from "react";
import {
  DndContext,
  KeyboardSensor,
  PointerSensor,
  closestCenter,
  type DragEndEvent,
  useSensor,
  useSensors,
} from "@dnd-kit/core";
import {
  SortableContext,
  rectSortingStrategy,
  sortableKeyboardCoordinates,
  useSortable,
} from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import { GripVertical } from "lucide-react";

import { cn } from "@/lib/utils";

type SortableDashboardGridProps = {
  items: string[];
  onReorder: (activeId: string, overId: string) => void;
  className?: string;
  handleClassName?: string;
  children: (key: string) => React.ReactNode;
};

function SortableGridItem({
  id,
  children,
  handleClassName,
}: {
  id: string;
  children: React.ReactNode;
  handleClassName?: string;
}) {
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
    id,
  });

  return (
    <div
      ref={setNodeRef}
      style={{
        transform: CSS.Transform.toString(transform),
        transition,
      }}
      className={cn("relative h-full", isDragging && "z-10 opacity-90")}
    >
      <button
        type="button"
        className={cn(
          "absolute top-1 right-1 z-10 inline-flex size-5 cursor-grab touch-none items-center justify-center rounded text-muted-foreground/60 hover:bg-muted hover:text-foreground active:cursor-grabbing",
          handleClassName,
        )}
        aria-label="Drag to reorder"
        {...attributes}
        {...listeners}
      >
        <GripVertical className="size-3" />
      </button>
      {children}
    </div>
  );
}

export function SortableDashboardGrid({
  items,
  onReorder,
  className,
  handleClassName,
  children,
}: SortableDashboardGridProps) {
  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 8 } }),
    useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }),
  );

  const handleDragEnd = (event: DragEndEvent) => {
    const { active, over } = event;
    if (!over || active.id === over.id) return;
    onReorder(String(active.id), String(over.id));
  };

  return (
    <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
      <SortableContext items={items} strategy={rectSortingStrategy}>
        <div className={className}>
          {items.map((key) => (
            <SortableGridItem key={key} id={key} handleClassName={handleClassName}>
              {children(key)}
            </SortableGridItem>
          ))}
        </div>
      </SortableContext>
    </DndContext>
  );
}
