'use client';

/**
 * Empfänger-Tabelle für den Stats-Drilldown (Phase 2).
 *
 * Zeigt eine paginierte Liste aller Empfänger einer Campaign mit aggregiertem Status
 * (zugestellt / geöffnet / geklickt / konvertiert / gebounced / abgemeldet) plus
 * Zeitstempel der jeweiligen Erst-Events. Click auf Zeile öffnet den Timeline-Drawer.
 *
 * Datenquelle: GET /api/campaigns/[id]/recipients (paginiert, gefiltert, sortiert)
 *
 * Filter werden mit 300ms debounce gegen die API geschickt — bei großen Listen
 * verhindert das einen Request pro Tastenanschlag im Suchfeld.
 */

import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react';
import {
  AlertOctagon,
  AlertTriangle,
  BadgeEuro,
  Eye,
  Loader2,
  MailCheck,
  MailX,
  MousePointerClick,
  Search,
  ShieldCheck,
  UserX,
  Users,
  ChevronLeft,
  ChevronRight,
} from 'lucide-react';
import { cn } from '@/lib/utils';

type RecipientStatus =
  | 'sent'
  | 'delivered'
  | 'opened'
  | 'clicked'
  | 'converted'
  | 'bounced'
  | 'unsubscribed';

interface RecipientRow {
  id: string;
  email: string;
  firstName: string | null;
  lastName: string | null;
  variantId: string | null;
  variantLabel: string | null;
  deliveredAt: string | null;
  firstOpenAt: string | null;
  firstClickAt: string | null;
  bounceAt: string | null;
  unsubscribedAt: string | null;
  conversionCount: number;
  conversionValueTotal: number;
  openCount: number;
  clickCount: number;
  behaviorCount: number;
  isMppOnly: boolean;
  lastEventAt: string | null;
  status: RecipientStatus;
}

interface VariantOption {
  id: string;
  label: string;
}

interface RecipientsResponse {
  ok: boolean;
  rows: RecipientRow[];
  total: number;
  limit: number;
  offset: number;
  variants: VariantOption[];
}

export interface RecipientsTableProps {
  campaignId: string;
  onOpenRecipient: (id: string) => void;
  className?: string;
}

const STATUS_OPTIONS: Array<{ value: RecipientStatus | ''; label: string }> = [
  { value: '', label: 'Alle Status' },
  { value: 'converted', label: 'Konvertiert' },
  { value: 'clicked', label: 'Geklickt' },
  { value: 'opened', label: 'Geöffnet (verified)' },
  { value: 'delivered', label: 'Zugestellt' },
  { value: 'bounced', label: 'Bounced' },
  { value: 'unsubscribed', label: 'Abgemeldet' },
  { value: 'sent', label: 'Nur versendet' },
];

const PAGE_SIZE = 50;

function fmtName(r: RecipientRow): string {
  const fn = [r.firstName, r.lastName].filter(Boolean).join(' ').trim();
  return fn || r.email;
}

function fmtTime(iso: string | null): string {
  if (!iso) return '—';
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return '—';
  return d.toLocaleString('de-DE', {
    day: '2-digit',
    month: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
  });
}

function fmtEuro(value: number): string {
  return new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR', maximumFractionDigits: 0 }).format(value);
}

