'use client';

import { useState } from 'react';
import {
  DndContext,
  KeyboardSensor,
  PointerSensor,
  closestCenter,
  useSensor,
  useSensors,
  type DragEndEvent,
} from '@dnd-kit/core';
import {
  SortableContext,
  arrayMove,
  sortableKeyboardCoordinates,
  useSortable,
  verticalListSortingStrategy,
} from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { GripVertical, LayoutGrid } from 'lucide-react';

import { Button } from '@/components/ui/button';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from '@/components/ui/dialog';
import { Switch } from '@/components/ui/switch';
import { cn } from '@/lib/utils';
import { useDashboardWidgets } from '@/hooks/use-dashboard-widgets';
import type { DashboardWidget } from './widget-registry';

/**
 * Combined visibility + reorder picker for the dashboard header. Two
 * sections in one modal:
 *
 *   1. "On dashboard" — visible widgets, each row with a drag handle
 *      (reorder via dnd-kit single SortableContext, no buckets); flipping
 *      a switch off moves the row to section 2.
 *   2. "Hidden" — widgets currently off; flipping a switch on appends to
 *      the bottom of section 1.
 *
 * Both visibility toggles and order changes commit optimistically via
 * `useDashboardWidgets` so the dashboard reflows in the background and
 * the rep can keep editing. The "Rearrange" button on the header is
 * gone — order lives here too now, keeping all dashboard layout
 * controls in one place.
 */
