import { useEffect, useMemo, useState } from 'react';
import {
  CheckCircle2, ChevronDown, ExternalLink, Link2, Link2Off,
  Loader2, Pencil, Plus, Search, X,
} from 'lucide-react';
import { toast } from 'sonner';
import { api } from '@/api';
import { cn, fmt, errMessage } from '@/lib/utils';
import type { Dollars } from '@/lib/money';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Checkbox } from '@/components/ui/checkbox';
import {
  Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle,
} from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';

interface Descriptor {
  id: number | string;
  descriptor?: string;
}

interface MatchedBill {
  id: number;
  name?: string;
  active?: number;
  monthly_equivalent?: Dollars;
}

interface CatalogEntry {
  id: number | string;
  name: string;
  category?: string | null;
  subscription_type?: string;
  starting_monthly_usd?: number | null;
  website?: string | null;
  matched_bill?: MatchedBill | null;
  user_descriptors?: Descriptor[];
}

const TYPE_LABELS: Record<string, string> = {
  streaming: 'Streaming', software: 'Software', cloud: 'Cloud',
  music: 'Music', news: 'News', fitness: 'Fitness', gaming: 'Gaming',
  utilities: 'Utilities', insurance: 'Insurance', food: 'Food',
  education: 'Education', shopping: 'Shopping', security: 'Security', other: 'Other',
};

const CHIPS: { value: string | null; label: string }[] = [
  { value: null,        label: 'All' },
  { value: 'streaming', label: 'Streaming' },
  { value: 'music',     label: 'Music' },
  { value: 'gaming',    label: 'Gaming' },
  { value: 'news',      label: 'News' },
  { value: 'fitness',   label: 'Fitness' },
  { value: 'software',  label: 'Software' },
  { value: 'security',  label: 'Security' },
  { value: 'food',      label: 'Food' },
  { value: 'cloud',     label: 'Cloud' },
  { value: 'shopping',  label: 'Shopping' },
  { value: 'education', label: 'Education' },
];

// Returns 'match' | 'above' | 'below' | null
function priceDrift(monthly: number | null | undefined, catalogStarting: number | null | undefined): 'match' | 'above' | 'below' | null {
  if (!catalogStarting || !monthly) return null;
  const pct = (monthly - catalogStarting) / catalogStarting;
  if (Math.abs(pct) <= 0.05) return 'match';
  return pct > 0 ? 'above' : 'below';
}

// ── Descriptor editor inline inside a matched card ─────────────────────────
function DescriptorEditor({ catalogId, descriptors, onAdd, onDelete }: {
  catalogId: number | string;
  descriptors: Descriptor[];
  onAdd: (catalogId: number | string, descriptor: string) => Promise<boolean> | void;
  onDelete: (descriptorId: number | string) => void;
}) {
  const [open, setOpen]         = useState(false);
  const [value, setValue]       = useState('');
  const [busy, setBusy]         = useState(false);

  async function handleAdd() {
    const d = value.trim();
    if (!d) return;
    setBusy(true);
    try {
      await onAdd(catalogId, d);
      setValue('');
    } finally {
      setBusy(false);
    }
  }

  return (
    <div className="mt-2 border-t border-border/30 pt-2">
      <button
        type="button"
        onClick={() => setOpen(s => !s)}
        className="flex items-center gap-1 text-[11px] text-muted-foreground transition-colors hover:text-foreground"
      >
        <ChevronDown className={cn('h-3 w-3 transition-transform', !open && '-rotate-90')} />
        Custom bank descriptors
        {descriptors.length > 0 && (
          <span className="ml-1 rounded bg-muted/50 px-1 font-mono text-[10px]">{descriptors.length}</span>
        )}
      </button>

      {open && (
        <div className="mt-2 space-y-1.5">
          {descriptors.map(d => (
            <div key={d.id} className="flex items-center gap-2">
              <span className="flex-1 rounded border border-border/40 bg-muted/30 px-2 py-0.5 font-mono text-[11px]">
                {d.descriptor}
              </span>
              <button
                type="button"
                onClick={() => onDelete(d.id)}
                className="text-muted-foreground transition-colors hover:text-destructive"
                title="Remove descriptor"
              >
                <X className="h-3 w-3" />
              </button>
            </div>
          ))}

          <div className="flex gap-1.5">
            <Input
              placeholder="e.g. NETFLIX DIGITAL"
              value={value}
              onChange={e => setValue(e.target.value)}
              onKeyDown={e => { if (e.key === 'Enter' && value.trim()) handleAdd(); }}
              className="h-7 font-mono text-xs"
            />
            <Button
              type="button"
              size="sm"
              variant="outline"
              disabled={!value.trim() || busy}
              onClick={handleAdd}
              className="h-7 px-2"
            >
              {busy ? <Loader2 className="h-3 w-3 animate-spin" /> : <Plus className="h-3 w-3" />}
            </Button>
          </div>
          <p className="text-[10px] text-muted-foreground/70">
            Add the exact payee text your bank uses to improve auto-matching.
          </p>
        </div>
      )}
    </div>
  );
}

