import { type ReactNode } from "react";
import {
  closestCenter,
  DndContext,
  KeyboardSensor,
  PointerSensor,
  useSensor,
  useSensors,
  type DragEndEvent,
} from "@dnd-kit/core";
import {
  arrayMove,
  SortableContext,
  sortableKeyboardCoordinates,
  verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import type { PanelLayout } from "../lib/panelLayout";
import PanelGroup from "./PanelGroup";

export type PanelItem = { id: string; title: string; body: ReactNode };

// Renders a panel's islands in the user's saved order, with drag-to-reorder + hide + per-group
// collapse driven by `layout` (see lib/panelLayout). `items` holds only the currently AVAILABLE
// groups (a caller drops facet-gated / empty ones); the layout order is filtered to them so a
// stored order that references a now-absent group is tolerated. Reordering/hiding is active only
// in `editing` mode. Shared by all three side panels.
export default function PanelGroups({
  items,
  layout,
  setLayout,
  editing,
}: {
  items: PanelItem[];
  layout: PanelLayout;
  setLayout: (l: PanelLayout) => void;
  editing: boolean;
}) {
  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 4 } }),
    // The group grips are focusable and call themselves reorderable; without this only a pointer
    // could actually move them (keyboard drag matched the other sortable lists).
    useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }),
  );
  const byId = new Map(items.map((it) => [it.id, it]));

  const orderedAvailable = layout.order.filter((id) => byId.has(id));
  // Append any available id missing from the stored order (e.g. a group that became available
  // after the layout was saved) so it never silently disappears.
  for (const it of items) if (!orderedAvailable.includes(it.id)) orderedAvailable.push(it.id);
  const renderedIds = editing
    ? orderedAvailable
    : orderedAvailable.filter((id) => !layout.hidden[id]);

  function toggleCollapse(id: string) {
    setLayout({ ...layout, collapsed: { ...layout.collapsed, [id]: !layout.collapsed[id] } });
  }
  function toggleHidden(id: string) {
    setLayout({ ...layout, hidden: { ...layout.hidden, [id]: !layout.hidden[id] } });
  }
  function onDragEnd(e: DragEndEvent) {
    const { active, over } = e;
    if (!over || active.id === over.id) return;
    const from = layout.order.indexOf(active.id as string);
    const to = layout.order.indexOf(over.id as string);
    if (from < 0 || to < 0) return;
    setLayout({ ...layout, order: arrayMove(layout.order, from, to) });
  }

  return (
    <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={onDragEnd}>
      <SortableContext items={renderedIds} strategy={verticalListSortingStrategy}>
        <div className="space-y-3">
          {renderedIds.map((id) => (
            <PanelGroup
              key={id}
              id={id}
              title={byId.get(id)!.title}
              editing={editing}
              collapsed={!!layout.collapsed[id]}
              hidden={!!layout.hidden[id]}
              onToggleCollapse={() => toggleCollapse(id)}
              onToggleHidden={() => toggleHidden(id)}
            >
              {byId.get(id)!.body}
            </PanelGroup>
          ))}
        </div>
      </SortableContext>
    </DndContext>
  );
}
