'use client';

import { useState } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import {
  DndContext,
  closestCenter,
  type DragEndEvent,
  PointerSensor,
  useSensor,
  useSensors,
} from '@dnd-kit/core';
import { SortableContext, verticalListSortingStrategy, useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { GripVertical, Plus, Loader2, Trash2, Users } from 'lucide-react';
import { toast } from 'sonner';

import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Badge } from '@/components/ui/badge';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { EmptyState } from '@/components/shared/empty-state';
import { ClientPicker } from '@/components/shared/client-picker';
import { usePermissions } from '@/hooks/use-permissions';
import { useRealtimeInvalidation } from '@/hooks/use-realtime-invalidation';
import { apiFetch } from '@/lib/api/client';
import { toastError } from '@/lib/api/toast-error';

interface WaitingListEntry {
  id: string;
  clientId: string;
  clientName: string | null;
  position: number;
  priority: string;
  notifyPref: string;
  notes: string | null;
  createdAt: string;
}

interface WaitingListManagerProps {
  berthId: string;
}

/** Shape the PUT (full-replace) endpoint accepts per entry. */
function toPutEntry(e: WaitingListEntry, position: number) {
  return {
    clientId: e.clientId,
    position,
    priority: e.priority as 'normal' | 'high',
    notifyPref: e.notifyPref as 'email' | 'in_app' | 'both',
    notes: e.notes ?? undefined,
  };
}

function SortableEntry({
  entry,
  isNext,
  canManage,
  onRemove,
}: {
  entry: WaitingListEntry;
  isNext: boolean;
  canManage: boolean;
  onRemove: (id: string) => void;
}) {
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
    id: entry.id,
    disabled: !canManage,
  });

  const style = {
    transform: CSS.Transform.toString(transform),
    transition,
    opacity: isDragging ? 0.5 : 1,
  };

  return (
    <div
      ref={setNodeRef}
      style={style}
      className="flex items-center gap-3 rounded-md border bg-card p-3"
    >
      {canManage ? (
        <button
          {...attributes}
          {...listeners}
          className="cursor-grab text-muted-foreground active:cursor-grabbing"
          aria-label="Drag to reorder"
        >
          <GripVertical className="h-4 w-4" aria-hidden />
        </button>
      ) : null}

      <span className="w-6 text-center font-mono text-sm text-muted-foreground">
        {entry.position}
      </span>

      <div className="min-w-0 flex-1">
        <p className="truncate text-sm font-medium">
          {entry.clientName ?? `Client ${entry.clientId.slice(0, 8)}`}
        </p>
        {entry.notes && <p className="truncate text-xs text-muted-foreground">{entry.notes}</p>}
      </div>

      {isNext ? (
        <Badge variant="outline" className="border-transparent bg-emerald-100 text-emerald-700">
          Next in line
        </Badge>
      ) : null}

      {entry.priority === 'high' ? <Badge variant="destructive">High</Badge> : null}

      {canManage ? (
        <button
          onClick={() => onRemove(entry.id)}
          className="text-muted-foreground transition-colors hover:text-destructive"
          aria-label="Remove from waiting list"
        >
          <Trash2 className="h-4 w-4" aria-hidden />
        </button>
      ) : null}
    </div>
  );
}