// ── Card for an already-tracked catalog entry ──────────────────────────────
function MatchedCard({ entry, onEdit, onRelink, onAddDescriptor, onDeleteDescriptor }: {
  entry: CatalogEntry;
  onEdit: (id: number) => void;
  onRelink: (entry: CatalogEntry) => void;
  onAddDescriptor: (catalogId: number | string, descriptor: string) => Promise<boolean> | void;
  onDeleteDescriptor: (descriptorId: number | string) => void;
}) {
  const { matched_bill: bill, user_descriptors: descs = [] } = entry;
  const drift = priceDrift(bill?.monthly_equivalent, entry.starting_monthly_usd);

  return (
    <div className="rounded-lg border border-primary/20 bg-primary/5 p-3 transition-colors hover:border-primary/30">
      <div className="flex items-start justify-between gap-3">
        <div className="min-w-0 flex-1">
          <div className="flex flex-wrap items-center gap-1.5">
            <span className="text-sm font-semibold text-foreground">{entry.name}</span>
            <Badge
              variant="outline"
              className="border-primary/25 bg-primary/10 text-[10px] text-primary"
            >
              {TYPE_LABELS[entry.subscription_type ?? ''] || 'Other'}
            </Badge>
            {bill && !bill.active && (
              <Badge variant="outline" className="border-amber-500/25 bg-amber-500/10 text-[10px] text-amber-400">
                Paused
              </Badge>
            )}
          </div>

          <div className="mt-1 flex flex-wrap items-center gap-x-3 gap-y-0.5 text-xs">
            {bill && (
              <span className="font-mono font-semibold text-foreground">{fmt(bill.monthly_equivalent)}/mo</span>
            )}
            {drift === 'match' && entry.starting_monthly_usd && (
              <span className="flex items-center gap-1 text-emerald-500">
                <CheckCircle2 className="h-3 w-3" />
                matches catalog price
              </span>
            )}
            {drift === 'above' && (
              <span className="text-amber-500">
                catalog from ${entry.starting_monthly_usd?.toFixed(2)}/mo
              </span>
            )}
            {drift === 'below' && entry.starting_monthly_usd && (
              <span className="text-sky-500">
                catalog from ${entry.starting_monthly_usd.toFixed(2)}/mo
              </span>
            )}
            {!entry.starting_monthly_usd && entry.website && (
              <a
                href={entry.website}
                target="_blank"
                rel="noreferrer"
                className="flex items-center gap-0.5 text-muted-foreground hover:text-primary"
              >
                website <ExternalLink className="h-2.5 w-2.5" />
              </a>
            )}
          </div>
        </div>

        <div className="flex shrink-0 items-center gap-1">
          <Button
            type="button"
            size="sm"
            variant="outline"
            className="h-7 gap-1 text-xs"
            onClick={() => bill && onEdit(bill.id)}
          >
            <Pencil className="h-3 w-3" />
            Edit
          </Button>
          <Button
            type="button"
            size="sm"
            variant="ghost"
            className="h-7 gap-1 text-xs text-muted-foreground hover:text-foreground"
            onClick={() => onRelink(entry)}
            title="Change catalog link"
          >
            <Link2 className="h-3 w-3" />
            Re-link
          </Button>
        </div>
      </div>

      <DescriptorEditor
        catalogId={entry.id}
        descriptors={descs}
        onAdd={onAddDescriptor}
        onDelete={onDeleteDescriptor}
      />
    </div>
  );
}

