"use client";

import { useState, useEffect, useCallback } from "react";
import {
  Activity, AlertTriangle, MousePointer, XCircle, LogOut,
  ChevronDown, ChevronRight, Zap, Gauge, Clock, ExternalLink,
  Eye, Phone, ClipboardList, CalendarCheck, Footprints,
  Flame, FormInput, ArrowUp, AlertCircle,
} from "lucide-react";
import { CardShell, KpiRowSkeleton, TableSkeleton } from "./_shared";

interface CwvData { lcp: number; cls: number; inp: number; ttfb: number; samples: number }
interface CwvPage { url: string; lcp: number; cls: number; inp: number; samples: number }
interface UxRow { page: string; target: string; count: number }
interface JsError { message: string; page: string; count: number; firstSeen: string; lastSeen: string }
interface ExitIntent { page: string; count: number; avgTime: number; avgScroll: number }
interface OutboundRow { page: string; target: string; count: number }

interface PageEngagement {
  totalPageViews: number;
  totalSessions: number;
  avgPagesPerSession: number;
  topPages: Array<{ url: string; views: number }>;
  topEntryPages: Array<{ url: string; sessions: number }>;
}
interface FormsData { starts: number; submits: number; completionRate: number }
interface PhoneData { totalClicks: number; smsClicks: number }
interface BookingData { widgetOpened: number; step: number; submit: number; confirmed: number }
interface UxTotals { totalEvents: number; totalSessions: number; rumSamples: number; signalEvents: number }
interface FrustrationData {
  rageClicks: number;
  deadClicks: number;
  formAbandoned: number;
  scrollBounces: number;
  errorsShown: number;
  topRageElements: Array<{ label: string; page: string; count: number }>;
}

interface UxData {
  cwv: CwvData;
  cwvByPage: CwvPage[];
  rageClicks: UxRow[];
  deadClicks: UxRow[];
  jsErrors: JsError[];
  exitIntents: ExitIntent[];
  outboundClicks: OutboundRow[];
  // Optional so older cached payloads (without these fields)
  // don't crash the renderer.
  pageEngagement?: PageEngagement;
  forms?: FormsData;
  phone?: PhoneData;
  booking?: BookingData;
  frustration?: FrustrationData;
  totals?: UxTotals;
}

export interface UxTabProps { brandId: string; range: string }

type CwvMetric = "lcp" | "cls" | "inp" | "ttfb";
type CwvRating = "good" | "warn" | "bad";

function cwvRating(metric: CwvMetric, value: number): CwvRating {
  const thresholds: Record<CwvMetric, [number, number]> = {
    lcp:  [2500, 4000],
    cls:  [0.1, 0.25],
    inp:  [200, 500],
    ttfb: [800, 1800],
  };
  const [good, poor] = thresholds[metric];
  if (value <= good) return "good";
  if (value < poor) return "warn";
  return "bad";
}

const ratingStyles: Record<CwvRating, { text: string; bg: string; border: string; label: string; ring: string }> = {
  good: { text: "text-emerald-700", bg: "bg-emerald-50", border: "border-emerald-200", label: "Good", ring: "ring-emerald-100" },
  warn: { text: "text-amber-700", bg: "bg-amber-50", border: "border-amber-200", label: "Needs Improvement", ring: "ring-amber-100" },
  bad:  { text: "text-red-700", bg: "bg-red-50", border: "border-red-200", label: "Poor", ring: "ring-red-100" },
};

function formatCwv(metric: CwvMetric, value: number): string {
  if (metric === "cls") return value.toFixed(3);
  if (metric === "lcp") return `${(value / 1000).toFixed(2)}s`;
  return `${Math.round(value)}ms`;
}

const cwvLabels: Record<CwvMetric, { name: string; full: string }> = {
  lcp: { name: "LCP", full: "Largest Contentful Paint" },
  cls: { name: "CLS", full: "Cumulative Layout Shift" },
  inp: { name: "INP", full: "Interaction to Next Paint" },
  ttfb: { name: "TTFB", full: "Time to First Byte" },
};

type SignalTab = "rage" | "dead" | "errors" | "exit" | "outbound";