export function WaitingListManager({ berthId }: WaitingListManagerProps) {
  const queryClient = useQueryClient();
  const { can } = usePermissions();
  const canManage = can('berths', 'manage_waiting_list');
  const sensors = useSensors(useSensor(PointerSensor));

  const [showAddForm, setShowAddForm] = useState(false);
  const [newClientId, setNewClientId] = useState<string | null>(null);
  const [newPriority, setNewPriority] = useState<'normal' | 'high'>('normal');
  const [newNotes, setNewNotes] = useState('');

  const { data, isLoading } = useQuery<{ data: WaitingListEntry[] }>({
    queryKey: ['berth-waiting-list', berthId],
    queryFn: () => apiFetch(`/api/v1/berths/${berthId}/waiting-list`),
  });

  useRealtimeInvalidation({
    'berth:waitingListChanged': [['berth-waiting-list', berthId]],
  });

  const entries = data?.data ?? [];

  function resetForm() {
    setShowAddForm(false);
    setNewClientId(null);
    setNewPriority('normal');
    setNewNotes('');
  }

  const reorderMutation = useMutation({
    mutationFn: (body: { entryId: string; newPosition: number }) =>
      apiFetch(`/api/v1/berths/${berthId}/waiting-list`, { method: 'PATCH', body }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['berth-waiting-list', berthId] });
    },
    onError: (err) => toastError(err),
  });

  const replaceMutation = useMutation({
    mutationFn: (entries: ReturnType<typeof toPutEntry>[]) =>
      apiFetch(`/api/v1/berths/${berthId}/waiting-list`, {
        method: 'PUT',
        body: { entries },
      }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['berth-waiting-list', berthId] });
      resetForm();
    },
    onError: (err) => toastError(err),
  });

  function handleDragEnd(event: DragEndEvent) {
    const { active, over } = event;
    if (!over || active.id === over.id) return;
    const overEntry = entries.find((e) => e.id === over.id);
    if (!overEntry) return;
    reorderMutation.mutate({ entryId: active.id as string, newPosition: overEntry.position });
  }

  function handleAdd() {
    if (!newClientId) return;
    if (entries.some((e) => e.clientId === newClientId)) {
      toast.error('That client is already on this waiting list.');
      return;
    }
    const next = [
      ...entries.map((e, i) => toPutEntry(e, i + 1)),
      {
        clientId: newClientId,
        position: entries.length + 1,
        priority: newPriority,
        notifyPref: 'email' as const,
        notes: newNotes.trim() || undefined,
      },
    ];
    replaceMutation.mutate(next);
  }

  function handleRemove(entryId: string) {
    const remaining = entries.filter((e) => e.id !== entryId).map((e, i) => toPutEntry(e, i + 1));
    replaceMutation.mutate(remaining);
  }

  return (
    <div className="space-y-4">
      <div className="flex items-center justify-between">
        <div>
          <h3 className="text-lg font-semibold">Waiting list</h3>
          <p className="text-xs text-muted-foreground">
            When this berth becomes available, the person at the top is flagged to the team.
          </p>
        </div>
        {canManage ? (
          <Button size="sm" variant="outline" onClick={() => setShowAddForm((v) => !v)}>
            <Plus className="me-1.5 h-4 w-4" aria-hidden />
            Add
          </Button>
        ) : null}
      </div>

      {showAddForm && canManage && (
        <div className="space-y-3 rounded-md border bg-muted/30 p-3">
          <ClientPicker
            value={newClientId}
            onChange={setNewClientId}
            placeholder="Select a client to add…"
          />
          <Select value={newPriority} onValueChange={(v) => setNewPriority(v as 'normal' | 'high')}>
            <SelectTrigger>
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="normal">Normal priority</SelectItem>
              <SelectItem value="high">High priority</SelectItem>
            </SelectContent>
          </Select>
          <Input
            placeholder="Notes (optional)"
            value={newNotes}
            onChange={(e) => setNewNotes(e.target.value)}
          />
          <div className="flex gap-2">
            <Button
              size="sm"
              onClick={handleAdd}
              disabled={!newClientId || replaceMutation.isPending}
            >
              {replaceMutation.isPending && (
                <Loader2 className="me-1.5 h-4 w-4 animate-spin" aria-hidden />
              )}
              Add to list
            </Button>
            <Button size="sm" variant="ghost" onClick={resetForm}>
              Cancel
            </Button>
          </div>
        </div>
      )}

      {isLoading ? (
        <div className="h-24 animate-pulse rounded bg-muted" />
      ) : entries.length === 0 ? (
        <EmptyState
          icon={Users}
          title="No one waiting"
          description="Add clients who want this berth so the team can follow up when it frees up."
        />
      ) : (
        <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
          <SortableContext items={entries.map((e) => e.id)} strategy={verticalListSortingStrategy}>
            <div className="space-y-2">
              {entries.map((entry, i) => (
                <SortableEntry
                  key={entry.id}
                  entry={entry}
                  isNext={i === 0}
                  canManage={canManage}
                  onRemove={handleRemove}
                />
              ))}
            </div>
          </SortableContext>
        </DndContext>
      )}
    </div>
  );
}