const STATUS_BADGE: Record<RecipientStatus, { label: string; cls: string; icon: ReactNode }> = {
  sent: {
    label: 'gesendet',
    cls: 'bg-zinc-100 text-zinc-600 dark:bg-zinc-800 dark:text-zinc-400',
    icon: <Users className="h-3 w-3" />,
  },
  delivered: {
    label: 'zugestellt',
    cls: 'bg-blue-100 text-blue-700 dark:bg-blue-950/40 dark:text-blue-300',
    icon: <MailCheck className="h-3 w-3" />,
  },
  opened: {
    label: 'geöffnet',
    cls: 'bg-indigo-100 text-indigo-700 dark:bg-indigo-950/40 dark:text-indigo-300',
    icon: <ShieldCheck className="h-3 w-3" />,
  },
  clicked: {
    label: 'geklickt',
    cls: 'bg-emerald-100 text-emerald-700 dark:bg-emerald-950/40 dark:text-emerald-300',
    icon: <MousePointerClick className="h-3 w-3" />,
  },
  converted: {
    label: 'konvertiert',
    cls: 'bg-amber-100 text-amber-700 dark:bg-amber-950/40 dark:text-amber-300',
    icon: <BadgeEuro className="h-3 w-3" />,
  },
  bounced: {
    label: 'bounced',
    cls: 'bg-red-100 text-red-700 dark:bg-red-950/40 dark:text-red-300',
    icon: <MailX className="h-3 w-3" />,
  },
  unsubscribed: {
    label: 'abgemeldet',
    cls: 'bg-zinc-200 text-zinc-700 dark:bg-zinc-700 dark:text-zinc-300',
    icon: <UserX className="h-3 w-3" />,
  },
};