export function UxTab({ brandId, range }: UxTabProps) {
  const [data, setData] = useState<UxData | null>(null);
  const [loading, setLoading] = useState(true);
  const [cwvExpanded, setCwvExpanded] = useState(false);
  const [signalTab, setSignalTab] = useState<SignalTab>("rage");

  const load = useCallback(async () => {
    setLoading(true);
    const res = await fetch(`/api/site-tag/analytics/ux?brandId=${brandId}&range=${range}`);
    if (res.ok) setData(await res.json());
    setLoading(false);
  }, [brandId, range]);

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

  if (loading) {
    return (
      <div className="space-y-6">
        <KpiRowSkeleton />
        <TableSkeleton rows={5} cols={4} />
      </div>
    );
  }

  // Only show the empty state when we have genuinely ZERO events
  // for this brand. Previously we gated on CWV / rage-click /
  // dead-click / js-error / outbound-click (all heatmap-module
  // signals that ship separately), which made the tab go blank on
  // fully-instrumented brands until the heatmap rolled out.
  const totalEvents = data?.totals?.totalEvents ?? 0;
  const hasAnyRum = (data?.cwv.samples ?? 0) > 0;
  const hasAnySignals =
    (data?.rageClicks.length ?? 0) > 0 ||
    (data?.deadClicks.length ?? 0) > 0 ||
    (data?.jsErrors.length ?? 0) > 0 ||
    (data?.exitIntents.length ?? 0) > 0 ||
    (data?.outboundClicks?.length ?? 0) > 0;
  const hasData = !!data && (totalEvents > 0 || hasAnyRum || hasAnySignals);
  if (!hasData) {
    return (
      <div className="bg-white rounded-xl border border-slate-200 p-12 text-center">
        <Activity className="w-10 h-10 text-slate-200 mx-auto mb-3" />
        <h2 className="text-lg font-bold text-slate-900 mb-1">No UX Data Yet</h2>
        <p className="text-sm text-slate-500 max-w-sm mx-auto">
          This data will appear once the Site Tag is installed and sending events from your site.
        </p>
      </div>
    );
  }

  // Pick the default tab to the one with the most data
  const outboundRows = data!.outboundClicks ?? [];
  const signalCounts = {
    rage: data!.rageClicks.length,
    dead: data!.deadClicks.length,
    errors: data!.jsErrors.length,
    exit: data!.exitIntents.length,
    outbound: outboundRows.length,
  };

  const SIGNAL_TABS: Array<{ key: SignalTab; label: string; icon: typeof MousePointer; count: number }> = [
    { key: "rage",     label: "Rage Clicks",    icon: MousePointer,  count: signalCounts.rage },
    { key: "dead",     label: "Dead Clicks",    icon: XCircle,       count: signalCounts.dead },
    { key: "errors",   label: "JS Errors",      icon: AlertTriangle, count: signalCounts.errors },
    { key: "exit",     label: "Exit Intent",    icon: LogOut,        count: signalCounts.exit },
    { key: "outbound", label: "Outbound",       icon: ExternalLink,  count: signalCounts.outbound },
  ];

  const frustration = data!.frustration;
  const frustrationTotal = frustration
    ? frustration.rageClicks + frustration.deadClicks + frustration.formAbandoned + frustration.scrollBounces + frustration.errorsShown
    : 0;
  const engagement = data!.pageEngagement;
  const forms = data!.forms;
  const phone = data!.phone;
  const booking = data!.booking;
  const bookingHasAnything = !!booking && (booking.widgetOpened + booking.step + booking.submit + booking.confirmed) > 0;

  return (
    <div className="space-y-6">
      {/* ── Page Engagement ────────────────────────────────── */}
      {engagement && engagement.totalPageViews > 0 && (
        <div className="space-y-3">
          <h2 className="text-base font-bold text-slate-900 flex items-center gap-2">
            <Footprints className="w-4 h-4 text-slate-500" />
            Page Engagement
          </h2>
          <div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
            <StatCard icon={Eye} label="Page Views" value={engagement.totalPageViews.toLocaleString()} accent="text-blue-600" bg="bg-blue-50" />
            <StatCard icon={Footprints} label="Sessions" value={engagement.totalSessions.toLocaleString()} accent="text-indigo-600" bg="bg-indigo-50" />
            <StatCard icon={Activity} label="Pages / Session" value={engagement.avgPagesPerSession.toFixed(1)} accent="text-violet-600" bg="bg-violet-50" />
            <StatCard icon={ExternalLink} label="Outbound (signals)" value={(data!.outboundClicks?.reduce((s, o) => s + o.count, 0) ?? 0).toLocaleString()} accent="text-amber-600" bg="bg-amber-50" />
          </div>
          <div className="grid grid-cols-1 lg:grid-cols-2 gap-3">
            <TopPagesCard title="Most visited pages" rows={engagement.topPages.map((p) => ({ url: p.url, count: p.views }))} countLabel="views" />
            <TopPagesCard title="Top entry pages" rows={engagement.topEntryPages.map((p) => ({ url: p.url, count: p.sessions }))} countLabel="sessions" />
          </div>
        </div>
      )}

      {/* ── Forms UX ────────────────────────────────────────── */}
      {forms && (forms.starts > 0 || forms.submits > 0) && (
        <div className="space-y-3">
          <h2 className="text-base font-bold text-slate-900 flex items-center gap-2">
            <ClipboardList className="w-4 h-4 text-slate-500" />
            Form UX
          </h2>
          <div className="grid grid-cols-2 lg:grid-cols-3 gap-3">
            <StatCard icon={ClipboardList} label="Form Starts" value={forms.starts.toLocaleString()} accent="text-slate-700" bg="bg-slate-100" />
            <StatCard icon={ClipboardList} label="Form Submits" value={forms.submits.toLocaleString()} accent="text-emerald-700" bg="bg-emerald-50" />
            <StatCard
              icon={Gauge}
              label="Completion Rate"
              value={`${forms.completionRate.toFixed(1)}%`}
              accent={forms.completionRate >= 40 ? "text-emerald-700" : forms.completionRate >= 15 ? "text-amber-700" : "text-red-700"}
              bg={forms.completionRate >= 40 ? "bg-emerald-50" : forms.completionRate >= 15 ? "bg-amber-50" : "bg-red-50"}
            />
          </div>
          {forms.starts > forms.submits && forms.starts > 5 && (
            <p className="text-[11px] text-slate-500 px-1">
              {(forms.starts - forms.submits).toLocaleString()} visitors started a form but didn&apos;t submit — that&apos;s {((1 - forms.submits / forms.starts) * 100).toFixed(0)}% abandonment.
            </p>
          )}
        </div>
      )}

      {/* ── Phone / SMS ─────────────────────────────────────── */}
      {phone && (phone.totalClicks > 0 || phone.smsClicks > 0) && (
        <div className="space-y-3">
          <h2 className="text-base font-bold text-slate-900 flex items-center gap-2">
            <Phone className="w-4 h-4 text-slate-500" />
            Call &amp; Text
          </h2>
          <div className="grid grid-cols-2 gap-3">
            <StatCard icon={Phone} label="Phone Clicks (click-to-call)" value={phone.totalClicks.toLocaleString()} accent="text-emerald-700" bg="bg-emerald-50" />
            <StatCard icon={Phone} label="SMS Clicks" value={phone.smsClicks.toLocaleString()} accent="text-sky-700" bg="bg-sky-50" />
          </div>
        </div>
      )}

      {/* ── Booking funnel ──────────────────────────────────── */}
      {booking && bookingHasAnything && (
        <div className="space-y-3">
          <h2 className="text-base font-bold text-slate-900 flex items-center gap-2">
            <CalendarCheck className="w-4 h-4 text-slate-500" />
            Booking Funnel
          </h2>
          <div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
            <StatCard icon={CalendarCheck} label="Widget Opened" value={booking.widgetOpened.toLocaleString()} accent="text-slate-700" bg="bg-slate-100" />
            <StatCard icon={CalendarCheck} label="Step Reached" value={booking.step.toLocaleString()} accent="text-indigo-700" bg="bg-indigo-50" />
            <StatCard icon={CalendarCheck} label="Submitted" value={booking.submit.toLocaleString()} accent="text-amber-700" bg="bg-amber-50" />
            <StatCard icon={CalendarCheck} label="Confirmed" value={booking.confirmed.toLocaleString()} accent="text-emerald-700" bg="bg-emerald-50" />
          </div>
        </div>
      )}

      {/* ── UX Frustration Signals ──────────────────────────────
          Counts for rage / dead / form-abandoned / scroll-bounce /
          error-shown events captured by the new t.js monitors.
          Always rendered (even when all zero) so the operator can
          confirm the signals are live; each card red when >0,
          slate when 0. */}
      {frustration && (
        <div className="space-y-3">
          <h2 className="text-base font-bold text-slate-900 flex items-center gap-2">
            <Flame className="w-4 h-4 text-slate-500" />
            UX Frustration Signals
          </h2>
          <p className="text-[11px] text-slate-500 -mt-1 max-w-2xl">
            These signals indicate UX friction points that may be reducing conversions — rage clicks on unresponsive buttons, dead clicks on misleadingly-styled non-interactive elements, abandoned forms, low-engagement bounces, and visible error messages.
          </p>
          <div className="grid grid-cols-2 lg:grid-cols-5 gap-3">
            <FrustrationCard icon={Flame}         label="Rage Clicks"       value={frustration.rageClicks} />
            <FrustrationCard icon={MousePointer}  label="Dead Clicks"       value={frustration.deadClicks} />
            <FrustrationCard icon={FormInput}     label="Form Abandonments" value={frustration.formAbandoned} />
            <FrustrationCard icon={ArrowUp}       label="Scroll Bounces"    value={frustration.scrollBounces} />
            <FrustrationCard icon={AlertCircle}   label="Errors Shown"      value={frustration.errorsShown} />
          </div>
          {frustration.topRageElements.length > 0 && (
            <div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
              <div className="px-5 py-3 border-b border-slate-100">
                <p className="text-[11px] font-bold uppercase tracking-widest text-slate-500">Top rage-clicked elements</p>
              </div>
              <div className="divide-y divide-slate-100">
                {(() => {
                  const max = Math.max(...frustration.topRageElements.map((r) => r.count), 1);
                  return frustration.topRageElements.map((r, i) => {
                    const width = (r.count / max) * 100;
                    return (
                      <div key={`${r.label}::${r.page}::${i}`} className="px-5 py-2.5">
                        <div className="flex items-center justify-between mb-1">
                          <span className="text-xs font-semibold text-slate-800 truncate max-w-[45%]" title={r.label}>{r.label}</span>
                          <span className="font-mono text-[10px] text-brand-600 truncate max-w-[40%]" title={r.page}>{r.page}</span>
                          <span className="text-sm font-bold text-red-700 tabular-nums ml-3">{r.count}</span>
                        </div>
                        <div className="w-full bg-slate-100 rounded-full h-1.5 overflow-hidden">
                          <div className="h-full rounded-full bg-red-500" style={{ width: `${Math.max(width, 3)}%` }} />
                        </div>
                      </div>
                    );
                  });
                })()}
              </div>
            </div>
          )}
          {frustrationTotal === 0 && (
            <div className="bg-emerald-50/60 border border-emerald-200 rounded-xl px-5 py-3 text-[11px] text-emerald-800">
              No UX frustration signals detected in the selected window — visitors aren&apos;t rage-clicking, dead-clicking, abandoning forms, bouncing, or encountering visible errors.
            </div>
          )}
        </div>
      )}

      {/* Core Web Vitals — large, prominent */}
      {data!.cwv.samples > 0 && (
        <div className="space-y-3">
          <div className="flex items-end justify-between">
            <div>
              <h2 className="text-base font-bold text-slate-900 flex items-center gap-2">
                <Gauge className="w-4 h-4 text-slate-500" />
                Core Web Vitals
              </h2>
              <p className="text-xs text-slate-500 mt-0.5">
                {data!.cwv.samples.toLocaleString()} real user samples
              </p>
            </div>
          </div>

          <div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
            {(["lcp", "cls", "inp", "ttfb"] as const).map((metric) => {
              const val = data!.cwv[metric];
              const rating = cwvRating(metric, val);
              const style = ratingStyles[rating];
              return (
                <div
                  key={metric}
                  className={`rounded-xl border ${style.border} ${style.bg} px-5 py-5 flex flex-col justify-between min-h-[140px] ring-4 ${style.ring} ring-opacity-50`}
                >
                  <div className="flex items-center justify-between">
                    <div>
                      <p className="text-xs font-bold text-slate-600 uppercase tracking-wide">{cwvLabels[metric].name}</p>
                      <p className="text-[10px] text-slate-500 mt-0.5">{cwvLabels[metric].full}</p>
                    </div>
                    <Gauge className={`w-4 h-4 ${style.text}`} />
                  </div>
                  <div className="mt-3">
                    <p className={`text-[34px] font-bold leading-none tabular-nums ${style.text}`}>
                      {formatCwv(metric, val)}
                    </p>
                    <span className={`inline-block mt-2 text-[10px] font-bold uppercase tracking-wider ${style.text}`}>
                      {style.label}
                    </span>
                  </div>
                </div>
              );
            })}
          </div>

          {/* Collapsible per-page CWV table */}
          {data!.cwvByPage.length > 0 && (
            <CardShell
              title="CWV by Page"
              icon={Gauge}
              right={
                <button
                  onClick={() => setCwvExpanded(!cwvExpanded)}
                  className="flex items-center gap-1 text-[10px] font-semibold text-slate-500 hover:text-slate-700"
                >
                  {cwvExpanded ? <ChevronDown className="w-3 h-3" /> : <ChevronRight className="w-3 h-3" />}
                  {cwvExpanded ? "Hide" : `Show ${data!.cwvByPage.length} pages`}
                </button>
              }
            >
              {cwvExpanded && (
                <div className="overflow-x-auto">
                  <table className="w-full text-sm">
                    <thead>
                      <tr className="text-left text-[11px] font-semibold uppercase tracking-wider text-slate-400 border-b border-slate-100 bg-slate-50">
                        <th className="px-5 py-2.5">Page</th>
                        <th className="px-5 py-2.5 text-right">LCP</th>
                        <th className="px-5 py-2.5 text-right">CLS</th>
                        <th className="px-5 py-2.5 text-right">INP</th>
                        <th className="px-5 py-2.5 text-right">Samples</th>
                      </tr>
                    </thead>
                    <tbody className="divide-y divide-slate-100">
                      {data!.cwvByPage.map((p) => {
                        const lcpR = cwvRating("lcp", p.lcp);
                        const clsR = cwvRating("cls", p.cls);
                        const inpR = cwvRating("inp", p.inp);
                        return (
                          <tr key={p.url} className="hover:bg-slate-50 transition-colors">
                            <td className="px-5 py-2.5 font-mono text-xs text-brand-600 truncate max-w-[280px]" title={p.url}>{p.url}</td>
                            <td className={`px-5 py-2.5 text-right text-xs tabular-nums font-semibold ${ratingStyles[lcpR].text}`}>{formatCwv("lcp", p.lcp)}</td>
                            <td className={`px-5 py-2.5 text-right text-xs tabular-nums font-semibold ${ratingStyles[clsR].text}`}>{p.cls.toFixed(3)}</td>
                            <td className={`px-5 py-2.5 text-right text-xs tabular-nums font-semibold ${ratingStyles[inpR].text}`}>{Math.round(p.inp)}ms</td>
                            <td className="px-5 py-2.5 text-right text-xs text-slate-400 tabular-nums">{p.samples}</td>
                          </tr>
                        );
                      })}
                    </tbody>
                  </table>
                </div>
              )}
            </CardShell>
          )}
        </div>
      )}

      {/* UX Signals — tabbed interface. Rendered even when all categories
          are empty so users see the tab bar and can tell what's being
          tracked. Each empty category shows a "Tracking not yet configured"
          hint so missing data is explained, not silent. */}
      <div className="space-y-3">
        <h2 className="text-base font-bold text-slate-900 flex items-center gap-2">
          <Zap className="w-4 h-4 text-slate-500" />
          UX Signals
        </h2>

          {/* Tab bar */}
          <div className="flex items-center gap-1 bg-slate-100 rounded-xl p-1 w-fit overflow-x-auto">
            {SIGNAL_TABS.map(({ key, label, icon: Icon, count }) => (
              <button
                key={key}
                onClick={() => setSignalTab(key)}
                className={`flex items-center gap-1.5 px-3 py-2 rounded-lg text-xs font-semibold whitespace-nowrap transition-colors ${
                  signalTab === key
                    ? "bg-white text-slate-900 shadow-sm"
                    : "text-slate-500 hover:text-slate-700"
                }`}
              >
                <Icon className="w-3.5 h-3.5" />
                {label}
                <span className={`inline-flex items-center justify-center min-w-[20px] h-5 px-1.5 rounded-full text-[10px] font-bold ${
                  signalTab === key
                    ? (count > 0 ? "bg-red-50 text-red-600" : "bg-slate-100 text-slate-400")
                    : "bg-white text-slate-500 border border-slate-200"
                }`}>
                  {count}
                </span>
              </button>
            ))}
          </div>

          {/* Tab content */}
          {signalTab === "rage" && (
            <SignalTable
              rows={data!.rageClicks}
              empty="Rage clicks (3+ rapid clicks on the same element) haven't been detected yet. This is a good sign — visitors aren't encountering broken or frustrating UI."
              renderRow={(r) => ({
                page: r.page,
                main: r.target,
                count: r.count,
              })}
              color="bg-red-500"
              icon={MousePointer}
            />
          )}

          {signalTab === "dead" && (
            <SignalTable
              rows={data!.deadClicks}
              empty="Dead clicks (clicks on elements that don't respond) haven't been detected yet. Every click on your site appears to do something useful."
              renderRow={(r) => ({
                page: r.page,
                main: r.target,
                count: r.count,
              })}
              color="bg-amber-500"
              icon={XCircle}
            />
          )}

          {signalTab === "errors" && (
            <JsErrorsTable errors={data!.jsErrors} />
          )}

          {signalTab === "exit" && (
            <ExitIntentTable exits={data!.exitIntents} />
          )}

          {signalTab === "outbound" && (
            <OutboundTable rows={outboundRows} />
          )}
      </div>

    </div>
  );
}

