'use client';

import { getBlobErrorMessage, jsonErrorInBlobResponse } from '@/utils/helper/blobError';
import {
  useEffect,
  useState,
  useCallback,
  useMemo,
  useRef,
  Suspense,
} from 'react';
import { useRouter, useSearchParams } from 'next/navigation';
import {
  ColumnDef,
  PaginationState,
  SortingState,
  getCoreRowModel,
  getSortedRowModel,
  useReactTable,
} from '@tanstack/react-table';
import {
  Search,
  Phone,
  Mail,
  RefreshCw,
  Play,
  Loader2,
  User,
  Eye,
  Plus,
  AlertTriangle,
  Copy,
  Check,
  Settings2,
  Filter,
  Download,
  X,
} from 'lucide-react';
import axios from '@/network/axios';
import {
  Card,
  CardFooter,
  CardHeader,
  CardHeading,
  CardTable,
  CardTitle,
  CardToolbar,
  CardContent,
} from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Badge } from '@/components/ui/badge';
import { ScrollArea, ScrollBar } from '@/components/ui/scroll-area';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from '@/components/ui/dialog';
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from '@/components/ui/popover';
import { Container } from '@/components/common/container';
import {
  Toolbar,
  ToolbarHeading,
} from '@/app/components/layouts/demo1/components/toolbar';
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
import { DataGrid } from '@/components/ui/data-grid';
import { DataGridColumnHeader } from '@/components/ui/data-grid-column-header';
import { DataGridColumnVisibility } from '@/components/ui/data-grid-column-visibility';
import { DataGridPagination } from '@/components/ui/data-grid-pagination';
import { DataGridTable } from '@/components/ui/data-grid-table';

type Platform =
  | 'snapchat'
  | 'tiktok'
  | 'instagram'
  | 'youtube'
  | 'twitter'
  | 'twitch';

const PLATFORMS: { value: Platform; label: string }[] = [
  { value: 'snapchat', label: 'Snapchat' },
  { value: 'tiktok', label: 'TikTok' },
  { value: 'instagram', label: 'Instagram' },
  { value: 'youtube', label: 'YouTube' },
  { value: 'twitter', label: 'Twitter / X' },
  { value: 'twitch', label: 'Twitch' },
];

interface RawSnapRow {
  id: number;
  profile_id: string;
  snap_user_name: string;
  display_name: string;
  email: string | null;
  phone: string | null;
  raw_bio: string | null;
  created_at: string;
  updated_at: string;
}

interface RawSocialRow {
  id: number;
  username: string;
  social_id: string | null;
  title: string | null;
  email: string | null;
  phone: string | null;
  raw_bio: string | null;
  created_at: string;
  updated_at: string;
}

type AnyRow = RawSnapRow | RawSocialRow;

interface NormalizedRow {
  id: number;
  key: string;
  handle: string;
  title: string;
  email: string | null;
  phone: string | null;
  raw_bio: string | null;
  social_id?: string | null;
  profile_id?: string;
  created_at: string;
  updated_at: string;
}

interface PaginationMeta {
  current_page: number;
  last_page: number;
  per_page: number;
  total: number;
}

function normalizeRow(platform: Platform, r: AnyRow): NormalizedRow {
  if (platform === 'snapchat') {
    const s = r as RawSnapRow;
    return {
      id: s.id,
      key: s.profile_id,
      handle: s.snap_user_name || '',
      title: s.display_name || '',
      email: s.email,
      phone: s.phone,
      raw_bio: s.raw_bio,
      profile_id: s.profile_id,
      created_at: s.created_at,
      updated_at: s.updated_at,
    };
  }
  const s = r as RawSocialRow;
  return {
    id: s.id,
    key: s.username || s.social_id || String(s.id),
    handle: s.username || '',
    title: s.title || '',
    email: s.email,
    phone: s.phone,
    raw_bio: s.raw_bio,
    social_id: s.social_id,
    created_at: s.created_at,
    updated_at: s.updated_at,
  };
}

function splitMulti(v: string | null | undefined): string[] {
  if (!v) return [];
  return v
    .split(',')
    .map((x) => x.trim())
    .filter(Boolean);
}

function CopyButton({ value }: { value: string }) {
  const [copied, setCopied] = useState(false);
  return (
    <button
      type="button"
      className="inline-flex items-center text-muted-foreground hover:text-foreground transition-colors"
      onClick={async (e) => {
        e.stopPropagation();
        try {
          await navigator.clipboard.writeText(value);
          setCopied(true);
          setTimeout(() => setCopied(false), 1200);
        } catch {
          /* ignore */
        }
      }}
      title="Copy"
    >
      {copied ? (
        <Check className="h-3 w-3 text-emerald-500" />
      ) : (
        <Copy className="h-3 w-3" />
      )}
    </button>
  );
}

