import { useState, useMemo, useRef, useEffect } from 'react';
import { useMediaQuery } from '@/hooks/useMediaQuery';
import { Plus, Users, Star, Cake, Phone, Mail, MapPin, Tag, Building2, Briefcase, AlignLeft, Ghost, ChevronDown, Unlink, Link2, User2 } from 'lucide-react';
import type { LucideIcon } from 'lucide-react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { format, parseISO, differenceInYears } from 'date-fns';
import { toast } from 'sonner';
import api, { getErrorMessage } from '@/lib/api';
import type { Person } from '@/types';
import { Button } from '@/components/ui/button';
import { EmptyState } from '@/components/ui/empty-state';
import {
  EntityTable,
  EntityDetailPanel,
  CategoryFilterBar,
} from '@/components/shared';
import type { ColumnDef, PanelField } from '@/components/shared';
import {
  getInitials,
  getAvatarColor,
  getNextBirthday,
  getDaysUntilBirthday,
} from '@/components/shared/utils';
import { useTableVisibility } from '@/hooks/useTableVisibility';
import { useCategoryOrder } from '@/hooks/useCategoryOrder';
import PersonForm from './PersonForm';
import ConnectionSearch from '@/components/connections/ConnectionSearch';
import ConnectionRequestCard from '@/components/connections/ConnectionRequestCard';
import { useConnections } from '@/hooks/useConnections';