export function CustomizeWidgetsMenu() {
  const [open, setOpen] = useState(false);
  const {
    allWidgets,
    visibleWidgets,
    visibility,
    setVisible,
    setAll,
    setOrder,
    resetToDefaults,
    isSaving,
  } = useDashboardWidgets();

  const visibleCount = Object.values(visibility).filter(Boolean).length;
  const allVisible = visibleCount === allWidgets.length;
  const allHidden = visibleCount === 0;
  const matchesDefaults = allWidgets.every((w) => (visibility[w.id] ?? false) === w.defaultVisible);

  // Hidden = everything not currently rendered. Sorted by registry order
  // so it reads predictably (newly-added widgets appear at the bottom
  // until the rep explicitly enables them).
  const hidden = allWidgets.filter((w) => !visibility[w.id]);

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

  function onDragEnd(event: DragEndEvent) {
    const { active, over } = event;
    if (!over || active.id === over.id) return;
    const ids = visibleWidgets.map((w) => w.id);
    const oldIndex = ids.indexOf(String(active.id));
    const newIndex = ids.indexOf(String(over.id));
    if (oldIndex === -1 || newIndex === -1) return;
    setOrder(arrayMove(ids, oldIndex, newIndex));
  }

  return (
    <Dialog open={open} onOpenChange={setOpen}>
      <DialogTrigger asChild>
        <Button variant="outline" size="sm" className="gap-1.5">
          <LayoutGrid className="h-4 w-4" aria-hidden />
          Customize
        </Button>
      </DialogTrigger>
      <DialogContent className="max-w-xl">
        <DialogHeader>
          <DialogTitle>Customize dashboard</DialogTitle>
          <DialogDescription>
            Drag a visible widget to change its position. Toggle the switch to show or hide. Hidden
            widgets leave no empty space - the layout reflows to fill the available width.
          </DialogDescription>
        </DialogHeader>

        {/* Toggle + reorder list. Capped at ~60vh with internal scroll so
            the modal doesn't push the action footer off-screen. */}
        <div className="max-h-[60vh] -mx-2 overflow-y-auto px-2">
          {visibleWidgets.length > 0 ? (
            <Section title={`On dashboard (${visibleWidgets.length})`}>
              <DndContext
                sensors={sensors}
                collisionDetection={closestCenter}
                onDragEnd={onDragEnd}
              >
                <SortableContext
                  items={visibleWidgets.map((w) => w.id)}
                  strategy={verticalListSortingStrategy}
                >
                  <ul className="space-y-1">
                    {visibleWidgets.map((w, idx) => (
                      <SortableVisibleRow
                        key={w.id}
                        widget={w}
                        position={idx + 1}
                        disabled={isSaving}
                        onToggle={(checked) => setVisible(w.id, checked)}
                      />
                    ))}
                  </ul>
                </SortableContext>
              </DndContext>
            </Section>
          ) : null}

          {hidden.length > 0 ? (
            <Section title={`Hidden (${hidden.length})`}>
              <ul className="space-y-1">
                {hidden.map((w) => (
                  <HiddenRow
                    key={w.id}
                    widget={w}
                    disabled={isSaving}
                    onToggle={(checked) => setVisible(w.id, checked)}
                  />
                ))}
              </ul>
            </Section>
          ) : null}
        </div>

        <DialogFooter className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between sm:gap-2">
          <span className="text-xs text-muted-foreground sm:order-first">
            {visibleCount} of {allWidgets.length} visible
          </span>
          <div className="flex flex-wrap items-center gap-2 sm:flex-nowrap">
            <Button
              variant="ghost"
              size="sm"
              disabled={matchesDefaults || isSaving}
              onClick={resetToDefaults}
            >
              Reset to defaults
            </Button>
            <Button
              variant="outline"
              size="sm"
              disabled={allHidden || isSaving}
              onClick={() => setAll(false)}
            >
              Hide all
            </Button>
            <Button
              variant="outline"
              size="sm"
              disabled={allVisible || isSaving}
              onClick={() => setAll(true)}
            >
              Show all
            </Button>
            <Button size="sm" onClick={() => setOpen(false)} className="w-full sm:w-auto">
              Done
            </Button>
          </div>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

function Section({ title, children }: { title: string; children: React.ReactNode }) {
  return (
    <div className="py-2 first:pt-1">
      <div className="px-1 pb-1.5 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">
        {title}
      </div>
      {children}
    </div>
  );
}

function SortableVisibleRow({
  widget,
  position,
  disabled,
  onToggle,
}: {
  widget: DashboardWidget;
  position: number;
  disabled: boolean;
  onToggle: (checked: boolean) => void;
}) {
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
    id: widget.id,
  });
  return (
    <li
      ref={setNodeRef}
      style={{ transform: CSS.Transform.toString(transform), transition }}
      className={cn(
        'flex items-start gap-2 rounded-md border bg-background px-2 py-2.5',
        isDragging && 'opacity-60 shadow-md',
      )}
    >
      <button
        type="button"
        className="mt-0.5 inline-flex h-7 w-7 shrink-0 cursor-grab items-center justify-center rounded text-muted-foreground hover:bg-accent active:cursor-grabbing"
        aria-label={`Drag handle for ${widget.label}`}
        {...attributes}
        {...listeners}
      >
        <GripVertical className="h-4 w-4" aria-hidden />
      </button>
      <span className="mt-1 w-5 shrink-0 text-right text-xs tabular-nums text-muted-foreground">
        {position}
      </span>
      <div className="min-w-0 flex-1">
        <div className="text-sm font-medium text-foreground">{widget.label}</div>
        <p className="text-xs text-muted-foreground">{widget.description}</p>
      </div>
      <Switch
        aria-label={`Show ${widget.label}`}
        checked
        disabled={disabled}
        onCheckedChange={onToggle}
        className="mt-0.5 shrink-0"
      />
    </li>
  );
}

function HiddenRow({
  widget,
  disabled,
  onToggle,
}: {
  widget: DashboardWidget;
  disabled: boolean;
  onToggle: (checked: boolean) => void;
}) {
  return (
    <li className="flex items-start gap-3 rounded-md px-3 py-2.5 hover:bg-accent/40">
      <div className="min-w-0 flex-1">
        <div className="text-sm font-medium text-foreground">{widget.label}</div>
        <p className="text-xs text-muted-foreground">{widget.description}</p>
      </div>
      <Switch
        aria-label={`Show ${widget.label}`}
        checked={false}
        disabled={disabled}
        onCheckedChange={onToggle}
        className="mt-0.5 shrink-0"
      />
    </li>
  );
}