function RowDetail({
  record,
  platform,
}: {
  record: NormalizedRow;
  platform: Platform;
}) {
  const emails = splitMulti(record.email);
  const phones = splitMulti(record.phone);
  return (
    <div className="space-y-3">
      <div>
        <p className="text-xs font-medium text-muted-foreground mb-1">
          {platform === 'snapchat' ? 'Display Name' : 'Title'}
        </p>
        <p className="text-sm">{record.title || '-'}</p>
      </div>
      {record.raw_bio ? (
        <div>
          <p className="text-xs font-medium text-muted-foreground mb-1">Bio</p>
          <p className="text-sm whitespace-pre-wrap bg-muted/50 rounded-lg p-3">
            {record.raw_bio}
          </p>
        </div>
      ) : null}
      {emails.length ? (
        <div>
          <p className="text-xs font-medium text-muted-foreground mb-1">
            Email{emails.length > 1 ? 's' : ''}
          </p>
          <div className="space-y-1">
            {emails.map((e) => (
              <div
                key={e}
                className="text-sm text-emerald-700 dark:text-emerald-400 flex items-center gap-2"
              >
                {e}
                <CopyButton value={e} />
              </div>
            ))}
          </div>
        </div>
      ) : null}
      {phones.length ? (
        <div>
          <p className="text-xs font-medium text-muted-foreground mb-1">
            Phone{phones.length > 1 ? 's' : ''}
          </p>
          <div className="space-y-1">
            {phones.map((p) => (
              <div
                key={p}
                className="text-sm text-violet-700 dark:text-violet-400 font-mono flex items-center gap-2"
              >
                {p}
                <CopyButton value={p} />
              </div>
            ))}
          </div>
        </div>
      ) : null}
      <div>
        <p className="text-xs font-medium text-muted-foreground mb-1">
          {platform === 'snapchat' ? 'Profile ID' : 'Lookup key'}
        </p>
        <p className="text-sm font-mono break-all">{record.key}</p>
      </div>
      {record.social_id ? (
        <div>
          <p className="text-xs font-medium text-muted-foreground mb-1">
            Social ID
          </p>
          <p className="text-sm font-mono break-all">{record.social_id}</p>
        </div>
      ) : null}
      <div className="grid grid-cols-2 gap-3 text-xs text-muted-foreground">
        <div>
          <span className="block">Created</span>
          <span className="text-foreground">
            {record.created_at
              ? new Date(record.created_at).toLocaleString()
              : '-'}
          </span>
        </div>
        <div>
          <span className="block">Updated</span>
          <span className="text-foreground">
            {record.updated_at
              ? new Date(record.updated_at).toLocaleString()
              : '-'}
          </span>
        </div>
      </div>
    </div>
  );
}

