import {
  DndContext,
  DragEndEvent,
  KeyboardSensor,
  MouseSensor,
  TouchSensor,
  closestCenter,
  useSensor,
  useSensors,
} from "@dnd-kit/core";
import {
  restrictToParentElement,
  restrictToVerticalAxis,
} from "@dnd-kit/modifiers";
import {
  SortableContext,
  arrayMove,
  sortableKeyboardCoordinates,
  useSortable,
  verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import classNames from "classnames";

import { Toggle } from "../buttons/Toggle";
import { Icon, Icons } from "../Icon";

export interface ToggleableItem {
  id: string;
  name: string;
  disabled?: boolean;
  enabled?: boolean;
}

function SortableItemWithToggle(props: {
  item: ToggleableItem;
  onToggle: (id: string) => void;
}) {
  const { attributes, listeners, setNodeRef, transform, transition } =
    useSortable({ id: props.item.id });

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

  const handleToggleClick = (e: React.MouseEvent) => {
    e.stopPropagation();
    e.preventDefault();
    props.onToggle(props.item.id);
  };

  return (
    <div
      ref={setNodeRef}
      style={style}
      {...attributes}
      className={classNames(
        "bg-dropdown-background hover:bg-dropdown-hoverBackground select-none space-x-3 flex items-center max-w-[25rem] py-3 px-4 rounded-lg",
        props.item.disabled && "opacity-50",
      )}
    >
      <span className="flex-1 text-white font-bold">{props.item.name}</span>
      {props.item.disabled && <Icon icon={Icons.UNPLUG} />}
      <div
        onClick={handleToggleClick}
        className="cursor-pointer flex-shrink-0"
        onMouseDown={(e) => e.stopPropagation()}
        onTouchStart={(e) => e.stopPropagation()}
      >
        <Toggle enabled={props.item.enabled ?? true} />
      </div>
      <div
        {...listeners}
        className={classNames(
          "cursor-grab touch-manipulation flex-shrink-0",
          transform ? "cursor-grabbing" : "cursor-grab",
        )}
      >
        <Icon icon={Icons.MENU} />
      </div>
    </div>
  );
}

export function SortableListWithToggles(props: {
  items: ToggleableItem[];
  setItems: (items: ToggleableItem[]) => void;
  onToggle: (id: string) => void;
}) {
  const sensors = useSensors(
    useSensor(TouchSensor, {
      activationConstraint: {
        delay: 75,
        tolerance: 1,
      },
    }),
    useSensor(MouseSensor),
    useSensor(KeyboardSensor, {
      coordinateGetter: sortableKeyboardCoordinates,
    }),
  );

  const handleDragEnd = (event: DragEndEvent) => {
    const { active, over } = event;
    if (!over) return;
    if (active.id !== over.id) {
      const currentItems = props.items;
      const oldIndex = currentItems.findIndex((item) => item.id === active.id);
      const newIndex = currentItems.findIndex((item) => item.id === over.id);
      const newItems = arrayMove(currentItems, oldIndex, newIndex);
      props.setItems(newItems);
    }
  };

  return (
    <DndContext
      sensors={sensors}
      collisionDetection={closestCenter}
      onDragEnd={handleDragEnd}
      modifiers={[restrictToVerticalAxis, restrictToParentElement]}
    >
      <SortableContext
        items={props.items}
        strategy={verticalListSortingStrategy}
      >
        <div className="flex flex-col gap-2">
          {props.items.map((item) => (
            <SortableItemWithToggle
              key={item.id}
              item={item}
              onToggle={props.onToggle}
            />
          ))}
        </div>
      </SortableContext>
    </DndContext>
  );
}