// ─── Small stat + top-pages helpers ──────────────────────────────────────────

function StatCard({
  icon: Icon, label, value, accent, bg,
}: {
  icon: typeof MousePointer;
  label: string;
  value: string;
  accent: string;
  bg: string;
}) {
  return (
    <div className="bg-white rounded-xl border border-slate-200 px-4 py-4">
      <div className="flex items-center gap-2 mb-2">
        <span className={`w-7 h-7 rounded-lg ${bg} ${accent} flex items-center justify-center`}>
          <Icon className="w-3.5 h-3.5" />
        </span>
        <p className="text-[10px] font-bold uppercase tracking-widest text-slate-500">{label}</p>
      </div>
      <p className={`text-2xl font-bold tabular-nums leading-none ${accent}`}>{value}</p>
    </div>
  );
}

// Red-when-nonzero variant for the frustration section. Any count
// above zero renders the card in red to draw the eye; zero counts
// slip back to slate so a healthy site's UX panel reads calm.
function FrustrationCard({
  icon: Icon, label, value,
}: {
  icon: typeof MousePointer;
  label: string;
  value: number;
}) {
  const hot = value > 0;
  const accent = hot ? "text-red-700" : "text-slate-400";
  const bg = hot ? "bg-red-50" : "bg-slate-100";
  return (
    <div className={`rounded-xl border px-4 py-4 ${hot ? "bg-white border-red-200" : "bg-white border-slate-200"}`}>
      <div className="flex items-center gap-2 mb-2">
        <span className={`w-7 h-7 rounded-lg ${bg} ${accent} flex items-center justify-center`}>
          <Icon className="w-3.5 h-3.5" />
        </span>
        <p className="text-[10px] font-bold uppercase tracking-widest text-slate-500">{label}</p>
      </div>
      <p className={`text-2xl font-bold tabular-nums leading-none ${accent}`}>{value.toLocaleString()}</p>
    </div>
  );
}