function BioPhonesPageInner() {
  const router = useRouter();
  const sp = useSearchParams();

  const platformParam = (sp?.get('platform') ?? 'snapchat') as Platform;
  const platform: Platform = PLATFORMS.some((p) => p.value === platformParam)
    ? platformParam
    : 'snapchat';

  // Filter state (URL-persisted)
  const initialSearch = sp?.get('search') ?? '';
  const initialHasEmail = sp?.get('has_email') === '1';
  const initialHasPhone = sp?.get('has_phone') === '1';
  const initialPerPage = Number(sp?.get('per_page') ?? '25');
  const initialPage = Number(sp?.get('page') ?? '1');

  const [searchInput, setSearchInput] = useState(initialSearch);
  const [searchQuery, setSearchQuery] = useState(initialSearch);
  const [hasEmail, setHasEmail] = useState(initialHasEmail);
  const [hasPhone, setHasPhone] = useState(initialHasPhone);

  const [pagination, setPagination] = useState<PaginationState>({
    pageIndex: Math.max(0, initialPage - 1),
    pageSize: [25, 50, 100, 200].includes(initialPerPage)
      ? initialPerPage
      : 25,
  });
  const [sorting, setSorting] = useState<SortingState>([]);

  const [records, setRecords] = useState<NormalizedRow[]>([]);
  const [loading, setLoading] = useState(true);
  const [meta, setMeta] = useState<PaginationMeta>({
    current_page: 1,
    last_page: 1,
    per_page: 25,
    total: 0,
  });

  // Bulk + single extraction state
  const [extractingAll, setExtractingAll] = useState(false);
  const [confirmExtractAll, setConfirmExtractAll] = useState(false);
  const [extractAllResult, setExtractAllResult] = useState<string | null>(null);
  const [extractSingleOpen, setExtractSingleOpen] = useState(false);
  const [singleKey, setSingleKey] = useState('');
  const [singleSubmitting, setSingleSubmitting] = useState(false);
  const [singleResult, setSingleResult] = useState<{
    found: boolean;
    message: string;
    row?: NormalizedRow;
  } | null>(null);

  const [detailRow, setDetailRow] = useState<NormalizedRow | null>(null);
  const [exporting, setExporting] = useState(false);
  const [exportError, setExportError] = useState<string | null>(null);

  // Sync URL with state
  useEffect(() => {
    const p = new URLSearchParams();
    p.set('platform', platform);
    if (searchQuery) p.set('search', searchQuery);
    if (hasEmail) p.set('has_email', '1');
    if (hasPhone) p.set('has_phone', '1');
    if (pagination.pageSize !== 25)
      p.set('per_page', String(pagination.pageSize));
    if (pagination.pageIndex !== 0)
      p.set('page', String(pagination.pageIndex + 1));
    router.replace(`?${p.toString()}`, { scroll: false });
  }, [
    router,
    platform,
    searchQuery,
    hasEmail,
    hasPhone,
    pagination.pageIndex,
    pagination.pageSize,
  ]);

  // Reset filters when platform changes (skip first render so URL params are honored)
  const didMountPlatform = useRef(false);
  useEffect(() => {
    if (!didMountPlatform.current) {
      didMountPlatform.current = true;
      return;
    }
    setSearchInput('');
    setSearchQuery('');
    setHasEmail(false);
    setHasPhone(false);
    setPagination((p) => ({ ...p, pageIndex: 0 }));
  }, [platform]);

  // Reset to page 0 when filters change (skip first render)
  const didMountFilters = useRef(false);
  useEffect(() => {
    if (!didMountFilters.current) {
      didMountFilters.current = true;
      return;
    }
    setPagination((p) => ({ ...p, pageIndex: 0 }));
  }, [searchQuery, hasEmail, hasPhone]);

  const fetchData = useCallback(async () => {
    setLoading(true);
    try {
      const params: Record<string, string | number> = {
        platform,
        page: pagination.pageIndex + 1,
        per_page: pagination.pageSize,
      };
      if (searchQuery) params.search = searchQuery;
      if (hasEmail) params.has_email = 1;
      if (hasPhone) params.has_phone = 1;

      const response = await axios.get('/bio-phones', { params });
      const inner = response.data?.data;

      let dataArray: AnyRow[] = [];
      let nextMeta: PaginationMeta = {
        current_page: pagination.pageIndex + 1,
        last_page: 1,
        per_page: pagination.pageSize,
        total: 0,
      };
      if (inner && typeof inner === 'object' && !Array.isArray(inner)) {
        dataArray = inner.data || inner.rows || [];
        nextMeta = inner.pagination || inner.meta || nextMeta;
      } else if (Array.isArray(inner)) {
        dataArray = inner;
      }

      setRecords(dataArray.map((r) => normalizeRow(platform, r)));
      setMeta(nextMeta);
    } catch (err) {
      console.error('Error fetching bio phones:', err);
      setRecords([]);
    } finally {
      setLoading(false);
    }
  }, [
    platform,
    pagination.pageIndex,
    pagination.pageSize,
    searchQuery,
    hasEmail,
    hasPhone,
  ]);

  useEffect(() => {
    fetchData();
  }, [fetchData]);

  const updatePlatform = (next: Platform) => {
    const p = new URLSearchParams();
    p.set('platform', next);
    router.push(`?${p.toString()}`);
  };

  const handleExtractAll = async () => {
    setConfirmExtractAll(false);
    setExtractingAll(true);
    setExtractAllResult(null);
    try {
      const response = await axios.post('/bio-phones/extract-all', null, {
        params: { platform },
      });
      const summary = response.data?.data;
      if (summary?.total_profiles !== undefined) {
        setExtractAllResult(
          `Scanned ${summary.total_profiles} ${platform} profiles. Found contact info on ${summary.extracted}.`,
        );
      } else {
        setExtractAllResult(
          response.data?.message || 'Extraction complete.',
        );
      }
      await fetchData();
    } catch (err) {
      const e = err as {
        response?: { status?: number; data?: { message?: string } };
        message?: string;
      };
      const status = e?.response?.status;
      const beMsg = e?.response?.data?.message;
      console.error('Error extracting bios:', err);
      setExtractAllResult(
        `Failed to scan ${platformLabel} bios${
          status ? ` (HTTP ${status})` : ''
        }: ${beMsg || e?.message || 'Unknown error'}`,
      );
    } finally {
      setExtractingAll(false);
    }
  };

  const handleExtractSingle = async (keyOverride?: string) => {
    const key = (keyOverride ?? singleKey).trim();
    if (!key) return;
    setSingleSubmitting(true);
    setSingleResult(null);
    try {
      const response = await axios.post(
        `/bio-phones/extract/${encodeURIComponent(key)}`,
        null,
        { params: { platform } },
      );
      const payload = response.data?.data;
      const msg = response.data?.message || '';
      const found = !!(payload?.id && (payload.email || payload.phone));
      setSingleResult({
        found,
        message: msg,
        row: found ? normalizeRow(platform, payload as AnyRow) : undefined,
      });
      if (found) await fetchData();
    } catch (err) {
      const e = err as {
        response?: { data?: { message?: string } };
        message?: string;
      };
      setSingleResult({
        found: false,
        message:
          e?.response?.data?.message ||
          e?.message ||
          'Failed to extract this profile',
      });
    } finally {
      setSingleSubmitting(false);
    }
  };

  const handleExport = async (scope: 'current' | 'all' = 'current') => {
    setExportError(null);
    setExporting(true);
    try {
      const params: Record<string, string | number> = {
        platform: scope === 'all' ? 'all' : platform,
      };
      if (scope === 'current') {
        if (searchQuery) params.search = searchQuery;
        if (hasEmail) params.has_email = 1;
        if (hasPhone) params.has_phone = 1;
      }
      const response = await axios.get('/bio-phones/export', {
        params,
        responseType: 'blob',
      });

      // A failed export still arrives as a Blob because of responseType, so a
      // JSON error body would otherwise be saved as a .csv the user can't read.
      const jsonError = await jsonErrorInBlobResponse(response);
      if (jsonError) throw new Error(jsonError);

      const url = window.URL.createObjectURL(new Blob([response.data]));
      const a = document.createElement('a');
      a.href = url;
      a.download = `bio_phones_${scope === 'all' ? 'all' : platform}_${new Date()
        .toISOString()
        .slice(0, 10)}.csv`;
      document.body.appendChild(a);
      a.click();
      a.remove();
      window.URL.revokeObjectURL(url);
    } catch (err) {
      // The server's message was previously only logged, so a failed export
      // looked like nothing happening at all.
      console.error('Export failed:', err);
      setExportError(await getBlobErrorMessage(err));
    } finally {
      setExporting(false);
    }
  };

  const platformLabel =
    PLATFORMS.find((p) => p.value === platform)?.label || platform;

  const handleLabel = platform === 'snapchat' ? 'Snap Username' : 'Username';
  const titleLabel = platform === 'snapchat' ? 'Display Name' : 'Title';
  const lookupPlaceholder =
    platform === 'snapchat' ? 'Profile ID (UUID)' : 'Username or Social ID';

  // Stats from current page
  const pageStats = useMemo(
    () => ({
      withEmail: records.filter((r) => r.email).length,
      withPhone: records.filter((r) => r.phone).length,
      withBoth: records.filter((r) => r.email && r.phone).length,
    }),
    [records],
  );

  // Active filter count for the filter button badge
  const activeFilterCount =
    (hasEmail ? 1 : 0) + (hasPhone ? 1 : 0) + (searchQuery ? 1 : 0);

  const columns = useMemo<ColumnDef<NormalizedRow>[]>(
    () => [
      {
        id: 'index',
        header: '#',
        cell: ({ row }) => (
          <span className="text-xs text-muted-foreground">
            {pagination.pageIndex * pagination.pageSize + row.index + 1}
          </span>
        ),
        enableSorting: false,
        enableHiding: false,
        size: 60,
      },
      {
        id: 'handle',
        accessorFn: (row) => row.handle,
        header: ({ column }) => (
          <DataGridColumnHeader title={handleLabel} column={column} />
        ),
        cell: ({ row }) => (
          <div className="flex items-center gap-2.5 min-w-0">
            <Avatar className="h-7 w-7 shrink-0">
              <AvatarFallback className="text-[10px] bg-primary/10 text-primary font-semibold">
                {(row.original.handle || '??').substring(0, 2).toUpperCase()}
              </AvatarFallback>
            </Avatar>
            <span className="text-sm font-medium truncate">
              {row.original.handle || '-'}
            </span>
          </div>
        ),
        enableSorting: true,
        size: 220,
      },
      {
        id: 'title',
        accessorFn: (row) => row.title,
        header: ({ column }) => (
          <DataGridColumnHeader title={titleLabel} column={column} />
        ),
        cell: ({ row }) => (
          <span className="text-sm">{row.original.title || '-'}</span>
        ),
        enableSorting: true,
        size: 200,
      },
      {
        id: 'email',
        accessorFn: (row) => row.email || '',
        header: ({ column }) => (
          <DataGridColumnHeader title="Email" column={column} />
        ),
        cell: ({ row }) => {
          const emails = splitMulti(row.original.email);
          if (!emails.length)
            return (
              <span className="text-xs text-muted-foreground/50">-</span>
            );
          return (
            <div className="flex flex-col gap-0.5">
              {emails.map((e) => (
                <div key={e} className="flex items-center gap-1.5">
                  <Mail className="h-3.5 w-3.5 text-emerald-500 shrink-0" />
                  <span className="text-sm text-emerald-700 dark:text-emerald-400">
                    {e}
                  </span>
                  <CopyButton value={e} />
                </div>
              ))}
            </div>
          );
        },
        enableSorting: true,
        size: 240,
      },
      {
        id: 'phone',
        accessorFn: (row) => row.phone || '',
        header: ({ column }) => (
          <DataGridColumnHeader title="Phone" column={column} />
        ),
        cell: ({ row }) => {
          const phones = splitMulti(row.original.phone);
          if (!phones.length)
            return (
              <span className="text-xs text-muted-foreground/50">-</span>
            );
          return (
            <div className="flex flex-col gap-0.5">
              {phones.map((p) => (
                <div key={p} className="flex items-center gap-1.5">
                  <Phone className="h-3.5 w-3.5 text-violet-500 shrink-0" />
                  <span className="text-sm text-violet-700 dark:text-violet-400 font-mono">
                    {p}
                  </span>
                  <CopyButton value={p} />
                </div>
              ))}
            </div>
          );
        },
        enableSorting: true,
        size: 220,
      },
      {
        id: 'bio',
        accessorFn: (row) => row.raw_bio || '',
        header: ({ column }) => (
          <DataGridColumnHeader title="Bio" column={column} />
        ),
        cell: ({ row }) =>
          row.original.raw_bio ? (
            <button
              className="text-xs text-muted-foreground truncate block max-w-[220px] text-left hover:text-foreground transition-colors"
              onClick={() => setDetailRow(row.original)}
            >
              {row.original.raw_bio}
            </button>
          ) : (
            <span className="text-xs text-muted-foreground/50">-</span>
          ),
        enableSorting: false,
        size: 240,
      },
      {
        id: 'created_at',
        accessorFn: (row) => row.created_at,
        header: ({ column }) => (
          <DataGridColumnHeader title="Created" column={column} />
        ),
        cell: ({ row }) => (
          <span className="text-xs text-muted-foreground whitespace-nowrap">
            {row.original.created_at
              ? new Date(row.original.created_at).toLocaleDateString()
              : '-'}
          </span>
        ),
        enableSorting: true,
        size: 110,
      },
      {
        id: 'actions',
        header: '',
        cell: ({ row }) => (
          <div className="flex items-center gap-1">
            <Button
              variant="ghost"
              size="sm"
              mode="icon"
              className="h-7 w-7"
              onClick={() => setDetailRow(row.original)}
              title="View detail"
            >
              <Eye className="h-4 w-4" />
            </Button>
            <Button
              variant="ghost"
              size="sm"
              mode="icon"
              className="h-7 w-7"
              onClick={() => handleExtractSingle(row.original.key)}
              title="Re-extract this profile"
            >
              <RefreshCw className="h-3.5 w-3.5" />
            </Button>
          </div>
        ),
        enableSorting: false,
        enableHiding: false,
        size: 90,
      },
    ],
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [handleLabel, titleLabel, pagination.pageIndex, pagination.pageSize],
  );

  const table = useReactTable({
    columns,
    data: records,
    pageCount: meta.last_page || 1,
    getRowId: (row) => String(row.id),
    state: { pagination, sorting },
    manualPagination: true,
    manualFiltering: true,
    columnResizeMode: 'onChange',
    onPaginationChange: setPagination,
    onSortingChange: setSorting,
    getCoreRowModel: getCoreRowModel(),
    getSortedRowModel: getSortedRowModel(),
  });

  return (
    <Container>
      <Toolbar>
        <ToolbarHeading>
          <h1 className="text-xl font-semibold text-foreground">
            Bio Contact Extractor
          </h1>
          <p className="text-sm text-muted-foreground">
            Extract phones and emails from public bios across Snapchat, TikTok,
            and Instagram.
          </p>
        </ToolbarHeading>
      </Toolbar>

      <div className="space-y-4 pb-8">
        {/* Stats */}
        <div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-3">
          <Card>
            <CardContent className="p-4">
              <div className="flex items-center gap-3">
                <div className="bg-blue-50 dark:bg-blue-950/30 rounded-lg p-2.5">
                  <User className="h-4 w-4 text-blue-600" />
                </div>
                <div>
                  <p className="text-xs font-medium text-muted-foreground">
                    Total ({platformLabel})
                  </p>
                  <p className="text-xl font-bold text-blue-600">
                    {meta.total.toLocaleString()}
                  </p>
                </div>
              </div>
            </CardContent>
          </Card>
          <Card>
            <CardContent className="p-4">
              <div className="flex items-center gap-3">
                <div className="bg-emerald-50 dark:bg-emerald-950/30 rounded-lg p-2.5">
                  <Mail className="h-4 w-4 text-emerald-600" />
                </div>
                <div>
                  <p className="text-xs font-medium text-muted-foreground">
                    With Email (page)
                  </p>
                  <p className="text-xl font-bold text-emerald-600">
                    {pageStats.withEmail.toLocaleString()}
                  </p>
                </div>
              </div>
            </CardContent>
          </Card>
          <Card>
            <CardContent className="p-4">
              <div className="flex items-center gap-3">
                <div className="bg-violet-50 dark:bg-violet-950/30 rounded-lg p-2.5">
                  <Phone className="h-4 w-4 text-violet-600" />
                </div>
                <div>
                  <p className="text-xs font-medium text-muted-foreground">
                    With Phone (page)
                  </p>
                  <p className="text-xl font-bold text-violet-600">
                    {pageStats.withPhone.toLocaleString()}
                  </p>
                </div>
              </div>
            </CardContent>
          </Card>
          <Card>
            <CardContent className="p-4">
              <div className="flex items-center gap-3">
                <div className="bg-amber-50 dark:bg-amber-950/30 rounded-lg p-2.5">
                  <User className="h-4 w-4 text-amber-600" />
                </div>
                <div>
                  <p className="text-xs font-medium text-muted-foreground">
                    With Both (page)
                  </p>
                  <p className="text-xl font-bold text-amber-600">
                    {pageStats.withBoth.toLocaleString()}
                  </p>
                </div>
              </div>
            </CardContent>
          </Card>
        </div>

        {extractAllResult ? (
          <div className="rounded-md border border-emerald-200 bg-emerald-50 text-emerald-900 px-3 py-2 text-sm flex items-center justify-between">
            <span>{extractAllResult}</span>
            <button
              onClick={() => setExtractAllResult(null)}
              className="text-emerald-700 hover:text-emerald-900"
            >
              <X className="h-4 w-4" />
            </button>
          </div>
        ) : null}

        <DataGrid
          table={table}
          recordCount={meta.total}
          isLoading={loading}
          loadingMode="skeleton"
          emptyMessage={
            searchQuery || hasEmail || hasPhone
              ? 'No results match your filters.'
              : `No extracted contacts yet for ${platformLabel}. Click "Re-scan all bios" to start.`
          }
          tableLayout={{
            columnsPinnable: true,
            columnsMovable: true,
            columnsVisibility: true,
            cellBorder: true,
            headerBackground: true,
            headerSticky: true,
            dense: false,
          }}
        >
          <Card>
            <CardHeader className="flex-col sm:flex-row sm:items-center gap-3">
              <CardHeading>
                <div className="flex flex-wrap items-center gap-3">
                  <CardTitle>Extracted Contacts</CardTitle>

                  {/* Platform switcher */}
                  <Select
                    value={platform}
                    onValueChange={(v) => updatePlatform(v as Platform)}
                  >
                    <SelectTrigger className="h-9 w-[160px]">
                      <SelectValue />
                    </SelectTrigger>
                    <SelectContent>
                      {PLATFORMS.map((p) => (
                        <SelectItem key={p.value} value={p.value}>
                          {p.label}
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>

                  {/* Search */}
                  <div className="relative">
                    <Search className="size-4 text-muted-foreground absolute start-3 top-1/2 -translate-y-1/2" />
                    <Input
                      placeholder="Search username, title, email, phone…"
                      value={searchInput}
                      onChange={(e) => setSearchInput(e.target.value)}
                      onKeyDown={(e) => {
                        if (e.key === 'Enter') setSearchQuery(searchInput);
                      }}
                      className="ps-9 w-[260px]"
                    />
                    {searchInput.length > 0 && (
                      <Button
                        mode="icon"
                        variant="ghost"
                        className="absolute end-1.5 top-1/2 -translate-y-1/2 h-6 w-6"
                        onClick={() => {
                          setSearchInput('');
                          setSearchQuery('');
                        }}
                      >
                        <X />
                      </Button>
                    )}
                  </div>
                </div>
              </CardHeading>

              <CardToolbar>
                {/* Advanced filters popover */}
                <Popover>
                  <PopoverTrigger asChild>
                    <Button variant="outline" size="sm">
                      <Filter className="size-4" />
                      Filters
                      {activeFilterCount > 0 ? (
                        <Badge size="sm" variant="primary" className="ml-1">
                          {activeFilterCount}
                        </Badge>
                      ) : null}
                    </Button>
                  </PopoverTrigger>
                  <PopoverContent align="end" className="w-72 space-y-3">
                    <div className="space-y-2">
                      <Label className="text-xs font-medium text-muted-foreground">
                        Search
                      </Label>
                      <div className="flex gap-2">
                        <Input
                          value={searchInput}
                          onChange={(e) => setSearchInput(e.target.value)}
                          placeholder="Search…"
                          className="h-9"
                        />
                        <Button
                          size="sm"
                          variant="outline"
                          onClick={() => setSearchQuery(searchInput)}
                        >
                          Apply
                        </Button>
                      </div>
                    </div>
                    <div className="space-y-2">
                      <Label className="text-xs font-medium text-muted-foreground">
                        Contact info
                      </Label>
                      <div className="flex flex-col gap-1.5">
                        <label className="flex items-center gap-2 text-sm cursor-pointer">
                          <input
                            type="checkbox"
                            checked={hasPhone}
                            onChange={(e) => setHasPhone(e.target.checked)}
                            className="rounded"
                          />
                          Has phone number
                        </label>
                        <label className="flex items-center gap-2 text-sm cursor-pointer">
                          <input
                            type="checkbox"
                            checked={hasEmail}
                            onChange={(e) => setHasEmail(e.target.checked)}
                            className="rounded"
                          />
                          Has email
                        </label>
                      </div>
                    </div>
                    {activeFilterCount > 0 ? (
                      <Button
                        variant="outline"
                        size="sm"
                        className="w-full"
                        onClick={() => {
                          setSearchInput('');
                          setSearchQuery('');
                          setHasEmail(false);
                          setHasPhone(false);
                        }}
                      >
                        <X className="size-3.5" />
                        Clear all filters
                      </Button>
                    ) : null}
                  </PopoverContent>
                </Popover>

                <DataGridColumnVisibility
                  table={table}
                  trigger={
                    <Button variant="outline" size="sm">
                      <Settings2 />
                      Columns
                    </Button>
                  }
                />

                <Button
                  variant="outline"
                  size="sm"
                  onClick={fetchData}
                  disabled={loading}
                >
                  <RefreshCw
                    className={loading ? 'animate-spin' : ''}
                  />
                  Refresh
                </Button>

                {/* Export current platform (respects active filters) */}
                <Button
                  variant="outline"
                  size="sm"
                  onClick={() => handleExport('current')}
                  disabled={exporting}
                  title={`Export ${platformLabel} contacts as CSV (Excel)`}
                >
                  {exporting ? (
                    <Loader2 className="animate-spin" />
                  ) : (
                    <Download />
                  )}
                  Export
                </Button>

                {/* Export every platform in one file */}
                <Button
                  variant="outline"
                  size="sm"
                  onClick={() => handleExport('all')}
                  disabled={exporting}
                  title="Export all platforms into one CSV (Excel)"
                >
                  <Download />
                  Export all
                </Button>

                {exportError && (
                  <span
                    role="alert"
                    className="flex items-center gap-1.5 text-sm text-red-600"
                  >
                    <AlertTriangle className="h-4 w-4 shrink-0" />
                    {exportError}
                  </span>
                )}

                {/* Extract single */}
                <Dialog
                  open={extractSingleOpen}
                  onOpenChange={(o) => {
                    setExtractSingleOpen(o);
                    if (!o) {
                      setSingleKey('');
                      setSingleResult(null);
                    }
                  }}
                >
                  <DialogTrigger asChild>
                    <Button variant="outline" size="sm">
                      <Plus />
                      Extract Single
                    </Button>
                  </DialogTrigger>
                  <DialogContent>
                    <DialogHeader>
                      <DialogTitle>
                        Extract single profile · {platformLabel}
                      </DialogTitle>
                      <DialogDescription>
                        Re-runs extraction on one profile and refreshes its row
                        in the table.
                      </DialogDescription>
                    </DialogHeader>
                    <div className="space-y-3 py-2">
                      <div>
                        <Label className="text-xs">{lookupPlaceholder}</Label>
                        <Input
                          value={singleKey}
                          onChange={(e) => setSingleKey(e.target.value)}
                          placeholder={lookupPlaceholder}
                          autoFocus
                          onKeyDown={(e) => {
                            if (e.key === 'Enter' && !singleSubmitting)
                              handleExtractSingle();
                          }}
                          disabled={singleSubmitting}
                        />
                      </div>
                      {singleResult ? (
                        <div
                          className={`rounded-md border p-3 text-sm ${
                            singleResult.found
                              ? 'border-emerald-200 bg-emerald-50 text-emerald-900'
                              : 'border-amber-200 bg-amber-50 text-amber-900'
                          }`}
                        >
                          <div className="font-medium">
                            {singleResult.message}
                          </div>
                          {singleResult.row ? (
                            <div className="mt-2 space-y-1 text-xs">
                              {singleResult.row.email ? (
                                <div>Email: {singleResult.row.email}</div>
                              ) : null}
                              {singleResult.row.phone ? (
                                <div>Phone: {singleResult.row.phone}</div>
                              ) : null}
                            </div>
                          ) : null}
                        </div>
                      ) : null}
                    </div>
                    <DialogFooter>
                      <Button
                        variant="outline"
                        onClick={() => setExtractSingleOpen(false)}
                        disabled={singleSubmitting}
                      >
                        Close
                      </Button>
                      <Button
                        onClick={() => handleExtractSingle()}
                        disabled={singleSubmitting || !singleKey.trim()}
                      >
                        {singleSubmitting ? (
                          <Loader2 className="animate-spin" />
                        ) : (
                          <Play />
                        )}
                        Extract
                      </Button>
                    </DialogFooter>
                  </DialogContent>
                </Dialog>

                {/* Re-scan all */}
                <Dialog
                  open={confirmExtractAll}
                  onOpenChange={setConfirmExtractAll}
                >
                  <DialogTrigger asChild>
                    <Button size="sm" disabled={extractingAll}>
                      {extractingAll ? (
                        <Loader2 className="animate-spin" />
                      ) : (
                        <Play />
                      )}
                      {extractingAll ? 'Scanning…' : `Re-scan all ${platformLabel}`}
                    </Button>
                  </DialogTrigger>
                  <DialogContent>
                    <DialogHeader>
                      <DialogTitle className="flex items-center gap-2">
                        <AlertTriangle className="h-5 w-5 text-amber-600" />
                        Re-scan all {platformLabel} bios?
                      </DialogTitle>
                      <DialogDescription>
                        {platform === 'snapchat'
                          ? 'Scans every Snapchat profile bio. Usually fast.'
                          : 'This may take a few minutes for large datasets — TikTok and Instagram chunk through 500 rows at a time on the server.'}{' '}
                        Existing rows are refreshed in place — no duplicates created.
                      </DialogDescription>
                    </DialogHeader>
                    <DialogFooter>
                      <Button
                        variant="outline"
                        onClick={() => setConfirmExtractAll(false)}
                      >
                        Cancel
                      </Button>
                      <Button onClick={handleExtractAll}>
                        <Play />
                        Start scan
                      </Button>
                    </DialogFooter>
                  </DialogContent>
                </Dialog>
              </CardToolbar>
            </CardHeader>

            {/* Active filter chips */}
            {activeFilterCount > 0 ? (
              <div className="px-5 pt-2 flex flex-wrap items-center gap-2">
                <span className="text-xs text-muted-foreground">
                  Active filters:
                </span>
                {searchQuery ? (
                  <Badge variant="secondary" appearance="outline">
                    Search: {searchQuery}
                    <button
                      onClick={() => {
                        setSearchInput('');
                        setSearchQuery('');
                      }}
                      className="ml-1 hover:text-foreground"
                    >
                      <X className="h-3 w-3" />
                    </button>
                  </Badge>
                ) : null}
                {hasPhone ? (
                  <Badge variant="secondary" appearance="outline">
                    Has phone
                    <button
                      onClick={() => setHasPhone(false)}
                      className="ml-1 hover:text-foreground"
                    >
                      <X className="h-3 w-3" />
                    </button>
                  </Badge>
                ) : null}
                {hasEmail ? (
                  <Badge variant="secondary" appearance="outline">
                    Has email
                    <button
                      onClick={() => setHasEmail(false)}
                      className="ml-1 hover:text-foreground"
                    >
                      <X className="h-3 w-3" />
                    </button>
                  </Badge>
                ) : null}
              </div>
            ) : null}

            <CardTable>
              <ScrollArea>
                <DataGridTable />
                <ScrollBar orientation="horizontal" />
              </ScrollArea>
            </CardTable>
            <CardFooter>
              <DataGridPagination
                sizes={[25, 50, 100, 200]}
                sizesLabel="Rows per page"
              />
            </CardFooter>
          </Card>
        </DataGrid>
      </div>

      {/* Detail dialog */}
      <Dialog
        open={!!detailRow}
        onOpenChange={(o) => !o && setDetailRow(null)}
      >
        <DialogContent>
          <DialogHeader>
            <DialogTitle className="flex items-center gap-2">
              <Avatar className="h-6 w-6">
                <AvatarFallback className="text-[10px] bg-primary/10 text-primary font-semibold">
                  {(detailRow?.handle || '??').substring(0, 2).toUpperCase()}
                </AvatarFallback>
              </Avatar>
              {detailRow?.handle}
            </DialogTitle>
          </DialogHeader>
          {detailRow ? (
            <RowDetail record={detailRow} platform={platform} />
          ) : null}
        </DialogContent>
      </Dialog>
    </Container>
  );
}

export default function BioPhonesPage() {
  return (
    <Suspense
      fallback={
        <div className="flex items-center justify-center py-16">
          <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
        </div>
      }
    >
      <BioPhonesPageInner />
    </Suspense>
  );
}