// ---------------------------------------------------------------------------
// StatCounter — inline helper
// ---------------------------------------------------------------------------
function StatCounter({
  icon: Icon,
  iconBg,
  iconColor,
  label,
  value,
}: {
  icon: LucideIcon;
  iconBg: string;
  iconColor: string;
  label: string;
  value: number;
}) {
  return (
    <div className="flex items-center gap-2.5">
      <div className={`p-1.5 rounded-md ${iconBg}`}>
        <Icon className={`h-4 w-4 ${iconColor}`} />
      </div>
      <div>
        <p className="text-[10px] tracking-wider uppercase text-muted-foreground">{label}</p>
        <p className="font-heading text-xl font-bold tabular-nums">{value}</p>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
function getPersonInitialsName(p: Person): string {
  const firstName = p.is_umbral_contact && p.shared_fields?.first_name
    ? String(p.shared_fields.first_name) : p.first_name;
  const lastName = p.is_umbral_contact && p.shared_fields?.last_name
    ? String(p.shared_fields.last_name) : p.last_name;
  const parts = [firstName, lastName].filter(Boolean);
  return parts.length > 0 ? parts.join(' ') : p.name;
}

function sortPeople(people: Person[], key: string, dir: 'asc' | 'desc'): Person[] {
  return [...people].sort((a, b) => {
    let cmp = 0;
    if (key === 'birthday') {
      const aD = a.birthday ? getDaysUntilBirthday(a.birthday) : Infinity;
      const bD = b.birthday ? getDaysUntilBirthday(b.birthday) : Infinity;
      cmp = aD - bD;
    } else {
      const aVal = a[key as keyof Person];
      const bVal = b[key as keyof Person];
      const aStr = aVal != null ? String(aVal) : '';
      const bStr = bVal != null ? String(bVal) : '';
      cmp = aStr.localeCompare(bStr);
    }
    return dir === 'asc' ? cmp : -cmp;
  });
}

// ---------------------------------------------------------------------------
// Column definitions
// ---------------------------------------------------------------------------
/** Get a field value, preferring shared_fields for umbral contacts. */
function sf(p: Person, key: string): string | null | undefined {
  if (p.is_umbral_contact && p.shared_fields && key in p.shared_fields) {
    return p.shared_fields[key] as string | null;
  }
  return p[key as keyof Person] as string | null | undefined;
}

const columns: ColumnDef<Person>[] = [
  {
    key: 'name',
    label: 'Name',
    sortable: true,
    visibilityLevel: 'essential',
    render: (p) => {
      const firstName = sf(p, 'first_name');
      const lastName = sf(p, 'last_name');
      const liveName = [firstName, lastName].filter(Boolean).join(' ') || p.nickname || p.name;
      const initialsName = liveName || getPersonInitialsName(p);
      return (
        <div className="flex items-center gap-2.5">
          <div
            className={`h-7 w-7 rounded-full flex items-center justify-center text-xs font-bold shrink-0 ${getAvatarColor(initialsName)}`}
          >
            {getInitials(initialsName)}
          </div>
          <span className="font-medium truncate">{liveName}</span>
          {p.is_umbral_contact && (
            <Ghost className="h-3.5 w-3.5 text-violet-400 shrink-0" aria-label="Umbral contact" />
          )}
        </div>
      );
    },
  },
  {
    key: 'phone',
    label: 'Number',
    sortable: false,
    visibilityLevel: 'essential',
    render: (p) => {
      const mobile = sf(p, 'mobile');
      const phone = sf(p, 'phone');
      return <span className="text-muted-foreground truncate">{mobile || phone || '—'}</span>;
    },
  },
  {
    key: 'email',
    label: 'Email',
    sortable: true,
    visibilityLevel: 'essential',
    render: (p) => {
      const email = sf(p, 'email');
      return <span className="text-muted-foreground truncate">{email || '—'}</span>;
    },
  },
  {
    key: 'job_title',
    label: 'Role',
    sortable: true,
    visibilityLevel: 'filtered',
    render: (p) => {
      const jobTitle = sf(p, 'job_title');
      const company = sf(p, 'company');
      const parts = [jobTitle, company].filter(Boolean);
      return <span className="text-muted-foreground truncate">{parts.join(', ') || '—'}</span>;
    },
  },
  {
    key: 'birthday',
    label: 'Birthday',
    sortable: true,
    visibilityLevel: 'filtered',
    render: (p) => {
      const birthday = sf(p, 'birthday');
      return birthday ? (
        <span className="text-muted-foreground">{format(parseISO(birthday), 'MMM d')}</span>
      ) : (
        <span className="text-muted-foreground">—</span>
      );
    },
  },
  {
    key: 'category',
    label: 'Category',
    sortable: true,
    visibilityLevel: 'all',
    render: (p) =>
      p.category ? (
        <span
          className="px-2 py-0.5 text-xs rounded"
          style={{
            backgroundColor: 'hsl(var(--accent-color) / 0.1)',
            color: 'hsl(var(--accent-color))',
          }}
        >
          {p.category}
        </span>
      ) : (
        <span className="text-muted-foreground">—</span>
      ),
  },
];

// ---------------------------------------------------------------------------
// Panel field config
// ---------------------------------------------------------------------------
const panelFields: PanelField[] = [
  { label: 'Preferred Name', key: 'preferred_name', icon: User2 },
  { label: 'Mobile', key: 'mobile', copyable: true, icon: Phone },
  { label: 'Phone', key: 'phone', copyable: true, icon: Phone },
  { label: 'Email', key: 'email', copyable: true, icon: Mail },
  { label: 'Birthday', key: 'birthday_display', icon: Cake },
  { label: 'Category', key: 'category', icon: Tag },
  { label: 'Company', key: 'company', icon: Building2 },
  { label: 'Job Title', key: 'job_title', icon: Briefcase },
  { label: 'Address', key: 'address', copyable: true, icon: MapPin, fullWidth: true },
  { label: 'Notes', key: 'notes', multiline: true, icon: AlignLeft, fullWidth: true },
];

// ---------------------------------------------------------------------------
// PeoplePage
// ---------------------------------------------------------------------------
export default function PeoplePage() {
  const queryClient = useQueryClient();
  const tableContainerRef = useRef<HTMLDivElement>(null);
  const isDesktop = useMediaQuery('(min-width: 1024px)');

  const [selectedPersonId, setSelectedPersonId] = useState<number | null>(null);
  const [showForm, setShowForm] = useState(false);
  const [editingPerson, setEditingPerson] = useState<Person | null>(null);
  const [activeFilters, setActiveFilters] = useState<string[]>([]);
  const [showPinned, setShowPinned] = useState(true);
  const [showUmbralOnly, setShowUmbralOnly] = useState(false);
  const [search, setSearch] = useState('');
  const [sortKey, setSortKey] = useState<string>('name');
  const [sortDir, setSortDir] = useState<'asc' | 'desc'>('asc');
  const [showConnectionSearch, setShowConnectionSearch] = useState(false);
  const [linkPersonId, setLinkPersonId] = useState<number | null>(null);
  const [showAddDropdown, setShowAddDropdown] = useState(false);
  const addDropdownRef = useRef<HTMLDivElement>(null);

  const { incomingRequests, outgoingRequests } = useConnections();
  const hasRequests = incomingRequests.length > 0 || outgoingRequests.length > 0;

  const { data: people = [], isLoading } = useQuery({
    queryKey: ['people'],
    queryFn: async () => {
      const { data } = await api.get<Person[]>('/people');
      return data;
    },
  });

  const panelOpen = selectedPersonId !== null;
  const visibilityMode = useTableVisibility(tableContainerRef, panelOpen);

  const allCategories = useMemo(() => {
    const cats = new Set<string>();
    people.forEach((p) => { if (p.category) cats.add(p.category); });
    return Array.from(cats).sort();
  }, [people]);

  const { orderedCategories, reorder: reorderCategories } = useCategoryOrder('people', allCategories);

  // Favourites (pinned section) — sorted
  const favourites = useMemo(
    () => sortPeople(people.filter((p) => p.is_favourite), sortKey, sortDir),
    [people, sortKey, sortDir]
  );

  // Filtered non-favourites
  const filteredPeople = useMemo(() => {
    let list = showPinned
      ? people.filter((p) => !p.is_favourite)
      : people;

    if (showUmbralOnly) {
      list = list.filter((p) => p.is_umbral_contact);
    }

    if (activeFilters.length > 0) {
      list = list.filter((p) => p.category && activeFilters.includes(p.category));
    }

    if (search) {
      const q = search.toLowerCase();
      list = list.filter(
        (p) =>
          p.name.toLowerCase().includes(q) ||
          p.first_name?.toLowerCase().includes(q) ||
          p.last_name?.toLowerCase().includes(q) ||
          p.nickname?.toLowerCase().includes(q) ||
          p.email?.toLowerCase().includes(q) ||
          p.mobile?.toLowerCase().includes(q) ||
          p.phone?.toLowerCase().includes(q) ||
          p.company?.toLowerCase().includes(q) ||
          p.category?.toLowerCase().includes(q)
      );
    }

    return sortPeople(list, sortKey, sortDir);
  }, [people, showPinned, showUmbralOnly, activeFilters, search, sortKey, sortDir]);

  // Build row groups for the table — ordered by custom category order
  const groups = useMemo(() => {
    if (activeFilters.length <= 1) {
      const label = activeFilters.length === 1 ? activeFilters[0] : 'All';
      return [{ label, rows: filteredPeople }];
    }
    // Use orderedCategories to control section order, filtered to active only
    return orderedCategories
      .filter((cat) => activeFilters.includes(cat))
      .map((cat) => ({
        label: cat,
        rows: filteredPeople.filter((p) => p.category === cat),
      }))
      .filter((g) => g.rows.length > 0);
  }, [activeFilters, filteredPeople, orderedCategories]);

  // Stats
  const totalCount = people.length;
  const favouriteCount = people.filter((p) => p.is_favourite).length;
  const upcomingBirthdays = useMemo(
    () =>
      people
        .filter((p) => p.birthday && getDaysUntilBirthday(p.birthday) <= 30)
        .sort((a, b) => getDaysUntilBirthday(a.birthday!) - getDaysUntilBirthday(b.birthday!)),
    [people]
  );
  const upcomingBdayCount = upcomingBirthdays.length;

  const selectedPerson = useMemo(
    () => people.find((p) => p.id === selectedPersonId) ?? null,
    [selectedPersonId, people]
  );

  // Sort handler
  const handleSort = (key: string) => {
    if (sortKey === key) {
      setSortDir((d) => (d === 'asc' ? 'desc' : 'asc'));
    } else {
      setSortKey(key);
      setSortDir('asc');
    }
  };

  // Filter handlers
  const toggleAll = () => setActiveFilters([]);
  const togglePinned = () => setShowPinned((p) => !p);
  const toggleCategory = (cat: string) => {
    setActiveFilters((prev) =>
      prev.includes(cat) ? prev.filter((c) => c !== cat) : [...prev, cat]
    );
  };
  const selectAllCategories = () => {
    const allSelected = orderedCategories.every((c) => activeFilters.includes(c));
    setActiveFilters(allSelected ? [] : [...orderedCategories]);
  };

  // Delete mutation
  const deleteMutation = useMutation({
    mutationFn: async () => {
      await api.delete(`/people/${selectedPersonId}`);
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['people'] });
      queryClient.invalidateQueries({ queryKey: ['connections'] });
      queryClient.invalidateQueries({ queryKey: ['dashboard'] });
      queryClient.invalidateQueries({ queryKey: ['upcoming'] });
      toast.success('Person deleted');
      setSelectedPersonId(null);
    },
    onError: (error) => {
      toast.error(getErrorMessage(error, 'Failed to delete person'));
    },
  });

  // Unlink umbral contact mutation
  const unlinkMutation = useMutation({
    mutationFn: async (personId: number) => {
      const { data } = await api.put(`/people/${personId}/unlink`);
      return data;
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['people'] });
      queryClient.invalidateQueries({ queryKey: ['connections'] });
      toast.success('Contact unlinked — converted to standard contact');
    },
    onError: (error) => {
      toast.error(getErrorMessage(error, 'Failed to unlink contact'));
    },
  });

  // Toggle favourite mutation
  const toggleFavouriteMutation = useMutation({
    mutationFn: async (person: Person) => {
      await api.put(`/people/${person.id}`, { is_favourite: !person.is_favourite });
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['people'] });
    },
    onError: (error) => {
      toast.error(getErrorMessage(error, 'Failed to update favourite'));
    },
  });

  // Escape key closes detail panel
  useEffect(() => {
    if (!panelOpen) return;
    const handler = (e: KeyboardEvent) => {
      if (e.key === 'Escape') setSelectedPersonId(null);
    };
    document.addEventListener('keydown', handler);
    return () => document.removeEventListener('keydown', handler);
  }, [panelOpen]);

  // Close add dropdown on outside click
  useEffect(() => {
    if (!showAddDropdown) return;
    const handler = (e: MouseEvent) => {
      if (addDropdownRef.current && !addDropdownRef.current.contains(e.target as Node)) {
        setShowAddDropdown(false);
      }
    };
    document.addEventListener('mousedown', handler);
    return () => document.removeEventListener('mousedown', handler);
  }, [showAddDropdown]);

  const handleCloseForm = () => {
    setShowForm(false);
    setEditingPerson(null);
  };

  // Panel header renderer (shared between desktop and mobile)
  const renderPersonHeader = (p: Person) => {
    const initialsName = getPersonInitialsName(p);
    return (
      <div className="flex items-center gap-3">
        <div
          className={`h-10 w-10 rounded-full flex items-center justify-center text-sm font-bold shrink-0 ${getAvatarColor(initialsName)}`}
        >
          {getInitials(initialsName)}
        </div>
        <div className="min-w-0">
          <div className="flex items-center gap-2">
            <h3 className="font-heading text-lg font-semibold truncate">{
              p.is_umbral_contact && p.shared_fields
                ? [sf(p, 'first_name'), sf(p, 'last_name')].filter(Boolean).join(' ') || p.name
                : p.name
            }</h3>
            {p.is_umbral_contact && (
              <Ghost className="h-4 w-4 text-violet-400 shrink-0" />
            )}
          </div>
          <div className="flex items-center gap-2">
            {p.is_umbral_contact && p.shared_fields?.umbral_name ? (
              <span className="text-xs text-violet-400/80 font-normal">
                @{String(p.shared_fields.umbral_name)}
              </span>
            ) : null}
            {p.category && (
              <span className="text-xs text-muted-foreground">{p.category}</span>
            )}
          </div>
        </div>
      </div>
    );
  };

  // Shared field key mapping (panel key -> shared_fields key)
  const sharedKeyMap: Record<string, string> = {
    preferred_name: 'preferred_name',
    email: 'email',
    phone: 'phone',
    mobile: 'mobile',
    birthday_display: 'birthday',
    address: 'address',
    company: 'company',
    job_title: 'job_title',
  };

  // Build dynamic panel fields with synced labels for shared fields
  const dynamicPanelFields = useMemo((): PanelField[] => {
    if (!selectedPerson?.is_umbral_contact || !selectedPerson.shared_fields) return panelFields;
    const shared = selectedPerson.shared_fields;
    return panelFields.map((f) => {
      const sharedKey = sharedKeyMap[f.key];
      if (sharedKey && sharedKey in shared) {
        return { ...f, label: `${f.label} (synced)` };
      }
      return f;
    });
  }, [selectedPerson]);

  // Panel getValue — overlays shared fields from connected user
  const getPanelValue = (p: Person, key: string): string | undefined => {
    // Check shared fields first for umbral contacts
    if (p.is_umbral_contact && p.shared_fields) {
      const sharedKey = sharedKeyMap[key];
      if (sharedKey && sharedKey in p.shared_fields) {
        const sharedVal = p.shared_fields[sharedKey];
        if (key === 'birthday_display' && sharedVal) {
          const bd = String(sharedVal);
          try {
            const age = differenceInYears(new Date(), parseISO(bd));
            return `${format(parseISO(bd), 'MMM d, yyyy')} (${age})`;
          } catch {
            return bd;
          }
        }
        return sharedVal != null ? String(sharedVal) : undefined;
      }
    }
    if (key === 'birthday_display' && p.birthday) {
      const age = differenceInYears(new Date(), parseISO(p.birthday));
      return `${format(parseISO(p.birthday), 'MMM d, yyyy')} (${age})`;
    }
    const val = p[key as keyof Person];
    return val != null ? String(val) : undefined;
  };

  const renderPanel = () => (
    <EntityDetailPanel<Person>
      item={selectedPerson}
      fields={dynamicPanelFields}
      onEdit={() => {
        setEditingPerson(selectedPerson);
        setShowForm(true);
      }}
      onDelete={() => deleteMutation.mutate()}
      deleteLoading={deleteMutation.isPending}
      onClose={() => setSelectedPersonId(null)}
      renderHeader={renderPersonHeader}
      getUpdatedAt={(p) => p.updated_at}
      getValue={getPanelValue}
      isFavourite={selectedPerson?.is_favourite}
      onToggleFavourite={() => selectedPerson && toggleFavouriteMutation.mutate(selectedPerson)}
      favouriteLabel="favourite"
      extraActions={(p) =>
        p.is_umbral_contact ? (
          <Button
            variant="ghost"
            size="sm"
            onClick={() => unlinkMutation.mutate(p.id)}
            disabled={unlinkMutation.isPending}
            className="h-7 text-[11px] text-muted-foreground hover:text-foreground gap-1"
          >
            <Unlink className="h-3 w-3" />
            Unlink
          </Button>
        ) : (
          <Button
            variant="ghost"
            size="sm"
            onClick={() => setLinkPersonId(p.id)}
            className="h-7 text-[11px] text-muted-foreground hover:text-foreground gap-1"
          >
            <Link2 className="h-3 w-3" />
            Link
          </Button>
        )
      }
    />
  );

  return (
    <div className="flex flex-col h-full animate-fade-in">
      {/* Header */}
      <div className="border-b bg-card px-4 md:px-6 min-h-[4rem] flex items-center gap-2 md:gap-4 flex-wrap py-2 md:py-0 md:h-16 md:flex-nowrap shrink-0">
        <h1 className="font-heading text-xl md:text-2xl font-bold tracking-tight">People</h1>
        <div className="w-full md:flex-1 md:w-auto min-w-0 order-last md:order-none">
          <CategoryFilterBar
            activeFilters={activeFilters}
            pinnedLabel="Favourites"
            showPinned={showPinned}
            categories={orderedCategories}
            onToggleAll={toggleAll}
            onTogglePinned={togglePinned}
            onToggleCategory={toggleCategory}
            onSelectAllCategories={selectAllCategories}
            onReorderCategories={reorderCategories}
            searchValue={search}
            onSearchChange={setSearch}
            extraPinnedFilters={[
              {
                label: 'Umbral',
                isActive: showUmbralOnly,
                onToggle: () => setShowUmbralOnly((p) => !p),
              },
            ]}
          />
        </div>
        <div className="relative" ref={addDropdownRef}>
          <div className="flex">
            <Button
              onClick={() => setShowForm(true)}
              size="sm"
              aria-label="Add person"
              className="rounded-r-none"
            >
              <Plus className="h-4 w-4 md:mr-2" /><span className="hidden md:inline">Add Person</span>
            </Button>
            <Button
              size="sm"
              onClick={() => setShowAddDropdown((p) => !p)}
              aria-label="More add options"
              className="rounded-l-none border-l border-background/20 px-1.5"
            >
              <ChevronDown className="h-3.5 w-3.5" />
            </Button>
          </div>
          {showAddDropdown && (
            <div className="absolute right-0 top-full mt-1 w-44 rounded-md border border-border bg-card shadow-lg z-50 py-1">
              <button
                className="w-full text-left px-3 py-1.5 text-sm hover:bg-card-elevated transition-colors"
                onClick={() => { setShowAddDropdown(false); setShowForm(true); }}
              >
                Standard Contact
              </button>
              <button
                className="w-full text-left px-3 py-1.5 text-sm hover:bg-card-elevated transition-colors flex items-center gap-2"
                onClick={() => { setShowAddDropdown(false); setShowConnectionSearch(true); }}
              >
                <Ghost className="h-3.5 w-3.5 text-violet-400" />
                Umbra Contact
              </button>
            </div>
          )}
        </div>
      </div>

      <div className="flex-1 overflow-hidden flex flex-col">
        {/* Stat bar */}
        {!isLoading && people.length > 0 && (
          <div className="px-4 md:px-6 pt-4 pb-2 flex items-start gap-6 shrink-0">
            <div className="flex gap-6 shrink-0">
              <StatCounter
                icon={Users}
                iconBg="bg-blue-500/10"
                iconColor="text-blue-400"
                label="Total"
                value={totalCount}
              />
              <StatCounter
                icon={Star}
                iconBg="bg-yellow-500/10"
                iconColor="text-yellow-400"
                label="Favourites"
                value={favouriteCount}
              />
              <StatCounter
                icon={Cake}
                iconBg="bg-pink-500/10"
                iconColor="text-pink-400"
                label="Upcoming Bdays"
                value={upcomingBdayCount}
              />
            </div>
            {/* Birthday list */}
            <div className="flex-1 flex flex-wrap gap-x-4 gap-y-1 overflow-hidden">
              {upcomingBirthdays.slice(0, 5).map((p) => (
                <span key={p.id} className="text-[11px] text-muted-foreground whitespace-nowrap">
                  {p.name} — {format(getNextBirthday(p.birthday!), 'MMM d')} (
                  {getDaysUntilBirthday(p.birthday!)}d)
                </span>
              ))}
              {upcomingBirthdays.length > 5 && (
                <span className="text-[11px] text-muted-foreground">
                  +{upcomingBirthdays.length - 5} more
                </span>
              )}
            </div>
          </div>
        )}

        {/* Pending requests */}
        {hasRequests && (
          <div className="px-4 md:px-6 pb-3">
            <div className="flex items-center gap-2 mb-2">
              <span className="text-xs text-muted-foreground uppercase tracking-wider font-medium">
                Pending Requests
              </span>
              <span className="text-[10px] tabular-nums bg-accent/15 text-accent px-1.5 py-0.5 rounded-full font-medium">
                {incomingRequests.length + outgoingRequests.length}
              </span>
            </div>
            <div className="space-y-2">
              {incomingRequests.length > 0 && outgoingRequests.length > 0 && (
                <p className="text-[11px] text-muted-foreground font-medium uppercase tracking-wider">Incoming</p>
              )}
              {incomingRequests.slice(0, 5).map((req) => (
                <ConnectionRequestCard key={req.id} request={req} direction="incoming" />
              ))}
              {incomingRequests.length > 5 && (
                <p className="text-xs text-muted-foreground">+{incomingRequests.length - 5} more</p>
              )}
              {incomingRequests.length > 0 && outgoingRequests.length > 0 && (
                <p className="text-[11px] text-muted-foreground font-medium uppercase tracking-wider mt-3">Outgoing</p>
              )}
              {outgoingRequests.slice(0, 5).map((req) => (
                <ConnectionRequestCard key={req.id} request={req} direction="outgoing" />
              ))}
              {outgoingRequests.length > 5 && (
                <p className="text-xs text-muted-foreground">+{outgoingRequests.length - 5} more</p>
              )}
            </div>
          </div>
        )}

        {/* Main content: table + panel */}
        <div className="flex-1 overflow-hidden flex">
          {/* Table */}
          <div
            ref={tableContainerRef}
            className={`overflow-y-auto transition-all duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] ${
              panelOpen ? 'w-full lg:w-[55%]' : 'w-full'
            }`}
          >
            <div className="px-4 md:px-6 pb-6">
              {isLoading ? (
                <EntityTable<Person>
                  columns={columns}
                  groups={[]}
                  pinnedRows={[]}
                  pinnedLabel="Favourites"
                  showPinned={false}
                  selectedId={null}
                  onRowClick={() => {}}
                  sortKey={sortKey}
                  sortDir={sortDir}
                  onSort={handleSort}
                  visibilityMode={visibilityMode}
                  loading={true}
                />
              ) : filteredPeople.length === 0 && favourites.length === 0 ? (
                <EmptyState
                  icon={Users}
                  title="No contacts yet"
                  description="Add people to your directory to keep track of contacts and relationships."
                  actionLabel="Add Person"
                  onAction={() => setShowForm(true)}
                />
              ) : (
                <EntityTable<Person>
                  columns={columns}
                  groups={groups}
                  pinnedRows={showPinned ? favourites : []}
                  pinnedLabel="Favourites"
                  showPinned={showPinned}
                  selectedId={selectedPersonId}
                  onRowClick={(id) =>
                    setSelectedPersonId((prev) => (prev === id ? null : id))
                  }
                  sortKey={sortKey}
                  sortDir={sortDir}
                  onSort={handleSort}
                  visibilityMode={visibilityMode}
                  mobileCardRender={(person) => (
                    <div className={`rounded-lg border p-3 transition-colors ${selectedPersonId === person.id ? 'border-accent/40 bg-accent/5' : 'border-border bg-card hover:bg-card-elevated'}`}>
                      <div className="flex items-center justify-between mb-1">
                        <span className="font-medium text-sm truncate flex-1">{person.name}</span>
                        {person.category && <span className="text-xs text-muted-foreground">{person.category}</span>}
                      </div>
                      <div className="flex items-center gap-2 text-xs text-muted-foreground">
                        {person.email && <span className="truncate">{person.email}</span>}
                        {person.phone && <span>{person.phone}</span>}
                      </div>
                    </div>
                  )}
                />
              )}
            </div>
          </div>

          {/* Detail panel (desktop) */}
          {panelOpen && isDesktop && (
            <div
              className="overflow-hidden transition-all duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] w-[45%]"
            >
              {renderPanel()}
            </div>
          )}
        </div>
      </div>

      {/* Mobile detail panel overlay */}
      {panelOpen && selectedPerson && !isDesktop && (
        <div
          className="fixed inset-0 z-50 bg-background/80 backdrop-blur-sm"
          onClick={() => setSelectedPersonId(null)}
        >
          <div
            className="fixed inset-y-0 right-0 w-full sm:w-[400px] bg-card border-l border-border shadow-lg"
            onClick={(e) => e.stopPropagation()}
          >
            {renderPanel()}
          </div>
        </div>
      )}

      {showForm && (
        <PersonForm
          person={editingPerson}
          categories={allCategories}
          onClose={handleCloseForm}
        />
      )}

      <ConnectionSearch
        open={showConnectionSearch}
        onOpenChange={setShowConnectionSearch}
      />

      <ConnectionSearch
        open={linkPersonId !== null}
        onOpenChange={(open) => { if (!open) setLinkPersonId(null); }}
        personId={linkPersonId ?? undefined}
      />
    </div>
  );
}