function TopPagesCard({
  title, rows, countLabel,
}: {
  title: string;
  rows: Array<{ url: string; count: number }>;
  countLabel: string;
}) {
  if (rows.length === 0) {
    return (
      <div className="bg-white rounded-xl border border-dashed border-slate-200 p-6 text-center">
        <p className="text-xs font-semibold text-slate-600">{title}</p>
        <p className="text-[11px] text-slate-400 mt-1">No {countLabel} in the selected range yet.</p>
      </div>
    );
  }
  const max = Math.max(...rows.map((r) => r.count), 1);
  return (
    <div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
      <div className="px-5 py-3 border-b border-slate-100">
        <p className="text-[11px] font-bold uppercase tracking-widest text-slate-500">{title}</p>
      </div>
      <div className="divide-y divide-slate-100">
        {rows.map((r, i) => {
          const width = (r.count / max) * 100;
          return (
            <div key={`${r.url}::${i}`} className="px-5 py-2.5 hover:bg-slate-50 transition-colors">
              <div className="flex items-center justify-between mb-1">
                <span className="font-mono text-xs text-brand-600 truncate max-w-[75%]" title={r.url}>{r.url}</span>
                <span className="text-sm font-bold text-slate-900 tabular-nums ml-3">{r.count.toLocaleString()}</span>
              </div>
              <div className="w-full bg-slate-100 rounded-full h-1.5 overflow-hidden">
                <div className="h-full rounded-full bg-brand-500" style={{ width: `${Math.max(width, 2)}%` }} />
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ─── Signal tables ──────────────────────────────────────────────────────────

function SignalTable<T>({ rows, renderRow, empty, color, icon: Icon }: {
  rows: T[];
  renderRow: (r: T) => { page: string; main: string; count: number };
  empty: string;
  color: string;
  icon: typeof MousePointer;
}) {
  if (rows.length === 0) {
    return (
      <div className="bg-white rounded-xl border border-dashed border-slate-200 p-10 text-center">
        <Icon className="w-8 h-8 text-slate-300 mx-auto mb-2" />
        <p className="text-sm font-semibold text-slate-600">No events detected</p>
        <p className="text-xs text-slate-400 mt-1 max-w-sm mx-auto">{empty}</p>
      </div>
    );
  }
  const max = Math.max(...rows.map((r) => renderRow(r).count), 1);
  return (
    <div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
      <div className="divide-y divide-slate-100">
        {rows.map((raw, i) => {
          const r = renderRow(raw);
          const width = (r.count / max) * 100;
          return (
            <div key={i} className="px-5 py-3 hover:bg-slate-50 transition-colors">
              <div className="flex items-center justify-between mb-1.5">
                <span className="font-mono text-xs text-brand-600 truncate max-w-[45%]" title={r.page}>{r.page}</span>
                <span className="font-mono text-xs text-slate-700 truncate max-w-[45%]" title={r.main}>{r.main}</span>
                <span className="text-sm font-bold text-slate-900 tabular-nums ml-3">{r.count}</span>
              </div>
              <div className="w-full bg-slate-100 rounded-full h-1.5 overflow-hidden">
                <div className={`h-full rounded-full ${color}`} style={{ width: `${Math.max(width, 2)}%` }} />
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

function JsErrorsTable({ errors }: { errors: JsError[] }) {
  const [expanded, setExpanded] = useState<number | null>(null);

  if (errors.length === 0) {
    return (
      <div className="bg-white rounded-xl border border-dashed border-slate-200 p-10 text-center">
        <AlertTriangle className="w-8 h-8 text-slate-300 mx-auto mb-2" />
        <p className="text-sm font-semibold text-slate-600">No JavaScript errors detected</p>
        <p className="text-xs text-slate-400 mt-1 max-w-sm mx-auto">
          The Site Tag is listening for uncaught errors and promise rejections on every pageview. Errors will appear here grouped by message.
        </p>
      </div>
    );
  }
  return (
    <div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
      <div className="divide-y divide-slate-100">
        {errors.map((e, i) => {
          const isOpen = expanded === i;
          return (
            <div key={i}>
              <button
                onClick={() => setExpanded(isOpen ? null : i)}
                className="w-full px-5 py-3 flex items-center gap-3 hover:bg-slate-50 text-left transition-colors"
              >
                {isOpen ? <ChevronDown className="w-3 h-3 text-slate-400 shrink-0" /> : <ChevronRight className="w-3 h-3 text-slate-400 shrink-0" />}
                <AlertTriangle className="w-3.5 h-3.5 text-red-500 shrink-0" />
                <span className="text-xs text-red-700 flex-1 truncate" title={e.message}>{e.message}</span>
                <span className="inline-flex items-center justify-center min-w-[32px] h-5 px-2 rounded-full bg-red-50 text-red-700 border border-red-200 text-[10px] font-bold tabular-nums shrink-0">
                  {e.count}×
                </span>
              </button>
              {isOpen && (
                <div className="px-10 py-3 bg-slate-50 text-xs text-slate-600 space-y-1">
                  <div><span className="text-slate-400">Page:</span> <span className="font-mono text-brand-600">{e.page}</span></div>
                  <div><span className="text-slate-400">First seen:</span> {new Date(e.firstSeen).toLocaleString()}</div>
                  <div><span className="text-slate-400">Last seen:</span> {new Date(e.lastSeen).toLocaleString()}</div>
                </div>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
}

function OutboundTable({ rows }: { rows: OutboundRow[] }) {
  if (rows.length === 0) {
    return (
      <div className="bg-white rounded-xl border border-dashed border-slate-200 p-10 text-center">
        <ExternalLink className="w-8 h-8 text-slate-300 mx-auto mb-2" />
        <p className="text-sm font-semibold text-slate-600">No outbound clicks detected</p>
        <p className="text-xs text-slate-400 mt-1 max-w-sm mx-auto">
          The Site Tag fires an <code className="font-mono text-[10px] px-1 py-0.5 bg-slate-50 border border-slate-200 rounded">outbound_click</code> event whenever a visitor clicks a link that leads off your domain — to Google Maps, social profiles, partner sites, or external PDFs. No outbound clicks have been captured yet for the selected range.
        </p>
      </div>
    );
  }
  const max = Math.max(...rows.map((r) => r.count), 1);
  return (
    <div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
      <table className="w-full text-sm">
        <thead>
          <tr className="text-left text-[11px] font-semibold uppercase tracking-wider text-slate-400 border-b border-slate-100 bg-slate-50">
            <th className="px-5 py-2.5">Page</th>
            <th className="px-5 py-2.5">Target Domain</th>
            <th className="px-5 py-2.5 text-right">Clicks</th>
          </tr>
        </thead>
        <tbody className="divide-y divide-slate-100">
          {rows.map((r, i) => {
            const width = (r.count / max) * 100;
            return (
              <tr key={`${r.page}::${r.target}::${i}`} className="hover:bg-slate-50 transition-colors">
                <td className="px-5 py-2.5 font-mono text-xs text-brand-600 truncate max-w-[320px]" title={r.page}>{r.page}</td>
                <td className="px-5 py-2.5">
                  <span className="font-mono text-xs text-slate-700 truncate max-w-[220px] inline-block" title={r.target}>{r.target}</span>
                </td>
                <td className="px-5 py-2.5 text-right">
                  <div className="flex items-center gap-2 justify-end">
                    <div className="w-24 bg-slate-100 rounded-full h-1.5 overflow-hidden">
                      <div className="h-full rounded-full bg-amber-500" style={{ width: `${Math.max(width, 3)}%` }} />
                    </div>
                    <span className="text-sm font-bold text-slate-900 tabular-nums w-10">{r.count}</span>
                  </div>
                </td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}

function ExitIntentTable({ exits }: { exits: ExitIntent[] }) {
  if (exits.length === 0) {
    return (
      <div className="bg-white rounded-xl border border-dashed border-slate-200 p-10 text-center">
        <LogOut className="w-8 h-8 text-slate-300 mx-auto mb-2" />
        <p className="text-sm font-semibold text-slate-600">No exit intent events yet</p>
        <p className="text-xs text-slate-400 mt-1 max-w-sm mx-auto">
          Exit intent fires when a visitor moves their cursor toward the browser chrome or switches tabs after some engagement. The Site Tag is listening but no exits have been captured yet.
        </p>
      </div>
    );
  }
  return (
    <div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
      <table className="w-full text-sm">
        <thead>
          <tr className="text-left text-[11px] font-semibold uppercase tracking-wider text-slate-400 border-b border-slate-100 bg-slate-50">
            <th className="px-5 py-2.5">Page</th>
            <th className="px-5 py-2.5 text-right">Exits</th>
            <th className="px-5 py-2.5 text-right">Avg Time</th>
            <th className="px-5 py-2.5 text-right">Avg Scroll</th>
          </tr>
        </thead>
        <tbody className="divide-y divide-slate-100">
          {exits.map((e, i) => (
            <tr key={i} className="hover:bg-slate-50 transition-colors">
              <td className="px-5 py-2.5 font-mono text-xs text-brand-600 truncate max-w-[300px]" title={e.page}>{e.page}</td>
              <td className="px-5 py-2.5 text-right font-bold text-slate-900 tabular-nums">{e.count}</td>
              <td className="px-5 py-2.5 text-right text-slate-500 tabular-nums">
                <span className="inline-flex items-center gap-1"><Clock className="w-3 h-3" />{e.avgTime}s</span>
              </td>
              <td className="px-5 py-2.5 text-right text-slate-500 tabular-nums">{e.avgScroll}%</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}