// ── Card for an untracked catalog entry ───────────────────────────────────
function UnmatchedCard({ entry, selected, onToggleSelect, onTrack, trackingBusy }: {
  entry: CatalogEntry;
  selected: boolean;
  onToggleSelect: (id: number | string, checked: boolean) => void;
  onTrack: (entry: CatalogEntry) => void;
  trackingBusy: boolean;
}) {
  return (
    <div
      className={cn(
        'flex items-center gap-3 rounded-lg border px-3 py-2.5 transition-colors',
        selected
          ? 'border-primary/30 bg-primary/5'
          : 'border-border/60 bg-background/35 hover:border-border/80',
      )}
    >
      <Checkbox
        checked={selected}
        onCheckedChange={checked => onToggleSelect(entry.id, !!checked)}
        aria-label={`Select ${entry.name}`}
      />
      <div className="min-w-0 flex-1">
        <p className="text-sm font-medium text-foreground">{entry.name}</p>
        <p className="text-xs text-muted-foreground">
          {entry.category}
          {entry.starting_monthly_usd && (
            <span className="ml-2 font-mono">from ${entry.starting_monthly_usd.toFixed(2)}/mo</span>
          )}
        </p>
      </div>
      {entry.website && (
        <a
          href={entry.website}
          target="_blank"
          rel="noreferrer"
          className="shrink-0 text-muted-foreground hover:text-primary"
          title="Open website"
        >
          <ExternalLink className="h-3.5 w-3.5" />
        </a>
      )}
      <Button
        type="button"
        size="sm"
        variant="outline"
        className="h-7 shrink-0 gap-1 text-xs"
        disabled={trackingBusy}
        onClick={() => onTrack(entry)}
      >
        {trackingBusy
          ? <Loader2 className="h-3 w-3 animate-spin" />
          : <><Plus className="h-3 w-3" />Track</>}
      </Button>
    </div>
  );
}