export function RecipientsTable({ campaignId, onOpenRecipient, className }: RecipientsTableProps) {
  const [data, setData] = useState<RecipientsResponse | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  // Filter-State
  const [search, setSearch] = useState('');
  const [debouncedSearch, setDebouncedSearch] = useState('');
  const [statusFilter, setStatusFilter] = useState<RecipientStatus | ''>('');
  const [variantFilter, setVariantFilter] = useState<string>('');
  const [offset, setOffset] = useState(0);

  const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);

  // 300ms debounce für Search — vermeidet Request-Spam
  useEffect(() => {
    if (debounceTimer.current) clearTimeout(debounceTimer.current);
    debounceTimer.current = setTimeout(() => {
      setDebouncedSearch(search);
      setOffset(0);
    }, 300);
    return () => {
      if (debounceTimer.current) clearTimeout(debounceTimer.current);
    };
  }, [search]);

  const fetchRows = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const params = new URLSearchParams({
        limit: String(PAGE_SIZE),
        offset: String(offset),
      });
      if (debouncedSearch) params.set('search', debouncedSearch);
      if (statusFilter) params.set('status', statusFilter);
      if (variantFilter) params.set('variantId', variantFilter);
      const res = await fetch(`/api/campaigns/${campaignId}/recipients?${params}`);
      if (!res.ok) throw new Error(`Empfänger-Lookup fehlgeschlagen (${res.status})`);
      const json: RecipientsResponse = await res.json();
      setData(json);
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Empfänger-Lookup fehlgeschlagen');
    } finally {
      setLoading(false);
    }
  }, [campaignId, debouncedSearch, statusFilter, variantFilter, offset]);

  useEffect(() => {
    void fetchRows();
  }, [fetchRows]);

  // Reset offset wenn Filter wechselt
  useEffect(() => { setOffset(0); }, [statusFilter, variantFilter]);

  const totalPages = data ? Math.max(1, Math.ceil(data.total / PAGE_SIZE)) : 1;
  const currentPage = Math.floor(offset / PAGE_SIZE) + 1;

  const variantOptions = useMemo(() => data?.variants ?? [], [data]);

  return (
    <div className={cn('flex flex-col gap-3', className)}>
      {/* ─── Filter-Bar ─────────────────────────────────────────────── */}
      <div className="flex flex-wrap items-center gap-2">
        <div className="relative flex-1 min-w-[200px]">
          <Search className="absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-zinc-400" />
          <input
            type="search"
            value={search}
            onChange={(e) => setSearch(e.target.value)}
            placeholder="Email oder Name suchen…"
            className="w-full rounded-md border border-zinc-200 bg-white py-1.5 pl-8 pr-3 text-xs text-zinc-900 placeholder:text-zinc-400 focus:border-zinc-400 focus:outline-none dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-100"
          />
        </div>
        <select
          value={statusFilter}
          onChange={(e) => setStatusFilter(e.target.value as RecipientStatus | '')}
          className="rounded-md border border-zinc-200 bg-white px-2 py-1.5 text-xs text-zinc-700 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-300"
        >
          {STATUS_OPTIONS.map((o) => (
            <option key={o.value} value={o.value}>
              {o.label}
            </option>
          ))}
        </select>
        {variantOptions.length > 1 && (
          <select
            value={variantFilter}
            onChange={(e) => setVariantFilter(e.target.value)}
            className="rounded-md border border-zinc-200 bg-white px-2 py-1.5 text-xs text-zinc-700 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-300"
          >
            <option value="">Alle Varianten</option>
            {variantOptions.map((v) => (
              <option key={v.id} value={v.id}>
                Variant {v.label}
              </option>
            ))}
          </select>
        )}
        <div className="ml-auto text-[11px] text-zinc-500">
          {data ? `${data.total} Empfänger` : ''}
        </div>
      </div>

      {error && (
        <div className="flex items-start gap-2 rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-800 dark:border-red-900/50 dark:bg-red-950/30">
          <AlertTriangle className="h-4 w-4 mt-0.5" />
          <span>{error}</span>
        </div>
      )}

      {/* ─── Tabelle ───────────────────────────────────────────────── */}
      <div className="overflow-hidden rounded-lg border border-zinc-200 bg-white dark:border-zinc-700 dark:bg-zinc-900">
        <table className="w-full text-xs">
          <thead className="border-b border-zinc-200 bg-zinc-50 text-left text-[11px] uppercase tracking-wider text-zinc-500 dark:border-zinc-700 dark:bg-zinc-800/50">
            <tr>
              <th className="px-3 py-2 font-semibold">Empfänger</th>
              <th className="px-3 py-2 font-semibold">Variant</th>
              <th className="px-3 py-2 font-semibold">Status</th>
              <th className="px-3 py-2 font-semibold">Zugestellt</th>
              <th className="px-3 py-2 font-semibold">Öffnung</th>
              <th className="px-3 py-2 font-semibold">Klick</th>
              <th className="px-3 py-2 font-semibold">Verhalten</th>
              <th className="px-3 py-2 text-right font-semibold">Conversion</th>
            </tr>
          </thead>
          <tbody className="divide-y divide-zinc-100 dark:divide-zinc-800">
            {loading && !data && (
              <RowSkeleton />
            )}
            {data?.rows.length === 0 && (
              <tr>
                <td colSpan={8} className="px-3 py-12 text-center text-zinc-500">
                  Keine Empfänger gefunden — Filter zurücksetzen?
                </td>
              </tr>
            )}
            {data?.rows.map((r) => {
              const badge = STATUS_BADGE[r.status];
              const isHotLead = r.status === 'clicked' && r.behaviorCount >= 2;
              return (
                <tr
                  key={r.id}
                  onClick={() => onOpenRecipient(r.id)}
                  className="cursor-pointer transition hover:bg-zinc-50 dark:hover:bg-zinc-800/50"
                >
                  <td className="px-3 py-2">
                    <div className="font-medium text-zinc-900 dark:text-zinc-100">{fmtName(r)}</div>
                    <div className="text-[11px] text-zinc-500">{r.email}</div>
                  </td>
                  <td className="px-3 py-2 text-zinc-600 dark:text-zinc-400">
                    {r.variantLabel ? (
                      <span className="rounded bg-zinc-100 px-1.5 py-0.5 text-[10px] font-semibold text-zinc-700 dark:bg-zinc-800 dark:text-zinc-300">
                        {r.variantLabel}
                      </span>
                    ) : (
                      <span className="text-zinc-400">—</span>
                    )}
                  </td>
                  <td className="px-3 py-2">
                    <span className={cn('inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-semibold', badge.cls)}>
                      {badge.icon}
                      {badge.label}
                    </span>
                    {isHotLead && (
                      <span className="ml-1 inline-flex items-center gap-1 rounded-full bg-orange-100 px-2 py-0.5 text-[10px] font-semibold text-orange-700 dark:bg-orange-950/40 dark:text-orange-300">
                        🔥 Hot
                      </span>
                    )}
                    {r.isMppOnly && r.openCount > 0 && (
                      <span
                        title="Alle Öffnungen sind Apple-MPP-Proxy-Pings — kein verifizierter User-Open."
                        className="ml-1 inline-flex items-center gap-1 rounded-full bg-zinc-100 px-2 py-0.5 text-[10px] font-medium text-zinc-500 dark:bg-zinc-800 dark:text-zinc-400"
                      >
                        <Eye className="h-3 w-3" /> MPP
                      </span>
                    )}
                  </td>
                  <td className="px-3 py-2 text-zinc-600 dark:text-zinc-400">{fmtTime(r.deliveredAt)}</td>
                  <td className="px-3 py-2 text-zinc-600 dark:text-zinc-400">
                    {r.firstOpenAt ? (
                      <div>
                        <div>{fmtTime(r.firstOpenAt)}</div>
                        {r.openCount > 1 && (
                          <div className="text-[10px] text-zinc-400">{r.openCount}× insgesamt</div>
                        )}
                      </div>
                    ) : (
                      <span className="text-zinc-400">—</span>
                    )}
                  </td>
                  <td className="px-3 py-2 text-zinc-600 dark:text-zinc-400">
                    {r.firstClickAt ? (
                      <div>
                        <div>{fmtTime(r.firstClickAt)}</div>
                        {r.clickCount > 1 && (
                          <div className="text-[10px] text-zinc-400">{r.clickCount}× insgesamt</div>
                        )}
                      </div>
                    ) : (
                      <span className="text-zinc-400">—</span>
                    )}
                  </td>
                  <td className="px-3 py-2 text-zinc-600 dark:text-zinc-400">
                    {r.behaviorCount > 0 ? (
                      <span className="text-emerald-600 dark:text-emerald-400">{r.behaviorCount} Events</span>
                    ) : (
                      <span className="text-zinc-400">—</span>
                    )}
                  </td>
                  <td className="px-3 py-2 text-right">
                    {r.conversionCount > 0 ? (
                      <div className="font-semibold text-amber-700 dark:text-amber-300">
                        {r.conversionValueTotal > 0 ? fmtEuro(r.conversionValueTotal) : `${r.conversionCount}×`}
                      </div>
                    ) : r.status === 'bounced' ? (
                      <span className="inline-flex items-center gap-1 text-red-600 dark:text-red-400">
                        <AlertOctagon className="h-3 w-3" /> Bounce
                      </span>
                    ) : (
                      <span className="text-zinc-400">—</span>
                    )}
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>

      {/* ─── Pagination ─────────────────────────────────────────────── */}
      {data && data.total > PAGE_SIZE && (
        <div className="flex items-center justify-between text-xs text-zinc-500">
          <div>
            Seite {currentPage} von {totalPages}
            {loading && <Loader2 className="ml-2 inline h-3 w-3 animate-spin" />}
          </div>
          <div className="flex items-center gap-2">
            <button
              type="button"
              onClick={() => setOffset(Math.max(0, offset - PAGE_SIZE))}
              disabled={offset === 0 || loading}
              className="inline-flex items-center gap-1 rounded-md border border-zinc-200 bg-white px-2 py-1 transition hover:bg-zinc-50 disabled:opacity-40 dark:border-zinc-700 dark:bg-zinc-900 dark:hover:bg-zinc-800"
            >
              <ChevronLeft className="h-3 w-3" /> Zurück
            </button>
            <button
              type="button"
              onClick={() => setOffset(offset + PAGE_SIZE)}
              disabled={offset + PAGE_SIZE >= data.total || loading}
              className="inline-flex items-center gap-1 rounded-md border border-zinc-200 bg-white px-2 py-1 transition hover:bg-zinc-50 disabled:opacity-40 dark:border-zinc-700 dark:bg-zinc-900 dark:hover:bg-zinc-800"
            >
              Weiter <ChevronRight className="h-3 w-3" />
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

function RowSkeleton() {
  return (
    <>
      {Array.from({ length: 5 }).map((_, i) => (
        <tr key={i}>
          {Array.from({ length: 8 }).map((_, j) => (
            <td key={j} className="px-3 py-2.5">
              <div className="h-3 w-full max-w-[120px] animate-pulse rounded bg-zinc-100 dark:bg-zinc-800" />
            </td>
          ))}
        </tr>
      ))}
    </>
  );
}