// ── Re-link dialog ─────────────────────────────────────────────────────────
function ReLinkDialog({ open, relinkEntry, allEntries, onClose, onConfirm, busy }: {
  open: boolean;
  relinkEntry: CatalogEntry | null;
  allEntries: CatalogEntry[];
  onClose: () => void;
  onConfirm: (billId: number | undefined, catalogId: number | string | null) => void;
  busy: boolean;
}) {
  const [search, setSearch]   = useState('');
  const [selected, setSelected] = useState<number | string | null>(null);

  useEffect(() => {
    if (open) { setSearch(''); setSelected(null); }
  }, [open]);

  const filtered = useMemo(() => {
    const q = search.toLowerCase();
    return allEntries.filter(e =>
      !q || e.name.toLowerCase().includes(q) || (e.category || '').toLowerCase().includes(q)
    );
  }, [allEntries, search]);

  const bill = relinkEntry?.matched_bill;

  return (
    <Dialog open={open} onOpenChange={v => { if (!v) onClose(); }}>
      <DialogContent className="border-border/60 bg-card/95 backdrop-blur-xl sm:max-w-md">
        <DialogHeader>
          <DialogTitle className="text-base font-semibold">Re-link to catalog entry</DialogTitle>
          {bill && (
            <p className="text-sm text-muted-foreground">
              Choose the correct service for{' '}
              <span className="font-medium text-foreground">{bill.name}</span>.
            </p>
          )}
        </DialogHeader>

        <Input
          autoFocus
          placeholder="Search services…"
          value={search}
          onChange={e => setSearch(e.target.value)}
          className="text-sm"
        />

        <div className="max-h-60 divide-y divide-border/40 overflow-y-auto rounded-lg border border-border/60">
          {/* Unlink option */}
          <button
            type="button"
            onClick={() => setSelected('unlink')}
            className={cn(
              'flex w-full items-center gap-3 px-3 py-2.5 text-left transition-colors hover:bg-muted/30',
              selected === 'unlink' && 'bg-primary/5',
            )}
          >
            <Link2Off className="h-4 w-4 shrink-0 text-muted-foreground" />
            <span className="text-sm text-muted-foreground">Unlink from catalog</span>
            {selected === 'unlink' && (
              <CheckCircle2 className="ml-auto h-4 w-4 shrink-0 text-primary" />
            )}
          </button>

          {filtered.length === 0 && search ? (
            <p className="px-3 py-4 text-center text-sm text-muted-foreground">No services found.</p>
          ) : filtered.map(e => (
            <button
              key={e.id}
              type="button"
              onClick={() => setSelected(e.id)}
              disabled={e.id === relinkEntry?.id}
              className={cn(
                'flex w-full items-center justify-between gap-3 px-3 py-2 text-left transition-colors',
                'hover:bg-muted/30 disabled:pointer-events-none disabled:opacity-40',
                selected === e.id && 'bg-primary/5',
              )}
            >
              <div className="min-w-0">
                <p className="truncate text-sm font-medium">{e.name}</p>
                <p className="text-xs text-muted-foreground">{e.category}</p>
              </div>
              <div className="flex shrink-0 items-center gap-2">
                {e.starting_monthly_usd && (
                  <span className="font-mono text-xs text-muted-foreground">
                    ${e.starting_monthly_usd.toFixed(2)}/mo
                  </span>
                )}
                {selected === e.id && <CheckCircle2 className="h-4 w-4 text-primary" />}
              </div>
            </button>
          ))}
        </div>

        <DialogFooter className="gap-2">
          <Button type="button" variant="ghost" onClick={onClose} className="text-xs">
            Cancel
          </Button>
          <Button
            type="button"
            disabled={!selected || busy}
            onClick={() => onConfirm(bill?.id, selected === 'unlink' ? null : selected)}
            className="text-xs"
          >
            {busy ? 'Saving…' : 'Confirm'}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

// ── Main component ─────────────────────────────────────────────────────────
export default function SubscriptionCatalogSection({ onEditBill, onTrackComplete }: {
  onEditBill: (id: number) => void;
  onTrackComplete?: () => void;
}) {
  const [catalog, setCatalog]           = useState<CatalogEntry[]>([]);
  const [loading, setLoading]           = useState(true);
  const [error, setError]               = useState<string | null>(null);
  const [showUnmatched, setShowUnmatched] = useState(false);
  const [activeType, setActiveType]     = useState<string | null>(null);
  const [search, setSearch]             = useState('');
  const [selectedIds, setSelectedIds]   = useState<Set<number | string>>(new Set());
  const [relinkEntry, setRelinkEntry]   = useState<CatalogEntry | null>(null);
  const [relinkBusy, setRelinkBusy]     = useState(false);
  const [trackBusyId, setTrackBusyId]   = useState<number | string | null>(null);
  const [bulkBusy, setBulkBusy]         = useState(false);

  async function loadCatalog() {
    setLoading(true);
    setError(null);
    try {
      const data = await api.subscriptionCatalog() as { catalog?: CatalogEntry[] };
      setCatalog(data.catalog || []);
    } catch (err) {
      const message = errMessage(err, 'Failed to load catalog');
      setError(message);
      toast.error(message);
    } finally {
      setLoading(false);
    }
  }

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

  // Filter by type chip + search
  const filtered = useMemo(() => {
    const q = search.toLowerCase().trim();
    return catalog.filter(e => {
      if (activeType && e.subscription_type !== activeType) return false;
      if (q) return e.name.toLowerCase().includes(q) || (e.category || '').toLowerCase().includes(q);
      return true;
    });
  }, [catalog, activeType, search]);

  const matched   = filtered.filter(e => e.matched_bill != null);
  const unmatched = filtered.filter(e => e.matched_bill == null);

  // ── Handlers ─────────────────────────────────────────────────────────────

  async function handleTrack(entry: CatalogEntry) {
    setTrackBusyId(entry.id);
    try {
      await api.createSubscriptionFromRecommendation({
        name:              entry.name,
        due_day:           1,
        expected_amount:   entry.starting_monthly_usd || 0,
        cycle_type:        'monthly',
        subscription_type: entry.subscription_type || 'other',
        catalog_match:     { id: entry.id, name: entry.name, subscription_type: entry.subscription_type },
      });
      toast.success(`${entry.name} added to your subscriptions`, {
        description: 'Open it with Edit to set the correct amount and due date.',
      });
      await loadCatalog();
      onTrackComplete?.();
    } catch (err) {
      toast.error(errMessage(err, `Failed to add ${entry.name}`));
    } finally {
      setTrackBusyId(null);
    }
  }

  async function handleBulkTrack() {
    if (selectedIds.size === 0) return;
    setBulkBusy(true);
    const toTrack = unmatched.filter(e => selectedIds.has(e.id));
    let succeeded = 0;
    let failed = 0;
    for (const entry of toTrack) {
      try {
        await api.createSubscriptionFromRecommendation({
          name:              entry.name,
          due_day:           1,
          expected_amount:   entry.starting_monthly_usd || 0,
          cycle_type:        'monthly',
          subscription_type: entry.subscription_type || 'other',
          catalog_match:     { id: entry.id, name: entry.name, subscription_type: entry.subscription_type },
        });
        succeeded++;
      } catch {
        failed++;
      }
    }
    if (succeeded > 0) {
      toast.success(`${succeeded} subscription${succeeded !== 1 ? 's' : ''} added`);
      setSelectedIds(new Set());
      await loadCatalog();
      onTrackComplete?.();
    }
    if (failed > 0) {
      toast.error(`${failed} subscription${failed !== 1 ? 's' : ''} could not be added`);
    }
    setBulkBusy(false);
  }

  async function handleRelink(billId: number | undefined, catalogId: number | string | null) {
    if (billId == null) return;
    setRelinkBusy(true);
    try {
      await api.updateSubscriptionCatalogLink(billId, catalogId as number | string);
      toast.success(catalogId ? 'Catalog link updated' : 'Catalog link removed');
      setRelinkEntry(null);
      await loadCatalog();
    } catch (err) {
      toast.error(errMessage(err, 'Failed to update catalog link'));
    } finally {
      setRelinkBusy(false);
    }
  }

  async function handleAddDescriptor(catalogId: number | string, descriptor: string): Promise<boolean> {
    try {
      const newDesc = await api.addCatalogDescriptor(catalogId, descriptor) as Descriptor;
      setCatalog(prev => prev.map(e =>
        e.id === catalogId
          ? { ...e, user_descriptors: [...(e.user_descriptors || []), newDesc] }
          : e
      ));
      toast.success('Descriptor added');
      return true;
    } catch (err) {
      toast.error(errMessage(err, 'Failed to add descriptor'));
      return false;
    }
  }

  async function handleDeleteDescriptor(catalogId: number | string, descriptorId: number | string) {
    try {
      await api.deleteCatalogDescriptor(descriptorId);
      setCatalog(prev => prev.map(e =>
        e.id === catalogId
          ? { ...e, user_descriptors: (e.user_descriptors || []).filter(d => d.id !== descriptorId) }
          : e
      ));
      toast.success('Descriptor removed');
    } catch (err) {
      toast.error(errMessage(err, 'Failed to remove descriptor'));
    }
  }

  function toggleSelect(id: number | string, checked: boolean) {
    setSelectedIds(prev => {
      const next = new Set(prev);
      if (checked) next.add(id);
      else next.delete(id);
      return next;
    });
  }

  // ── Render ────────────────────────────────────────────────────────────────

  return (
    <Card className="overflow-hidden">
      <CardHeader className="px-4 pb-3 sm:px-6">
        <CardTitle className="text-base">Known Service Catalog</CardTitle>
        <CardDescription>
          Popular services, linked bills, and custom bank descriptors used to improve matching.
        </CardDescription>

        {/* Category filter chips */}
        <div className="mt-3 flex flex-wrap gap-1.5">
          {CHIPS.map(chip => (
            <button
              key={String(chip.value)}
              type="button"
              onClick={() => setActiveType(chip.value)}
              className={cn(
                'rounded-full border px-2.5 py-0.5 text-xs font-medium transition-colors',
                activeType === chip.value
                  ? 'border-primary/40 bg-primary/15 text-primary'
                  : 'border-border/60 bg-muted/20 text-muted-foreground hover:border-border/80 hover:text-foreground',
              )}
            >
              {chip.label}
            </button>
          ))}
        </div>

        {/* Search */}
        <div className="relative mt-2">
          <Search className="pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" />
          <Input
            type="search"
            placeholder="Search services…"
            value={search}
            onChange={e => setSearch(e.target.value)}
            className="h-9 pl-8 text-sm"
          />
        </div>
      </CardHeader>

      <CardContent className="p-0">
        {loading ? (
          <div className="flex items-center justify-center gap-2 py-10 text-sm text-muted-foreground">
            <Loader2 className="h-4 w-4 animate-spin" />
            Loading catalog…
          </div>
        ) : error ? (
          <div className="px-4 py-8 text-center">
            <p className="text-sm text-destructive">{error}</p>
            <Button
              type="button"
              variant="outline"
              size="sm"
              className="mt-3 text-xs"
              onClick={loadCatalog}
            >
              Retry
            </Button>
          </div>
        ) : (
          <div className="divide-y divide-border/40">

            {/* ── Matched group ───────────────────────────────────────── */}
            {matched.length > 0 && (
              <div className="px-4 pb-3 pt-3 sm:px-6">
                <p className="mb-2.5 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground">
                  Tracking ({matched.length})
                </p>
                <div className="space-y-2">
                  {matched.map(entry => (
                    <MatchedCard
                      key={entry.id}
                      entry={entry}
                      onEdit={onEditBill}
                      onRelink={setRelinkEntry}
                      onAddDescriptor={handleAddDescriptor}
                      onDeleteDescriptor={(descriptorId) => handleDeleteDescriptor(entry.id, descriptorId)}
                    />
                  ))}
                </div>
              </div>
            )}

            {/* ── Unmatched toggle + group ─────────────────────────── */}
            <div>
              <button
                type="button"
                onClick={() => setShowUnmatched(s => !s)}
                className={cn(
                  'flex w-full items-center justify-between px-4 py-3 text-sm font-medium text-muted-foreground',
                  'transition-colors hover:bg-muted/20 hover:text-foreground sm:px-6',
                )}
              >
                <span className="flex items-center gap-2">
                  <ChevronDown
                    className={cn('h-4 w-4 transition-transform', !showUnmatched && '-rotate-90')}
                  />
                  {showUnmatched
                    ? `Hide ${unmatched.length} more service${unmatched.length !== 1 ? 's' : ''}`
                    : `Show ${unmatched.length} more service${unmatched.length !== 1 ? 's' : ''}`}
                </span>
                {selectedIds.size > 0 && (
                  <Badge variant="outline" className="border-primary/30 bg-primary/10 text-primary text-[10px]">
                    {selectedIds.size} selected
                  </Badge>
                )}
              </button>

              {showUnmatched && (
                <div className="px-4 pb-4 pt-1 sm:px-6">
                  {unmatched.length === 0 ? (
                    <p className="py-4 text-center text-sm text-muted-foreground">
                      {search || activeType ? 'No services match your filter.' : 'All known services are already being tracked.'}
                    </p>
                  ) : (
                    <div className="space-y-1.5">
                      {unmatched.map(entry => (
                        <UnmatchedCard
                          key={entry.id}
                          entry={entry}
                          selected={selectedIds.has(entry.id)}
                          onToggleSelect={toggleSelect}
                          onTrack={handleTrack}
                          trackingBusy={trackBusyId === entry.id}
                        />
                      ))}
                    </div>
                  )}
                </div>
              )}
            </div>

          </div>
        )}
      </CardContent>

      {/* ── Re-link dialog ─────────────────────────────────────────────── */}
      <ReLinkDialog
        open={!!relinkEntry}
        relinkEntry={relinkEntry}
        allEntries={catalog}
        onClose={() => setRelinkEntry(null)}
        onConfirm={handleRelink}
        busy={relinkBusy}
      />

      {/* ── Bulk action bar ────────────────────────────────────────────── */}
      {selectedIds.size > 0 && (
        <div className="sticky bottom-0 flex items-center justify-between gap-3 border-t border-primary/20 bg-card/95 px-4 py-3 backdrop-blur-md sm:px-6">
          <div className="flex items-center gap-2">
            <Badge variant="outline" className="border-primary/30 bg-primary/10 font-mono text-primary">
              {selectedIds.size}
            </Badge>
            <span className="text-sm font-medium">
              {selectedIds.size === 1 ? 'service' : 'services'} selected
            </span>
          </div>
          <div className="flex gap-2">
            <Button
              type="button"
              variant="ghost"
              size="sm"
              className="text-xs"
              onClick={() => setSelectedIds(new Set())}
              disabled={bulkBusy}
            >
              Clear
            </Button>
            <Button
              type="button"
              size="sm"
              className="text-xs"
              disabled={bulkBusy}
              onClick={handleBulkTrack}
            >
              {bulkBusy
                ? <><Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />Adding…</>
                : `Track ${selectedIds.size} selected`}
            </Button>
          </div>
        </div>
      )}
    </Card>
  );
}
